Skip to main content
GameDev.net gamedev.net
🔒 Locked 🎮 Unity

D3D 9 Strange "Ghost" artifact

Started by gameXcore Apr 25, 2011 at 4:26 PM 6 replies 2.4k views
Original Post
gameXcore
gameXcore
Hi All,

Since leaving uni and getting a real job I haven't been around on these board a lot, mainly due to the complete lack of programming I have done outside of the office, however recently I decided to start learning 3D programming from a technical standpoint using native Direct X (In the past I have always used wrappers, Ogre, XNA etc).

I have been following a few tutorials learning the syntax and how things fit together, and have come to the topic of lighting, I quickly hacked together my first lighted demo app and amnoticing a very strange occurance that I cannot explain and was hoping a fellow board member could enlighten me as to what is happening.

The program is a simple app that sets up a cube, renders it and allows the user to interact using the keyboard to translate, rotate and scale it. With the D3DRS_LIGHTING renderstate set to false the app works fine, you are able to move the cube around with no problems, (Code listing 2 below). The problem occurs when I refactor the code slightly to turn D3DRS_LIGHTING on and setup one light. The app initially works fine, the cube is correctly lit throught the user moving it, however precicely 6 seconds after the program starts a second cube "Appears" at the origin, this cube then procceeds to play back the motions of the original cube precicely 6 seconds after they happened, mirroring all movements, scaling changes and rotations.

Now barring that I may have accidently stubled upon AI which is currently playing tricks with me and may soon take over the world, I am failing to remove/add bits of code to track down what exactly is causing this strange occurance.

Thanks a lot for any help,
Scott

Code listings for D3D9 setup [1], the program with no lighting[2] and the program with lighting and strange behaviour[3] follow, aswell as my typedefs for a few of D3D's types:


#include "DeviceManager.h"
#include "ApplicationDisplay.h"

namespace XF
{
namespace GFX
{
DeviceManager::DeviceManager()
{
d3d = NULL;
d3dDevice = NULL;
}

bool DeviceManager::Init(HWND hWnd, ApplicationDisplay &appDisp)
{
d3d = Direct3DCreate9(D3D_SDK_VERSION);

if(!d3d)
return false;

ZeroMemory(&d3dPP, sizeof(d3dPP));

d3dPP.Windowed = !appDisp.Fullscreen();
d3dPP.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dPP.hDeviceWindow = hWnd;
d3dPP.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dPP.BackBufferWidth = appDisp.WindowWidth();
d3dPP.BackBufferHeight = appDisp.WindowHeight();
d3dPP.EnableAutoDepthStencil = TRUE;
d3dPP.AutoDepthStencilFormat = D3DFMT_D16;

if(FAILED(d3d->CreateDevice(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dPP,
&d3dDevice)))
{
return false;
}

d3dDevice->SetRenderState(D3DRS_ZENABLE, true);

return true;
}

void DeviceManager::Destroy()
{
d3dDevice->Release();
d3d->Release();
}

void DeviceManager::BeginFrame()
{
d3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3dDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

d3dDevice->BeginScene();
}

void DeviceManager::EndFrame()
{
d3dDevice->EndScene();
d3dDevice->Present(NULL, NULL, NULL, NULL);
}
}
}




#include "TestGameScreen.h"

#define CUSTOMFVF (D3DFVF_XYZ | D3DFVF_DIFFUSE)

struct CustomVertex
{
float x, y, z;
DWORD diffuse;
};

bool TestGameScreen::OnInit()
{
CustomVertex vertices[] =
{
{ -1.0f, 1.0f, -1.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 1.0f, 1.0f, -1.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ -1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB(0, 255, 255), },
{ -1.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 1.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ -1.0f, -1.0f, 1.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 1.0f, -1.0f, 1.0f, D3DCOLOR_XRGB(0, 255, 255), },
};

short indices[] =
{
0, 1, 2, // side 1
2, 1, 3,
4, 0, 6, // side 2
6, 0, 2,
7, 5, 6, // side 3
6, 5, 4,
3, 1, 7, // side 4
7, 1, 5,
4, 5, 0, // side 5
0, 5, 1,
3, 7, 2, // side 6
2, 7, 6,
};

app->device.GetDevice()->CreateVertexBuffer(
24 * sizeof(CustomVertex),
0,
CUSTOMFVF,
D3DPOOL_MANAGED,
&vBuffer,
NULL);

app->device.GetDevice()->CreateIndexBuffer(
36 * sizeof(short),
0,
D3DFMT_INDEX16,
D3DPOOL_MANAGED,
&iBuffer,
NULL);

void* voidPtr;
vBuffer->Lock(0, 0, (void**)&voidPtr, 0);
memcpy(voidPtr, vertices, sizeof(vertices));
vBuffer->Unlock();

iBuffer->Lock(0, 0, (void**)&voidPtr, 0);
memcpy(voidPtr, indices, sizeof(indices));
iBuffer->Unlock();

D3DXMatrixLookAtLH( &viewMatrix,
&XF::GFX::Vector3(0.0f, 0.0f, 10.0f),
&XF::GFX::Vector3Zero,
&XF::GFX::Vector3Up);

D3DXMatrixPerspectiveFovLH( &projMatrix,
D3DXToRadian(45),
(float)app->device.GetPresentationParameters().BackBufferWidth /
(float)app->device.GetPresentationParameters().BackBufferHeight,
1.0f,
100.0f);

position = XF::GFX::Vector3Zero;
rotation = XF::GFX::Vector3Zero;
scale = XF::GFX::Vector3One;

ZeroMemory(&light, sizeof(light));
light.Type = D3DLIGHT_DIRECTIONAL;
light.Diffuse = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f);
light.Direction = XF::GFX::Vector3(-1.0f, -0.3f, -1.0f);

app->device.GetDevice()->SetLight(0, &light);
app->device.GetDevice()->LightEnable(0, false);

ZeroMemory(&material, sizeof(XF::GFX::D3DMaterial));
material.Diffuse = D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f);
material.Ambient = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);

app->device.GetDevice()->SetMaterial(&material);

return true;
}

void TestGameScreen::OnUpdate(float dT)
{
if(app->input.KeyDown(XF::Keys::Q))
{
scale.x -= 1.0f * dT;
scale.y -= 1.0f * dT;
scale.z -= 1.0f * dT;
}

if(app->input.KeyDown(XF::Keys::R))
{
scale.x += 1.0f * dT;
scale.y += 1.0f * dT;
scale.z += 1.0f * dT;
}

if(app->input.KeyDown(XF::Keys::Up))
position.y += 0.5f * dT;

if(app->input.KeyDown(XF::Keys::Down))
position.y -= 0.5f * dT;

if(app->input.KeyDown(XF::Keys::Left))
position.x += 0.5f * dT;

if(app->input.KeyDown(XF::Keys::Right))
position.x -= 0.5f * dT;

if(app->input.KeyDown(XF::Keys::W))
rotation.z -= 0.5f * dT;

if(app->input.KeyDown(XF::Keys::E))
rotation.z += 0.5f * dT;

if(app->input.KeyDown(XF::Keys::S))
rotation.y -= 0.5f * dT;

if(app->input.KeyDown(XF::Keys:<img src='http://public.gamedev.net/public/style_emoticons/<#EMO_DIR#>/biggrin.gif' class='bbc_emoticon' alt=':D' />))
rotation.y += 0.5f * dT;
}

void TestGameScreen::OnDraw()
{
app->device.GetDevice()->SetRenderState(D3DRS_LIGHTING, false);
//app->device.GetDevice()->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(50, 50, 50));

app->device.GetDevice()->SetFVF(CUSTOMFVF);

XF::GFX::Matrix positionMatrix;
D3DXMatrixTranslation(&positionMatrix,
position.x,
position.y,
position.z);

XF::GFX::Matrix rotationMatrix;
D3DXMatrixRotationYawPitchRoll(
&rotationMatrix,
rotation.y,
rotation.x,
rotation.z);

XF::GFX::Matrix scaleMatrix;
D3DXMatrixScaling(&scaleMatrix,
scale.x,
scale.y,
scale.z);

app->device.GetDevice()->SetTransform(D3DTS_WORLD,
&(rotationMatrix * scaleMatrix * positionMatrix));

app->device.GetDevice()->SetTransform(D3DTS_VIEW, &viewMatrix);
app->device.GetDevice()->SetTransform(D3DTS_PROJECTION, &projMatrix);

app->device.GetDevice()->SetStreamSource(0, vBuffer, 0, sizeof(CustomVertex));
app->device.GetDevice()->SetIndices(iBuffer);

app->device.GetDevice()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);
}

void TestGameScreen::OnDestroy()
{
vBuffer->Release();
iBuffer->Release();
}




#include "TestGameScreen.h"

#define CUSTOMFVF (D3DFVF_XYZ | D3DFVF_NORMAL)

struct CustomVertex
{
float x, y, z;
XF::GFX::Vector3 normal;
};

bool TestGameScreen::OnInit()
{
CustomVertex vertices[] =
{
{ -1.0f, -1.0f, 1.0f, XF::GFX::Vector3(0.0f, 0.0f, 1.0f), }, // side 1
{ 1.0f, -1.0f, 1.0f, XF::GFX::Vector3(0.0f, 0.0f, 1.0f), },
{ -1.0f, 1.0f, 1.0f, XF::GFX::Vector3(0.0f, 0.0f, 1.0f), },
{ 1.0f, 1.0f, 1.0f, XF::GFX::Vector3(0.0f, 0.0f, 1.0f), },

{ -1.0f, -1.0f, -1.0f, XF::GFX::Vector3(0.0f, 0.0f, -1.0f), }, // side 2
{ -1.0f, 1.0f, -1.0f, XF::GFX::Vector3(0.0f, 0.0f, -1.0f), },
{ 1.0f, -1.0f, -1.0f, XF::GFX::Vector3(0.0f, 0.0f, -1.0f), },
{ 1.0f, 1.0f, -1.0f, XF::GFX::Vector3(0.0f, 0.0f, -1.0f), },

{ -1.0f, 1.0f, -1.0f, XF::GFX::Vector3(0.0f, 1.0f, 0.0f), }, // side 3
{ -1.0f, 1.0f, 1.0f, XF::GFX::Vector3(0.0f, 1.0f, 0.0f), },
{ 1.0f, 1.0f, -1.0f, XF::GFX::Vector3(0.0f, 1.0f, 0.0f), },
{ 1.0f, 1.0f, 1.0f, XF::GFX::Vector3(0.0f, 1.0f, 0.0f), },

{ -1.0f, -1.0f, -1.0f, XF::GFX::Vector3(0.0f, -1.0f, 0.0f), }, // side 4
{ 1.0f, -1.0f, -1.0f, XF::GFX::Vector3(0.0f, -1.0f, 0.0f), },
{ -1.0f, -1.0f, 1.0f, XF::GFX::Vector3(0.0f, -1.0f, 0.0f), },
{ 1.0f, -1.0f, 1.0f, XF::GFX::Vector3(0.0f, -1.0f, 0.0f), },

{ 1.0f, -1.0f, -1.0f, XF::GFX::Vector3(1.0f, 0.0f, 0.0f), }, // side 5
{ 1.0f, 1.0f, -1.0f, XF::GFX::Vector3(1.0f, 0.0f, 0.0f), },
{ 1.0f, -1.0f, 1.0f, XF::GFX::Vector3(1.0f, 0.0f, 0.0f), },
{ 1.0f, 1.0f, 1.0f, XF::GFX::Vector3(1.0f, 0.0f, 0.0f), },

{ -1.0f, -1.0f, -1.0f, XF::GFX::Vector3(-1.0f, 0.0f, 0.0f), }, // side 6
{ -1.0f, -1.0f, 1.0f, XF::GFX::Vector3(-1.0f, 0.0f, 0.0f), },
{ -1.0f, 1.0f, -1.0f, XF::GFX::Vector3(-1.0f, 0.0f, 0.0f), },
{ -1.0f, 1.0f, 1.0f, XF::GFX::Vector3(-1.0f, 0.0f, 0.0f), },
};

short indices[] =
{
0, 1, 2, // side 1
2, 1, 3,
4, 5, 6, // side 2
6, 5, 7,
8, 9, 10, // side 3
10, 9, 11,
12, 13, 14, // side 4
14, 13, 15,
16, 17, 18, // side 5
18, 17, 19,
20, 21, 22, // side 6
22, 21, 23,
};

app->device.GetDevice()->CreateVertexBuffer(
24 * sizeof(CustomVertex),
0,
CUSTOMFVF,
D3DPOOL_MANAGED,
&vBuffer,
NULL);

app->device.GetDevice()->CreateIndexBuffer(
36 * sizeof(short),
0,
D3DFMT_INDEX16,
D3DPOOL_MANAGED,
&iBuffer,
NULL);

void* voidPtr;
vBuffer->Lock(0, 0, (void**)&voidPtr, 0);
memcpy(voidPtr, vertices, sizeof(vertices));
vBuffer->Unlock();

iBuffer->Lock(0, 0, (void**)&voidPtr, 0);
memcpy(voidPtr, indices, sizeof(indices));
iBuffer->Unlock();

D3DXMatrixLookAtLH( &viewMatrix,
&XF::GFX::Vector3(0.0f, 0.0f, 10.0f),
&XF::GFX::Vector3Zero,
&XF::GFX::Vector3Up);

D3DXMatrixPerspectiveFovLH( &projMatrix,
D3DXToRadian(45),
(float)app->device.GetPresentationParameters().BackBufferWidth /
(float)app->device.GetPresentationParameters().BackBufferHeight,
1.0f,
100.0f);

position = XF::GFX::Vector3Zero;
rotation = XF::GFX::Vector3Zero;
scale = XF::GFX::Vector3One;

ZeroMemory(&light, sizeof(light));
light.Type = D3DLIGHT_DIRECTIONAL;
light.Diffuse = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f);
light.Direction = XF::GFX::Vector3(-1.0f, -0.3f, -1.0f);

app->device.GetDevice()->SetLight(0, &light);
app->device.GetDevice()->LightEnable(0, true);

ZeroMemory(&material, sizeof(XF::GFX::D3DMaterial));
material.Diffuse = D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f);
material.Ambient = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);

app->device.GetDevice()->SetMaterial(&material);

return true;
}

void TestGameScreen::OnUpdate(float dT)
{
if(app->input.KeyDown(XF::Keys::Q))
{
scale.x -= 1.0f * dT;
scale.y -= 1.0f * dT;
scale.z -= 1.0f * dT;
}

if(app->input.KeyDown(XF::Keys::R))
{
scale.x += 1.0f * dT;
scale.y += 1.0f * dT;
scale.z += 1.0f * dT;
}

if(app->input.KeyDown(XF::Keys::Up))
position.y += 0.5f * dT;

if(app->input.KeyDown(XF::Keys::Down))
position.y -= 0.5f * dT;

if(app->input.KeyDown(XF::Keys::Left))
position.x += 0.5f * dT;

if(app->input.KeyDown(XF::Keys::Right))
position.x -= 0.5f * dT;

if(app->input.KeyDown(XF::Keys::W))
rotation.z -= 0.5f * dT;

if(app->input.KeyDown(XF::Keys::E))
rotation.z += 0.5f * dT;

if(app->input.KeyDown(XF::Keys::S))
rotation.y -= 0.5f * dT;

if(app->input.KeyDown(XF::Keys:<img src='http://public.gamedev.net/public/style_emoticons/<#EMO_DIR#>/biggrin.gif' class='bbc_emoticon' alt=':D' />))
rotation.y += 0.5f * dT;
}

void TestGameScreen::OnDraw()
{
app->device.GetDevice()->SetRenderState(D3DRS_LIGHTING, true);
app->device.GetDevice()->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(50, 50, 50));

app->device.GetDevice()->SetFVF(CUSTOMFVF);

XF::GFX::Matrix positionMatrix;
D3DXMatrixTranslation(&positionMatrix,
position.x,
position.y,
position.z);

XF::GFX::Matrix rotationMatrix;
D3DXMatrixRotationYawPitchRoll(
&rotationMatrix,
rotation.y,
rotation.x,
rotation.z);

XF::GFX::Matrix scaleMatrix;
D3DXMatrixScaling(&scaleMatrix,
scale.x,
scale.y,
scale.z);

app->device.GetDevice()->SetTransform(D3DTS_WORLD,
&(rotationMatrix * scaleMatrix * positionMatrix));

app->device.GetDevice()->SetTransform(D3DTS_VIEW, &viewMatrix);
app->device.GetDevice()->SetTransform(D3DTS_PROJECTION, &projMatrix);

app->device.GetDevice()->SetStreamSource(0, vBuffer, 0, sizeof(CustomVertex));
app->device.GetDevice()->SetIndices(iBuffer);

app->device.GetDevice()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);
}

void TestGameScreen::OnDestroy()
{
vBuffer->Release();
iBuffer->Release();
}



#include <Windows.h>

#include <d3d9.h>
#include <d3dx9.h>

#ifndef XF_GFX_DX9TYPEDEFSANDDEFINES_H
#define XF_GFX_DX9TYPEDEFSANDDEFINES_H

namespace XF
{
namespace GFX
{
typedef LPDIRECT3D9 Direct3D;
typedef LPDIRECT3DDEVICE9 Direct3DDevice;
typedef D3DPRESENT_PARAMETERS PresentationParameters;

typedef LPDIRECT3DVERTEXBUFFER9 VertexBuffer;
typedef LPDIRECT3DINDEXBUFFER9 IndexBuffer;

typedef D3DXMATRIX Matrix;
static const Matrix MatrixIdentity = Matrix(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);

typedef D3DXVECTOR3 Vector3;
static const Vector3 Vector3Zero = Vector3(0.0f, 0.0f, 0.0f);
static const Vector3 Vector3One = Vector3(1.0f, 1.0f, 1.0f);
static const Vector3 Vector3Up = Vector3(0.0f, 1.0f, 0.0f);
static const Vector3 Vector3Down = Vector3(0.0f, -1.0f, 0.0f);
static const Vector3 Vector3Left = Vector3(-1.0f, 0.0f, 0.0f);
static const Vector3 Vector3Right = Vector3(1.0f, 0.0f, 0.0f);
static const Vector3 Vector3In = Vector3(0.0f, 0.0f, 1.0f);
static const Vector3 Vector3Out = Vector3(0.0f, 0.0f, -1.0f);

typedef D3DXVECTOR2 Vector2;
static const Vector2 Vector2Zero = Vector2(0.0f, 0.0f);
static const Vector2 Vector2One = Vector2(1.0f, 1.0f);
static const Vector2 Vector2Up = Vector2(0.0f, 1.0f);
static const Vector2 Vector2Down = Vector2(0.0f, -1.0f);
static const Vector2 Vector2Left = Vector2(-1.0f, 0.0f);
static const Vector2 Vector2Right = Vector2(1.0f, 0.0f);

typedef D3DLIGHT9 Light;
typedef D3DMATERIAL9 D3DMaterial;
}
}

#endif
Game development blog and portfolio: http://gamexcore.co.uk
GregMichael
GregMichael
Have you tried updating your graphics card drivers....seems like you have a ghost in the machine
gameXcore
gameXcore
Well I'm working on my laptop which at the tail end of last week had a fresh install of Windows 7, and then the 4 terrabytes of updates to everything that comes with it, including updates for the graphics drivers, I guess tomorro I could try seeing if my drivers are actually upto date. I could also try running on a different machine, I would have to get it set up tho.

This is indeed bizarre.
Game development blog and portfolio: http://gamexcore.co.uk
GregMichael
GregMichael
Let us know how you get on....it does seem to be very bizarre. Probably simple to fix though...once you know what it is
gameXcore
gameXcore
Ok, So I got home from work and decided to do some investigation, drivers upto date etc. I also noticed a distinct "flicker" in the window which was occuring at regular 6 second intervals. I started prodding and poking, removing and adding trying to narrow down what was causing the problem, I then noticed that in the version using no lighting the cube wasn't displaying correctly, only the front and back sides were visible.

Anyway, I narrowed that down to the drawIndexedPrimitive call being incorrect:

app->device.GetDevice()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);

Whereas actually there are 24 verices:

app->device.GetDevice()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 24, 0, 12);


Fixing this call cause the problem to go away, what I don't understand is why it occured in the first place?

Can anyone explain this?

Thanks, Scott
Game development blog and portfolio: http://gamexcore.co.uk
Evil Steve
Evil Steve
You told the graphics card that it only has to process 8 vertices, because only the first 8 in the vertex buffer are actually used. That value tells the driver how many vertices it needs to run through the vertex shader before it can assemble triangles from them. Using vertices outside that range is undefined behaviour, but I'd guess that the driver has some internal buffer that happens to be big enough for exactly 6 seconds worth of vertex data, and it just happened to be only partially filling it in some way which causes it to start recycling the old vertices when it's full.
gameXcore
gameXcore

You told the graphics card that it only has to process 8 vertices, because only the first 8 in the vertex buffer are actually used. That value tells the driver how many vertices it needs to run through the vertex shader before it can assemble triangles from them. Using vertices outside that range is undefined behaviour, but I'd guess that the driver has some internal buffer that happens to be big enough for exactly 6 seconds worth of vertex data, and it just happened to be only partially filling it in some way which causes it to start recycling the old vertices when it's full.


That makes sense, a circular buffer of some sort, with the numbers being just right to give the effect, an interesting one definately!
Game development blog and portfolio: http://gamexcore.co.uk
GregMichael
GregMichael
I blame the ghosts...though Evil Steve knows what he's talking about

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.