Sign in to follow this  

Lighting won't work with vertex colors

This topic is 4306 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying to get lighting working and for the life of me I can't get it to work. I've tried everything I can possibly think of to get it to work properly but it just won't work. Here's the problem: when I turn on lighting it always uses the material as the source color instead of the vertex color and so everything is being drawn as white. I'm trying to use a white directional light that's pointing straight down onto the map with a white material so 100% of the vertex color shines through. The vertex colors exist: when I turn off lighting the map is colored by vertex colors properly. The vertex normals are correct and even if they weren't I tried setting all normals to up just to see what would happen and everything still stayed white. Here's the relevant rendering code, minus error checking for compactness (errors aren't a problem either):
/*Vertex info
struct Vertex
{
	float x,y,z;
	float nx,ny,nz;
	D3DCOLOR col;		
};

#define D3DFVF_MYVERTEX ( D3DFVF_XYZ  | D3DFVF_NORMAL | D3DFVF_DIFFUSE )
*/
pD3DDev->SetRenderState( D3DRS_LIGHTING, TRUE );
pD3DDev->SetRenderState( D3DRS_COLORVERTEX, TRUE );
pD3DDev->SetRenderState( D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1 );
pD3DDev->SetRenderState( D3DRS_AMBIENT, 0 );
pD3DDev->SetRenderState( D3DRS_SPECULARENABLE, FALSE );

D3DLIGHT9 light;
ZeroMemory( &light, sizeof(D3DLIGHT9) );
light.Direction = D3DXVECTOR3(0,-1,0);
light.Ambient.r = light.Diffuse.r = 1.f;
light.Ambient.g = light.Diffuse.g = 1.f;
light.Ambient.b = light.Diffuse.b = 1.f;
light.Ambient.a = light.Diffuse.a = 1.f;
light.Type = D3DLIGHT_DIRECTIONAL;

pD3DDev->SetLight( 0, &light );
pD3DDev->LightEnable( 0, TRUE );
			
D3DMATERIAL9 mtrl;
ZeroMemory( &mtrl, sizeof(mtrl) );
mtrl.Diffuse.r = mtrl.Ambient.r = 1.f;
mtrl.Diffuse.g = mtrl.Ambient.g = 1.f;
mtrl.Diffuse.b = mtrl.Ambient.b = 1.f;
mtrl.Diffuse.a = mtrl.Ambient.a = 1.f;

pD3DDev->SetMaterial( &mtrl );

D3DXMATRIX temp;

//Removed: Matrix operations on temp

pMxStack->MultMatrixLocal( &temp );
pD3DDev->SetTransform( D3DTS_WORLD, pMxStack->GetTop() );
pD3DDev->SetFVF( D3DFVF_MYVERTEX );

//Removed: Map drawing function call
pD3DDev->SetRenderState( D3DRS_LIGHTING, FALSE );





So, can anyone help me with this problem? I've been working on it for the last three hours and it's driving me crazy.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I've never used the D3D fixed function lighting (always calculated it myself), so this is just a guess, but it's not the

pD3DDev->SetRenderState( D3DRS_COLORVERTEX, FALSE );

is it? Shouldn't that be set to true?

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
I've never used the D3D fixed function lighting (always calculated it myself), so this is just a guess, but it's not the

pD3DDev->SetRenderState( D3DRS_COLORVERTEX, FALSE );

is it? Shouldn't that be set to true?

Yes, and the code I copied was me testing what would happen if I turned it off. Either way it still breaks but I've corrected the code in the original post now.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Try setting the ambient to something other than pure white. It could be that the lighting calculation is just saturating out because of this.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Try this:

IDirect3DDevice9::SetRenderState( D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1 );

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
Try setting the ambient to something other than pure white. It could be that the lighting calculation is just saturating out because of this.
Nope, already tried that. I tried not adding a light and the map is rendered as black. I add a light and don't add a material and the map renders as black. I tried setting all light values to .5 but it just made everything gray. I tried setting material values to .5 and light back at 1 and it was the same gray color. I tried both, it was darker gray, which means the material is being treated as the source color, even though I'm explicitly setting the renderstate to use the vertex color.I've tried doing it with alpha on and alpha off to see if that would do anything. I tried turning culling off as well as turning the zbuffer off. Nothing caused any change. I tried changing the light to a point light and what I ended up with was a big white circle surrounded by black. I've tried changing the direction vector to be pointing in all sorts of directions, but there's no change. Nothing's working, so I'm going to try using vertex declarations instead of FVF and see if that helps.

Edit: Using vertex declarations doesn't help either. I might just have to give up on my goal of having this work on Fixed-Function-Only video cards.

Share this post


Link to post
Share on other sites
Hi!

I don't know about DirectX, but in OpenGL, vertex colors don't work with lighting. It won't probably work on DirectX either, after all, they work on the same hardware with the same specs.

In OpenGL, however, there is glColorMaterial, an option to make current material properties track to the vertex colors. It first needs to be enabled and then the user has to define which material properties are tracked. For example:
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);

There seems to be some cryptic notes on the glColorMaterial manual page, which seem to say that glColorMaterial might not work properly with vertex arrays under certain conditions.

I suggest you stop using vertex colors and go with the material functionality of DirectX.

-Richardo

Share this post


Link to post
Share on other sites
RichardoX is quite right, if you specify pD3DDev->SetRenderState( D3DRS_LIGHTING, TRUE );, then D3D will attempt to calculate the lighting, even though you're specifying it. Set it to false before rendering.

Share this post


Link to post
Share on other sites
Quote:
Original post by _goat
RichardoX is quite right, if you specify pD3DDev->SetRenderState( D3DRS_LIGHTING, TRUE );, then D3D will attempt to calculate the lighting, even though you're specifying it. Set it to false before rendering.
So what you're saying is this part from the GameDev Forums DirectX FAQ is incorrect:
Quote:
How is the color at a vertex eventually determined?
The color at a vertex depends on three things: whether there is a D3DFVF_DIFFUSE element in the vertex structure, whether the D3DRS_COLORVERTEX state is set, and whether the D3DRS_LIGHTING state is set:


D3DRS_LIGHTING

| D3DRS_COLORVERTEX

| | D3DFVF_DIFFUSE in vertex

| | | Result

----------------------------

0 0 0 White

0 1 0 White

0 1 0 White

0 1 1 Vertex Color

1 0 0 Material Color * Light

1 0 1 Material Color * Light

1 1 0 Material Color * Light

1 1 1 (Material Or Vertex Color) * Light

The last of those - (Material Color or Vertex Color) * Light – is determined by a set of four render states:
- D3DRS_DIFFUSEMATERIALSOURCE
- D3DRS_AMBIENTMATERIALSOURCE
- D3DRS_SPECULARMATERIALSOURCE
- D3DRS_EMISSIVEMATERIALSOURCE

Each of them can be set to:
(a) D3DMCS_MATERIAL, which uses the value from the material
(b) D3DMCS_COLOR1, which uses the vertex's diffuse color value
(c) D3DMCS_COLOR2, which uses the vertex's specular value

There is no way to get material color effects without enabling lighting.

If what you're saying is correct, the last line where it's 1 1 1 should be corrected to say "Material Color * Light."

Share this post


Link to post
Share on other sites
Vertex colors and lighting work together just fine in DirectX. ColorVertex and DiffuseMaterialSource are all you should need set for it to work. The whole point of all the *MaterialSource states is to choose between material and vertex coloring in lighting equations.

Something you're doing must be turning off those render states. Try reducing it down to a simple example case. Set the states right in front of the DrawIndexedPrimitive call to ensure nothing else is setting a state unexpectedly.

I'll whip together an example in just a second...

Share this post


Link to post
Share on other sites

#include "windows.h"
#include "d3d9.h"
#include "d3dx9.h"

#ifdef _DEBUG
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9d.lib")
#else
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#endif

HINSTANCE g_3DhInst;
ATOM g_3DWinClass;
HWND g_3DWindow=0;
HWND g_3DFocusWindow=0;
DWORD g_3DWindowStyleWin;
DWORD g_3DWindowStyleFullScreen;
DWORD g_3DWindowStyleExWin;
DWORD g_3DWindowStyleExFullScreen;
D3DPRESENT_PARAMETERS g_d3dpp;
LPDIRECT3D9 g_pD3D=0;
LPDIRECT3DDEVICE9 g_pDev=0;
bool g_bResetDevice = false;
char g_strWinClass[] = "QuickDX9";
char g_strWinTitle[] = "TestApp";

LRESULT WINAPI TestWinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (msg==WM_CLOSE)
{
PostQuitMessage(0);
}
else if (msg==WM_SIZE)
{
g_bResetDevice = true;
}
else if (msg==WM_KEYDOWN && wParam == VK_ESCAPE)
{
PostQuitMessage(0);
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}

bool RegisterWin()
{
WNDCLASSEX wndclass;

memset(&wndclass, 0, sizeof(wndclass));
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.style = CS_OWNDC;
wndclass.lpfnWndProc = TestWinProc;
wndclass.hInstance = g_3DhInst;
wndclass.lpszClassName = g_strWinClass;
g_3DWinClass = RegisterClassEx(&wndclass);
return g_3DWinClass != 0;
}

bool CreateWin()
{
RECT rc;

g_3DWindowStyleFullScreen = g_3DWindowStyleWin = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
g_3DWindowStyleExFullScreen = g_3DWindowStyleExWin = WS_EX_OVERLAPPEDWINDOW;
rc.left = 0;
rc.top = 0;
rc.right = 800;
rc.bottom = 600;
AdjustWindowRectEx(&rc, g_3DWindowStyleWin, false, g_3DWindowStyleExWin);
g_3DFocusWindow = CreateWindowEx(g_3DWindowStyleExWin, g_strWinClass, g_strWinTitle, g_3DWindowStyleWin, 0, 0, rc.right - rc.left, rc.bottom - rc.top, 0, 0, g_3DhInst, 0);
g_3DWindow = g_3DFocusWindow;
return g_3DWindow != 0;
}

bool MsgPump()
{
MSG msg;
static bool exit = false;

if (exit)
return false;

while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
exit = true;
return false;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return true;
}

void Cleanup()
{
if (g_pDev)
g_pDev->Release();
if (g_pD3D)
g_pD3D->Release();
if (g_3DWindow)
DestroyWindow(g_3DWindow);
}


bool CreateD3D()
{
g_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
return g_pD3D != 0;
}

bool CreateDevice()
{
RECT rc;

GetClientRect(g_3DWindow, &rc);
memset(&g_d3dpp, 0, sizeof(g_d3dpp));
g_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
g_d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
g_d3dpp.EnableAutoDepthStencil = true;
g_d3dpp.AutoDepthStencilFormat = D3DFMT_D24X8;
g_d3dpp.hDeviceWindow = g_3DWindow;
g_d3dpp.BackBufferWidth = rc.right - rc.left;
g_d3dpp.BackBufferHeight = rc.bottom - rc.top;
g_d3dpp.BackBufferCount = 1;
g_d3dpp.Windowed = true;
g_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE ;
if (FAILED(g_pD3D->CreateDevice(0, D3DDEVTYPE_HAL, g_3DFocusWindow, D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_d3dpp, &g_pDev)))
return false;
return true;
}

bool ResetDevice()
{
if (FAILED(g_pDev->Reset(&g_d3dpp)))
return false;
return true;
}

bool TestDevice()
{
HRESULT hr = g_pDev->TestCooperativeLevel();

if (hr == D3DERR_DEVICENOTRESET || (hr == S_OK && g_bResetDevice))
{
g_bResetDevice = false;
if (!ResetDevice())
return false;
}
else if (hr == D3DERR_DEVICELOST)
return false;

return true;
}

class TestVert
{
public:
float x,y,z;
float nx,ny,nz;
DWORD color;
};

TestVert g_aoVerts[4];
D3DXMATRIX w,v,p;

void TestUpdate()
{
g_aoVerts[0].x = -1;
g_aoVerts[0].y = -1;
g_aoVerts[0].z = 0;
g_aoVerts[0].nx = 0;
g_aoVerts[0].ny = 0;
g_aoVerts[0].nz = -1;
g_aoVerts[0].color = 0xFFFF0000;

g_aoVerts[1].x = -1;
g_aoVerts[1].y = 1;
g_aoVerts[1].z = 0;
g_aoVerts[1].nx = 0;
g_aoVerts[1].ny = 0;
g_aoVerts[1].nz = -1;
g_aoVerts[1].color = 0xFFFFFF00;

g_aoVerts[2].x = 1;
g_aoVerts[2].y = -1;
g_aoVerts[2].z = 0;
g_aoVerts[2].nx = 0;
g_aoVerts[2].ny = 0;
g_aoVerts[2].nz = -1;
g_aoVerts[2].color = 0xFFFF00FF;

g_aoVerts[3].x = 1;
g_aoVerts[3].y = 1;
g_aoVerts[3].z = 0;
g_aoVerts[3].nx = 0;
g_aoVerts[3].ny = 0;
g_aoVerts[3].nz = -1;
g_aoVerts[3].color = 0xFFFFFFFF;

POINT pt;
GetCursorPos(&pt);
D3DXMatrixRotationYawPitchRoll(&w, (pt.x - 400.0f) / 400 * D3DX_PI / 2, (pt.y - 300.0f) / 300 * D3DX_PI / 2, 0);

w._43 = 5;
D3DXMatrixPerspectiveFovLH(&p, D3DX_PI/4, 1.0, 0.1f, 500.0f);

g_pDev->SetTransform(D3DTS_WORLD, &w);
g_pDev->SetTransform(D3DTS_PROJECTION, &p);
D3DXMatrixIdentity(&w);
g_pDev->SetTransform(D3DTS_VIEW, &w);
}

void TestRender()
{
g_pDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
g_pDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
g_pDev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
g_pDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);

g_pDev->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
g_pDev->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

g_pDev->SetRenderState(D3DRS_LIGHTING, true);

D3DMATERIAL9 mat;

memset(&mat, 0, sizeof(mat));
mat.Diffuse.r = 0.56f;
mat.Diffuse.g = 0.34f;
mat.Diffuse.b = 0.12f;
mat.Diffuse.a = 1;
g_pDev->SetMaterial(&mat);

D3DLIGHT9 light;

memset(&light, 0, sizeof(light));
light.Direction.x = 0;
light.Direction.y = 0;
light.Direction.z = 1;
light.Type = D3DLIGHT_DIRECTIONAL;
light.Diffuse.r = 1;
light.Diffuse.g = 1;
light.Diffuse.b = 1;
light.Diffuse.a = 1;
g_pDev->LightEnable(0, false);
g_pDev->SetLight(0, &light);
g_pDev->LightEnable(1, true);

g_pDev->SetFVF(D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE);
g_pDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
g_pDev->SetRenderState(D3DRS_COLORVERTEX, true);

if (GetKeyState(VK_SPACE) & 0x80)
g_pDev->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
else
g_pDev->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);

g_pDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, g_aoVerts, sizeof(TestVert));
}

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdLine, int cmdShow)
{

g_3DhInst = hInst;
do
{
if (!RegisterWin())
break;
if (!CreateWin())
break;
if (!CreateD3D())
break;
if (!CreateDevice())
break;
while (MsgPump())
{
if (TestDevice())
{
TestUpdate();
g_pDev->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x456789, 1.0f, 0);
g_pDev->BeginScene();
TestRender();
g_pDev->EndScene();
g_pDev->Present(0,0,0,0);
}
};
} while (0);

Cleanup();

return 0;
}


Create an empty project, don't bother to setup your libs (the code does it magically), add this single file, compile and run.

Mouse rotates the quad. Hold space to change between vertex or material lighting.

Share this post


Link to post
Share on other sites

This topic is 4306 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this