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

Primitives and light source problem?

Started by wicked357 Mar 23, 2009 at 8:47 PM 14 replies 2.4k views
Original Post
wicked357
wicked357
I am messing around with lighting since I happen to be on that chapter and wonder how I can have lighting on primitive objects, below is my related code:

LPDIRECT3D9 g_D3D = NULL;
LPDIRECT3DDEVICE9 g_D3DDevice = NULL;

D3DXMATRIX g_projection;
D3DXMATRIX g_ViewMatrix;
D3DXMATRIX g_WorldMatrix;

D3DMATERIAL9 g_material;

D3DLIGHT9 g_light;

struct stD3DVertex
{
	float x, y, z, rhw;
	unsigned long color;
};

#define D3DFVF_VERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)

Now that my global area this is my projection matrix in my initializeD3D()

D3DXMatrixPerspectiveFovLH(&g_projection, 45.0f,
      WINDOW_WIDTH/WINDOW_HEIGHT, 0.1f, 1000.0f);

g_D3DDevice->SetTransform(D3DTS_PROJECTION, &g_projection);

This is my initializeObject()

stD3DVertex objData[] =
	{
		{175.0f, 50.0f, 0, 1.0f, D3DCOLOR_XRGB(255, 255, 255), },
		{250.0f, 200.0f, 0, 1.0f, D3DCOLOR_XRGB(255, 255, 255), },
		{100.0f, 200.0f, 0, 1.0f, D3DCOLOR_XRGB(255, 255, 255), },
	};

	// Create the vertex buffer.
   if(FAILED(g_D3DDevice->CreateVertexBuffer(sizeof(objData), 0,
             D3DFVF_VERTEX, D3DPOOL_DEFAULT, &g_VertexBuffer,
             NULL))) return false;

   // Fill the vertex buffer.
   void *ptr;

   if(FAILED(g_VertexBuffer->Lock(0, sizeof(objData),
      (void**)&ptr, 0))) return false;

   memcpy(ptr, objData, sizeof(objData));

   g_VertexBuffer->Unlock();

   g_D3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
   g_D3DDevice->SetRenderState(D3DRS_AMBIENT,
      D3DCOLOR_COLORVALUE(0.3f, 0.3f, 0.3f, 1.0f));

   g_light.Type = D3DLIGHT_DIRECTIONAL;
   g_light.Direction = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
   g_light.Diffuse.r = g_light.Diffuse.g = 1;
   g_light.Diffuse.b = g_light.Diffuse.a = 1;
   g_light.Specular.r = g_light.Specular.g = 1;
   g_light.Specular.b = g_light.Specular.a = 1;

   g_D3DDevice->SetLight(0, &g_light);
   g_D3DDevice->LightEnable(0, TRUE);

   // Setup the material properties for the teapot.
   ZeroMemory(&g_material, sizeof(D3DMATERIAL9));
   g_material.Diffuse.r = g_material.Ambient.r = 0.6f;
   g_material.Diffuse.g = g_material.Ambient.g = 0.6f;
   g_material.Diffuse.b = g_material.Ambient.b = 0.7f;
   g_material.Specular.r = 0.4f;
   g_material.Specular.g = 0.4f;
   g_material.Specular.b = 0.4f;
   g_material.Power = 8.0f;

   D3DXVECTOR3 cameraPos(0.0f, 0.0f, -8.0f);
   D3DXVECTOR3 lookAtPos(0.0f, 0.0f, 0.0f);
   D3DXVECTOR3 upDir(0.0f, 1.0f, 0.0f);

   D3DXMatrixLookAtLH(&g_ViewMatrix, &cameraPos, &lookAtPos, &upDir);

And now my renderScene()

   g_D3DDevice->SetStreamSource(0, g_VertexBuffer, 0, sizeof(stD3DVertex));
      g_D3DDevice->SetFVF(D3DFVF_VERTEX);
      g_D3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

      // Apply the view (camera).
      g_D3DDevice->SetTransform(D3DTS_VIEW, &g_ViewMatrix);

Supernat02
Supernat02
Is there anything in the chapter about normals? You can't use the RHW FVF type (I don't think). You have to have a vertex format of (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE) and add normals (3 floats) to your vertex structure. The pipeline uses the normals (vertex normals) to define the amount of light hitting each vertex. It is then shaded between vertices. Make sure the normals are normalized, or you can turn on a Render State (forget the name) to always normalize normals within the pipeline itself.

Chris

Chris ByersMicrosoft DirectX MVP - 2005
wicked357
wicked357
Okay, so this is what I have come up with as soon as I start using the normals I cannot even get my primitive to show, what is the problem here. Here is my changed code: (I switch from drawing a triangle to a quad instead, no reason)

struct stD3DVertex{	float x, y, z;	D3DVECTOR normal;	unsigned long color;};#define D3DFVF_VERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE)

stD3DVertex objData[] ={    { 420, 150, 0.5f, 1, 0, 1, D3DCOLOR_XRGB(255, 255, 255), },    { 420, 350, 0.5f, 1, 0, 1, D3DCOLOR_XRGB(255, 255, 255), },    { 220, 150, 0.5f, 1, 0, 1, D3DCOLOR_XRGB(255, 255, 255), },    { 220, 350, 0.5f, 1, 0, 1, D3DCOLOR_XRGB(255, 255, 255), },};

g_D3DDevice->SetTransform(D3DTS_VIEW, &g_ViewMatrix);;g_D3DDevice->SetStreamSource(0, g_VertexBuffer, 0, sizeof(stD3DVertex));g_D3DDevice->SetFVF(D3DFVF_VERTEX);g_D3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);


That is all I changed and I thought it would work, but I must be missing something somewhere, anyone got any suggestions?
programci_84
programci_84
You must setup a D3DMATERIAL9 object (I saw that you did it with "g_material") and before calling IDirect3DDevice9::DrawPrimitive() or IDirect3DDevice9::DrawPrimitiveUP(), you must set this material as default:

g_D3DDevice->SetStreamSource(...);//other codes like FVF or something anotherg_D3DDevice->SetMaterial (&g_material);//to use textures: g_D3DDevice->SetTexture (/*an LPDIRECT3DTEXTURE9 object*/);g_D3DDevice->DrawPrimitive(...);


During setup of your vertices, you've to setup your normals as well. Consider you've a triangle and vertices V1, V2, V3 and also winding order is CW. You can calculate a vertex normal for V1 by performing cross product between vectors (V2 - V1) and (V3 - V1) then normalize the result.

Hope this helps.

Regards,
Rohat.
There's no "hard", and "the impossible" takes just a little time.
wicked357
wicked357
Thanks, I read more into the chapter and it doesn't really explain much about lighting primitives, but I noticed a long the way that I didn't give it the material, so I did that, I guess now my problem is figuring the normals out. I am not the best at math and I can't quite make out what you mean since I have 3 normals per. Can you explain it dumbed down?
programci_84
programci_84
Hi,

If you don't use any normal data, lighting will fail. You've to calculate'em for your primitives.

First, look at this picture: Vertices and Normals

Here an example:
struct SVertex{ D3DXVECTOR3 pos;  D3DXVECTOR3 nor; static const DWORD FVF = D3DFVF_XYZ | D3DFVF_NORMAL; //we don't need DIFFUSE because we'll use material};//defining vertices//Notice that winding order of vertices is clockwise.SVertex V[3];V[0].pos = D3DXVECTOR3 ( 100, 0, 0);V[1].pos = D3DXVECTOR3 ( 0, 100, 0);V[2].pos = D3DXVECTOR3 (-100, 0, 0);D3DXVECTOR3 n0, n1, n2; //vertex normal of vertices V[0]..[2] respectively.D3DXVECTOR3 r1, r2;//computing n0r1 = V[2] - V[0]; r2 = V[1] - V[0];D3DXVec3Cross (&n0, &r1, &r2); D3DXVec3Normalize (&n0, &n0);V[0].nor = n0;r1 = V[0] - V[1]; r2 = V[2] - V[1];D3DXVec3Cross (&n1, &r1, &r2); D3DXVec3Normalize (&n1, &n1);V[1].nor = n1;r1 = V[1] - V[2]; r2 = V[0] - V[2];D3DXVec3Cross (&n2, &r1, &r2); D3DXVec3Normalize (&n2, &n2);V[2].nor = n2;//just fill your g_VertexBuffer and g_material, also setup your lighting how you want.//...//Rendering codeg_D3DDevice->SetFVF (SVertex::FVF);g_D3DDevice->SetStreamSource(...);g_D3DDevice->SetMaterial(&g_material);g_D3DDevice->DrawPrimitive(...);
;
There's no "hard", and "the impossible" takes just a little time.
RichardUK
RichardUK
For a start your vertex 'D3DFVF_XYZRHW' is wrong. With the fixed function vertices passed as this enter the pipeline after lighting. These are pre transformed vertices.

Also you have to set view with the inverse camera and set D3DTS_WORLD to the local to world matrix. Your way will need the lights pos to be transformed into camera space, rather messy and wasteful if your using the fixed function pipe.

Also no lights are enabled. How can you light the object with no light?

Unfortunately you are using an obsolete interface. It's really only there for backward compatibility. I can understand why you want to use it but I recommend you learning shaders. It can be a steep hill to climb but there is a lot of tuts out there for it.
Evil Steve
Evil Steve
You're no longer specifying vertex coordinates in screen space, you're using 3D world space coordinates now. Your camera is at (0, 0, -8), looking along +Z, but the quad is around (220, 150, 0.5) to (420, 350, 0.5). It's probably off the screen to the right and up.

Try using coordinates like (-220, -150, 0.5) to (220, 150, 0.5) and see if it shows up then.
Even if the lighting isn't working right, it should still show up. I.e. the lighting isn't what's making it not appear.
wicked357
wicked357
programci_84:

I followed your sample there and end up with same error over and over, the error starts at,
r1 = V[2] - V[0];

Error	1	error C2676: binary '-' : 'stD3DVertex' does not define this operator or a conversion to a type acceptable to the predefined operator


Quote:
Original post by Evil Steve
It's probably off the screen to the right and up.

If I change it back to rhw and set it to 1 I have no problem with my quad being in the middle of window, why if I change to normals would it not appear?
Evil Steve
Evil Steve
Quote:
Original post by wicked357
Quote:
Original post by Evil Steve
It's probably off the screen to the right and up.

If I change it back to rhw and set it to 1 I have no problem with my quad being in the middle of window, why if I change to normals would it not appear?
It's nothing to do with adding normals, it's changing the vertex type from post-transformed (D3DFVF_XYZRHW, which is in screen space) to untransformed (D3DFVF_XYZ, which is in world space).
wicked357
wicked357
Quote:
Original post by Evil Steve
Quote:
Original post by wicked357
Quote:
Original post by Evil Steve
It's probably off the screen to the right and up.

If I change it back to rhw and set it to 1 I have no problem with my quad being in the middle of window, why if I change to normals would it not appear?
It's nothing to do with adding normals, it's changing the vertex type from post-transformed (D3DFVF_XYZRHW, which is in screen space) to untransformed (D3DFVF_XYZ, which is in world space).


Your right, I did what you said and I get some crap across my screen, now my question is, any advice on figuring out space correctly? Since I am used to using just window coordinates.

EDIT: BTW, still having the error issues for figuring out the normals as stated above. I commented out the normals for now so I could figure out the the are the primitive will be drawn I now have that drawn on the screen, I get some weird light effect but not correct and I assume that is because of the normals not being there. Anyone know how to fix that error?

[Edited by - wicked357 on March 25, 2009 11:37:34 AM]
Evil Steve
Evil Steve
Quote:
Original post by wicked357
Your right, I did what you said and I get some crap across my screen, now my question is, any advice on figuring out space correctly? Since I am used to using just window coordinates.
If you want to give your vertices in window coordinates rather than world coordinates (So using somewhat fake 2D), you can set up an ortho projection matrix:
D3DXMATRIX matProj;float w = 640.0f;   // Max X coordinate for viewportfloat h = 480.0f;   // Max X coordinate for viewportD3DXMatrixOrthoOffCenterLH(&matProj, 0.0f, w, h, 0.0f, 0.1f, 1000.0f);pDevice->SetTransform(D3DTS_PROJECTION, &matProj);

That'll set up a projection matrix like you get in CAD software, so objects further from the camera don't change in size (Code is untested).

If you want to do "real" 3D, then you have to work out what can and can't be seen - I usually do it quickly by trial and error, but it's perfectly possible to work out with some trigonometry.

Quote:
Original post by wicked357
EDIT: BTW, still having the error issues for figuring out the normals as stated above. I commented out the normals for now so I could figure out the the are the primitive will be drawn I now have that drawn on the screen, I get some weird light effect but not correct and I assume that is because of the normals not being there. Anyone know how to fix that error?
The normal of a triangle is the normalised cross product of the vectors formed by two of the triangle edges. If your vertices are v0, v1, v2, then N = Normalise(Cross(v1-v0, v2-v0)).
If that doesn't help, can we see the code you have currently?
wicked357
wicked357
Yea that is what I pretty much ended up doing was some trial and error but I got it figured out since the middle of the window was 0.0 (...) so I just started with very low decimal numbers to the size I liked. Anyways, I'm not able to make since of the n = normalise(cross(v1-v0, v2-v0)), especially since I get errors using v1-v0 and so forth.
wicked357
wicked357
Okay I have been doing some work arounds since I get errors for the above code and this is what I came up with, it compiles but I get no lighting on my primitive at all, what am I missing? (Code relative from the beginning)
D3DXMATRIX g_projection;D3DXMATRIX g_ViewMatrix;D3DXMATRIX g_WorldMatrix;D3DMATERIAL9 g_material;LPDIRECT3DVERTEXBUFFER9 g_VertexBuffer = NULL;struct stD3DVertex{	D3DXVECTOR3 pos;	D3DXVECTOR3 nor;};#define D3DFVF_VERTEX (D3DFVF_XYZ | D3DFVF_NORMAL)

D3DXMatrixPerspectiveFovLH(&g_projection, 45.0f,    WINDOW_WIDTH/WINDOW_HEIGHT, 0.1f, 1000.0f);g_D3DDevice->SetTransform(D3DTS_PROJECTION, &g_projection);

stD3DVertex objData[3];objData[0].pos = D3DXVECTOR3 (0.0f, 0.2f, 0);objData[1].pos = D3DXVECTOR3 (0.2f, -0.2f, 0);objData[2].pos = D3DXVECTOR3 (-0.2f, -0.2f, 0);	//Vector for normalsD3DXVECTOR3 n0, n1, n2;D3DXVECTOR3 r1, r2;//computing for n0r1 = D3DXVECTOR3(-0.2f, -0.2f, 0.0f) - D3DXVECTOR3(0.0f, 0.2f, 0.0f);r2 = D3DXVECTOR3(0.2f, -0.2f, 0.0f) - D3DXVECTOR3(0.0f, 0.2f, 0.0f);D3DXVec3Cross (&n0, &r1, &r2);D3DXVec3Normalize (&n0, &n0);objData[0].nor = n0;//computing for n1r1 = D3DXVECTOR3(0.0f, 0.2f, 0.0f) - D3DXVECTOR3(0.2f, -0.2f, 0.0f);r2 = D3DXVECTOR3(-0.2f, -0.2f, 0.0f) - D3DXVECTOR3(0.2f, -0.2f, 0.0f);D3DXVec3Cross (&n1, &r1, &r2);D3DXVec3Normalize (&n1, &n1);objData[1].nor = n1;//computing for n2r1 = D3DXVECTOR3(0.2f, -0.2f, 0.0f) - D3DXVECTOR3(-0.2f, -0.2f, 0.0f);r2 = D3DXVECTOR3(0.0f, 0.2f, 0.0f) - D3DXVECTOR3(-0.2f, -0.2f, 0.0f);D3DXVec3Cross (&n2, &r1, &r2);D3DXVec3Normalize (&n2, &n2);objData[2].nor = n2;// Create the vertex buffer.if(FAILED(g_D3DDevice->CreateVertexBuffer(sizeof(objData), 0,    D3DFVF_VERTEX, D3DPOOL_DEFAULT, &g_VertexBuffer, NULL)))    return false;// Fill the vertex buffer.void *ptr;if(FAILED(g_VertexBuffer->Lock(0, sizeof(objData), (void**)&ptr, 0)))    return false;memcpy(ptr, objData, sizeof(objData));g_VertexBuffer->Unlock();

//Set default rendering statesg_D3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);g_D3DDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_COLORVALUE(0.3f, 0.3f,    0.3f, 1.0f));//Setup the light sourceg_light.Type = D3DLIGHT_POINT;g_light.Position = D3DXVECTOR3(move.x, 0.0f, -5.0f);g_light.Diffuse.r = 127;g_light.Diffuse.g = 127;g_light.Diffuse.b = 1;g_light.Attenuation0 = 0.5f;g_light.Range = 5.0f;//Register the lightg_D3DDevice->SetLight(0, &g_light);g_D3DDevice->LightEnable(0, TRUE);//Setup the material properties for the objectsZeroMemory(&g_material, sizeof(D3DMATERIAL9));g_material.Diffuse.r = g_material.Ambient.r = 0.6f;g_material.Diffuse.g = g_material.Ambient.g = 0.6f;g_material.Diffuse.b = g_material.Ambient.b = 0.7f;g_material.Specular.r = 0.4f;g_material.Specular.g = 0.4f;g_material.Specular.b = 0.4f;g_material.Power = 8.0f;//Define camera informationD3DXVECTOR3 cameraPos(0.0f, 0.0f, -0.8f);D3DXVECTOR3 lookAtPos(0.0f, 0.0f, 0.0f);D3DXVECTOR3 upDir(0.0f, 1.0f, 0.0f);//Build view matrixD3DXMatrixLookAtLH(&g_ViewMatrix, &cameraPos, &lookAtPos, &upDir);

//Apply the view (camera)g_D3DDevice->SetTransform(D3DTS_VIEW, &g_ViewMatrix);;//Render triangle primitiveg_D3DDevice->SetStreamSource(0, g_VertexBuffer, 0, sizeof(stD3DVertex));g_D3DDevice->SetFVF(D3DFVF_VERTEX);g_D3DDevice->SetMaterial(&g_material);g_D3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 1);


I hope this isn't to hard to look at, I named things as best I could.
wicked357
wicked357
Okay I figured it out, honestly all that precode calculation crap didn't work at all, I just looked at my vectex vectors, for anyone following ill tell you how I did it,
v[0] = (0.0, 0.2, 0.0)v[1] = (0.2, -0.2, 0.0)v[2] = (-0.2, -0.2, 0.0)

by looking at that the normals for all the vertices are as follows
v[0].nor = (0, 1, 0)v[1].nor = (1, -1, 0)v[2].nor = (-1, -1, 0)

You kind see how that worked out, I got my point light shinning on my primitive, thank god. To many hours on this problem thanks to everyone who helped. Here is the final vertex settings with normals
[source land="c"]stD3DVertex objData[3];objData[0].pos = D3DXVECTOR3 (0.0f, 0.2f, 0);objData[1].pos = D3DXVECTOR3 (0.2f, -0.2f, 0);objData[2].pos = D3DXVECTOR3 (-0.2f, -0.2f, 0);objData[0].nor = D3DXVECTOR3(0, -1, 0);objData[1].nor = D3DXVECTOR3(1, -1, 0);objData[2].nor = D3DXVECTOR3(-1, -1, 0);


EDIT: I actually can change the positive and negative values for the normals and it will give different results.
Evil Steve
Evil Steve
Glad you got it all working [smile].

As a bit of a nitpick, D3DXVECTOR3(-1, -1, 0) isn't a valid normal and may give you some strange artifacts. You should normalise the vector first with D3DXVec3Normalize.

Topic Locked

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

Sign in to reply to this topic.