#### Archived

This topic is now archived and is closed to further replies.

# Lighting Spotlights

## Recommended Posts

Hello, I''m trying to make a spotlight show up on a simple triangle on the screen (black in a blue background). I''m trying to make a white spotlight show on the triangle, not light the whole thing. Here is the triangle: pVertices[0].position = D3DXVECTOR3 (-1.0f, -1.0f, 0.0f); pVertices[0].normal = D3DXVECTOR3 (-1.0f, 0.0f, 0.0f); pVertices[1].position = D3DXVECTOR3 (1.0f, -1.0f, 0.0f); pVertices[1].normal = D3DXVECTOR3 (1.0f, 0.0f, 0.0f); pVertices[2].position = D3DXVECTOR3 (0.0f, 1.0f, 0.0f); pVertices[2].normal = D3DXVECTOR3 (0.0f, 0.0f, 0.0f); Here''s the struct for it: struct SpotlightTriangle { D3DXVECTOR3 position; D3DXVECTOR3 normal; }; I tried going though the Direct3D tutorials and it didn''t explain it like I wanted. =/ I''m not entirely sure the normals are right either. Any small little code to just light the triangle with a SPOTLIGHT light would be appriciated. Thanks alot

##### Share on other sites
You can''t get a spot light on a polygon. D3D lights vertices only, not the individual pixels on the polygon. You can get the spotlight''s brightness at each of the three points, but that''s it.

And yes, your normals are wrong. Very wrong. I''m not going to get into the details...

##### Share on other sites
quote:
Original post by Namethatnobodyelsetook
You can''t get a spot light on a polygon. D3D lights vertices only, not the individual pixels on the polygon. You can get the spotlight''s brightness at each of the three points, but that''s it.

And yes, your normals are wrong. Very wrong. I''m not going to get into the details...

Where can I find tutorial about normals ?
Could you explain ?

##### Share on other sites
Here''s how you calculate the normal:
vector a = vertices[2] - vertices[0];
vector b = vertices[1] - vertices[0];
normal = crossproduct(a, b);

Proceeding on a brutal rampage is the obvious choice.

##### Share on other sites
Ok, here goes the basics.Normals are used in 3D solely for lighting calculations.  Theyare always a unit vector, ie:  They all have a length of 1.0For example (1,0,0), (0,1,0), (0.7071, 0, 0.7071) are allvectors of length 1... sqrt(x*x+y*y+z*z) = 1.0When DirectX renders a polygon, the normal at each vertex isused to calculate lighting.  The 3 light values are theninterpolated across the polygon as each pixel is drawn.Normals point outward from the object.  Ignoring the front andback sides, the normals on the top, bottom, left and right wouldbe as follows: +-X    |     (0,1,0) (0,1,0)         Y        |       |(-1,0,0)--+-------+--(1,0,0)          |       |          |       |          |       |(-1,0,0)--+-------+--(1,0,0)          |       |       (0,-1,0)(0,-1,0)    The front face would be pointing towards you, so (0,0,-1), andthe back face would be pointing away from you, so (0,0,1).  Notethat in order to get a cube lit correctly, you'll need 3 copiesof each corner vertex to hold the correct normals.  For examplein the top, right, back corner, you'll need one with a normal tolight the top correctly, one to light the right side correctly,and one to light the back side correctly.  These vertices willall have the same position, but different normals.Now, most meshes aren't as hard edged as cubes, and as such youwon't have to duplicate vertices to get new normals.  You'llwant the normals shared between faces on a curve.  For example,take this arc.  Imagine it's a top down view of a wall, so youcan't see the polygons making it up... but you can see thenormals, as they poke outwards.  You want the object to appearlike a smooth curve, even though it's just a bunch of triangles. +-X            |             (0,0,1) Z                |  (-.5, 0, .87) __+__ (.5, 0, .87)            +-~~     ~~-+           /             -          /               -         +                 +     (-.7,0,.7)            (.7,0,.7)When DX draws the polygons with normals like these, the lightingvalues at each vertex will be calculated as though it was a flatsurface pointing in the direction of the normal.  Then theselighting values are interpolated across the polygon giving it asmooth light change, rather than an abrupt change at eachpolygon.[/CODE][edited by - Namethatnobodyelsetook on January 21, 2003 10:09:12 PM]

##### Share on other sites
So...

D3DXVec3Normalize() just basically scales it down to 1 unit?

##### Share on other sites
quote:
Original post by Anonymous Poster
So...

D3DXVec3Normalize() just basically scales it down to 1 unit?

yes

##### Share on other sites
To add one more thing: if you really want a spotlight on an individual triangle, you must tesselate the triangle. Tesselation means that you break one big triangle into many little triangles. In this way, D3D''s per-vertex lighting will show the spotlight correctly, as it will calculate the lighting for many different points on the large triangle.

Firebird Entertainment

##### Share on other sites
a good way to immitate spotlights over a lot of geometry is a projected texture, it will show on everything that you render with the projected texture stage on (provided its within the projection matrix of the texture) and it can be pretty fast if you can multitexture it well.

##### Share on other sites
Ok I have a question. I''ve got a tile based terrain where each tile is like 2 triangles with a texture put on top of it. I use this as my texture setup.

d3dDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_SELECTARG1);
d3dDevice->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE);
d3dDevice->SetTextureStageState(0,D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
d3dDevice->SetTextureStageState(0,D3DTSS_MINFILTER, D3DTEXF_LINEAR);

So now when I enable lighting, even ambient light doesn''t show up. I''ve got colored vertices underneath even though they don''t show and I''ve got normals. I''m enabling my lighting like this:

//setup lighting
d3dDevice->SetRenderState(D3DRS_LIGHTING,TRUE);
d3dDevice->SetRenderState(D3DRS_COLORVERTEX, TRUE);
d3dDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_COLORVALUE(1.0, 1.0, 0.0, 0.0));

// Set up a material
D3DMATERIAL8 mtrl;
ZeroMemory(&mtrl, sizeof(D3DMATERIAL8));
mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f;
mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f;
mtrl.Diffuse.b = mtrl.Ambient.b = 0.0f;
mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f;
d3dDevice->SetMaterial(&mtrl);

So my question is, why isn''t the lighting showing up? Is it because of the way I''m using the textures? I''ve loaded a .x file in there, too and the lighting seems to work on it. Also, if I comment out the texture code I posted above, the lighting seems to work. Any help?

##### Share on other sites
AP, the output of the lighting stage is diffuse and specular, fed into the texture stages as D3DTA_DIFFUSE and D3DTA_SPECULAR. You''re not using either. Try this:

d3dDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_MODULATE);
d3dDevice->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_DIFFUSE);
d3dDevice->SetTextureStageState(0,D3DTSS_COLORARG2, D3DTA_TEXTURE);

##### Share on other sites
Also, by default the lighting stage pulls material diffuse from the vertices and material ambient from the current material. You might want them both to come from the vertex colors, so:

d3dDevice->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_COLOR1);

##### Share on other sites
quote:

Here''s how you calculate the normal:
vector a = vertices[2] - vertices[0];
vector b = vertices[1] - vertices[0];
normal = crossproduct(a, b);

Doesn''t that method only find the surface normal? How do you know how many normals a vertex needs? I have a tiled terrain with hills, etc. but am calculating my normals like you posted and it''s not working properly.

Donavon Keithley - thanks for your help. That explained my problem.

##### Share on other sites
Ok, I found a tutorial that explained that finding the vertex normal is as easy as normalising the sum of the face vertices surrounding it.

I haven''t implemented this yet but I''m afraid I''m going to have a problem because I scale my terrain on the up axis before rendering. Will this cause a problem? Do you know what I can do to get around it?

##### Share on other sites
so I''m calculating my vertex normals like this:

  for(int j=0;j<=mapDepth;j++)	{for(int i=0;i<=mapWidth;i++){	D3DXVECTOR3 sum;			//get left face normalif(i > 0)  sum+=myVertices[j*(mapWidth+1)+i-1].normal;//get right face normalif(i < mapWidth)  sum+=myVertices[j*(mapWidth+1)+i+1].normal;//get top face normalif(j < mapDepth)  sum+=myVertices[(j+1)*(mapWidth+1)+i].normal;//get bottom face normalif(j > 0)  sum+=myVertices[(j-1)*(mapWidth+1)+i].normal;D3DXVec3Normalize((D3DXVECTOR3*)&myVertices[j*(mapWidth+1)+i].normal, &sum);//copy vertex into vertex buffervertices[j*(mapWidth+1)+i] = myVertices[j*(mapWidth+1)+i];}}

And the original normal is taken like this:

  vertex[0] = vertices[0].position;vertex[1] = vertices[1].position;vertex[2] = vertices[2].position;CalculateNormal(vertex, &vertices[0].normal);D3DXVec3Normalize((D3DXVECTOR3*)&vertices[0].normal, vertex);

where my CalculateNormal function is this:

  void CalculateNormal(D3DVECTOR v[3], D3DVECTOR *normal){	D3DVECTOR a, b;	static const int x = 0;	static const int y = 1;	static const int z = 2;	a.x = v[0].x - v[1].x;	a.y = v[0].y - v[1].y;	a.z = v[0].z - v[1].z;	b.x = v[1].x - v[2].x;	b.y = v[1].y - v[2].y;	b.z = v[1].z - v[2].z;	//find cross product to get the normal	normal->x = (a.y*b.z) - (a.z*b.y);	normal->y = (a.z*b.x) - (a.x*b.z);	normal->z = (a.x*b.y) - (a.y*b.x);}

Now I''m scaling my terrain after I caluclate normals so that may be my main problem but whats happening is, that depending on where the camera is looking, its like the light goes on and off. Sometimes its bright, sometimes its dark. Can anyone help? Or at least tell me if I''m calculating the normals correctly?

• ### Forum Statistics

• Total Topics
628401
• Total Posts
2982464

• 9
• 10
• 9
• 19
• 24