Archived

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

EnigmaX

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 this post


Link to post
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 this post


Link to post
Share on other sites
Guest Anonymous Poster
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 this post


Link to post
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);

Search google for vector math tutorials if you want to learn more.

Proceeding on a brutal rampage is the obvious choice.

Share this post


Link to post
Share on other sites

Ok, here goes the basics.

Normals are used in 3D solely for lighting calculations. They
are always a unit vector, ie: They all have a length of 1.0

For example (1,0,0), (0,1,0), (0.7071, 0, 0.7071) are all
vectors of length 1... sqrt(x*x+y*y+z*z) = 1.0

When DirectX renders a polygon, the normal at each vertex is
used to calculate lighting. The 3 light values are then
interpolated across the polygon as each pixel is drawn.

Normals point outward from the object. Ignoring the front and
back sides, the normals on the top, bottom, left and right would
be 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), and
the back face would be pointing away from you, so (0,0,1). Note
that in order to get a cube lit correctly, you'll need 3 copies
of each corner vertex to hold the correct normals. For example
in the top, right, back corner, you'll need one with a normal to
light the top correctly, one to light the right side correctly,
and one to light the back side correctly. These vertices will
all have the same position, but different normals.

Now, most meshes aren't as hard edged as cubes, and as such you
won't have to duplicate vertices to get new normals. You'll
want the normals shared between faces on a curve. For example,
take this arc. Imagine it's a top down view of a wall, so you
can't see the polygons making it up... but you can see the
normals, as they poke outwards. You want the object to appear
like 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 lighting
values at each vertex will be calculated as though it was a flat
surface pointing in the direction of the normal. Then these
lighting values are interpolated across the polygon giving it a
smooth light change, rather than an abrupt change at each
polygon.
[/CODE]


[edited by - Namethatnobodyelsetook on January 21, 2003 10:09:12 PM]

Share this post


Link to post
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 this post


Link to post
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 this post


Link to post
Share on other sites
Guest Anonymous Poster
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
Share on other sites
Guest Anonymous Poster
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 this post


Link to post
Share on other sites
Guest Anonymous Poster
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 this post


Link to post
Share on other sites
Guest Anonymous Poster
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 normal

if(i > 0)
sum+=myVertices[j*(mapWidth+1)+i-1].normal;
//get right face normal

if(i < mapWidth)
sum+=myVertices[j*(mapWidth+1)+i+1].normal;
//get top face normal

if(j < mapDepth)
sum+=myVertices[(j+1)*(mapWidth+1)+i].normal;
//get bottom face normal

if(j > 0)
sum+=myVertices[(j-1)*(mapWidth+1)+i].normal;

D3DXVec3Normalize((D3DXVECTOR3*)&myVertices[j*(mapWidth+1)+i].normal, &sum);

//copy vertex into vertex buffer

vertices[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?

Share this post


Link to post
Share on other sites