Skip to main content
gamedev.net
🔒 Locked

Lighting

Started by MENTAL Dec 22, 2001 at 6:07 PM 6 replies 150+ views
Original Post
MENTAL
MENTAL
I've finally got of my fat ass and am writing the "proper" version of my cel-shading article (the one that's on GD.net at the moment was an alpha version which I sent to dave for comments/suggestions and he put the damn thing up!) and I'm having a little trouble with the lighting calcuations. I've managed to work out the calculations for Positional Lighting with Vertex Normals and Positions, but I now need to somehow add the light's direction to it. Here's the code for Light Position with Vertex Position/Normal:
  
if (Lights[i].UseDirection == false && Lights[i].UsePosition == true)
{
	RotateVector (Matrix, Vertices[i].Normal, RotatedNormal);
//

	RotatedNormal.Normalize ();
//

	RotateVector (Matrix, Vertices[i].Position, RotatedPosition);
//

	LightVector.X = RotatedPosition.X - Lights[i].Position.X;
	LightVector.Y = RotatedPosition.Y - Lights[i].Position.Y;
	LightVector.Z = RotatedPosition.Z - Lights[i].Position.Z;
//

	LightVector.Normalize ();
//

	ShadeValue = RotatedNormal.DotProduct (LightVector);
//

	if (ShadeValue < 0.0f)
		ShadeValue = 0.0f;
//

	if (ShadeValue > Vertices[i].ShadeValue)
		Vertices[i].ShadeValue = ShadeValue;
}
  
Knowing my luck those formulae are wrong anyway (please tell me if they are). If you know how to get the light's direction in there I would greatly appreciate it. Thanks in advance Edited by - MENTAL on December 23, 2001 11:08:46 AM
S1CA
S1CA
As you know the code you have is for positional lighting. Also known as a point light without any attenuation.

LightVector in your code represents the direction from the vertex to the light position.

So to do directional lighting (i.e. where the light has a "direction", but no position - usually used for far away lights like the sun) change your code to:

LightVector.x = -LightDirection.x
LightVector.y = -LightDirection.y;
LightVector.z = -LightDirection.z;

[It''s -LightDirection rather than LightDirection because we want the vector from the vertex to where the light is coming from. The L.N gets the cosine of the angle between the two vectors - think of pythagoras and right angled triangles]

--
Simon O''''Connor
Creative Asylum Ltd
www.creative-asylum.com
Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site
MENTAL
MENTAL
you misunderstood me - i need positional AND directional lighting on the SAME light.

i''ve already worked out directional OR positional, but not both at the same time

thanks anyway though
S1CA
S1CA
So you''re after a spotlight effect then where the light only shines in a particular direction starting at a position...

What you need in that case is a spotlight term:

Cspot = max( -L dot Sdir, 0 ) ^ Sexp

L is the vector from the vertex to the light position.

Sdir is the direction of the spotlight.

Sexp is an exponent used to control the fall off of light from the centre of the spotlight (one of those "hacks" you often encounter in graphics programming which "looks about right").

The max() clamps Cspot to 0 if it becomes negative.

Combined with the N dot L you get:

I = Cspot * (N.L)



--
Simon O''''Connor
Creative Asylum Ltd
www.creative-asylum.com
Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site
MENTAL
MENTAL
cheers, that''s just what i needed!

i''m not using the exponential in my calculations just yet - a simple "is the light in the sphere, if so, light it" test is all i need (no one has ever said cel-shading was realistic).

well, that''s now 1 person i have in the "thanks" section
MENTAL
MENTAL
    
if (Lights[i].UseDirection == true && Lights[i].UsePosition == true)
{
RotateVector (Matrix, Vertices[i].Normal, RotatedNormal);
//

RotatedNormal.Normalize ();
//

RotateVector (Matrix, Vertices[i].Position, RotatedPosition);
//

LightVector.X = RotatedPosition.X - Lights[i].Position.X;
LightVector.Y = RotatedPosition.Y - Lights[i].Position.Y;
LightVector.Z = RotatedPosition.Z - Lights[i].Position.Z;
//

LightVector.Normalize ();
//

ShadeValue = MAX (LightVector.DotProduct (Lights[i].Direction), 0.0f) * RotatedNormal.DotProduct (LightVector);
//

if (ShadeValue > Vertices[i].ShadeValue)
Vertices[i].ShadeValue = ShadeValue;
}


did i get it right (i added the // to break the code up a little - the source tags dont allow blank lines for some reason)

Edited by - MENTAL on December 23, 2001 11:07:24 AM
S1CA
S1CA
quote:

did i get it right



almost...

a)
LightVector = RotatedPosition - Lights.Position;
gets a vector which points FROM the light position TO the vertex being lit.

LV == V <--- LP



b)
The light direction vector points FROM the light position in the direction of the spotlight. If you imagine the spotlight as a cone, this is the central axis of the cone. The apex of the cone is the position of the light.

LD == <--- LP



c)
The normal vector points OUT of the object or vertex.

NV == V --->



The dot product gets us the cosine of the angle between two vectors so to draw them on paper the start point of the two vectors should join up and form two sides of a triangle.


a b
\ /
\ /
\/
p

a & b are vectors and p is the point where they both start. The dot product gets the cosine of the angle between a and b.


For the light direction and light to vertex vector this makes sense since they both meet at the point in the world which represents the position of the light. The Cspot term gets a value which increases when the the vertex is near to the centre of the light cone and decreases moving away from the centre.

The second part of the lighting in your code, the N.L bit is what's a tad wrong since the start of both the vectors need to meet at the same point. What you need is that both N and L both point OUT of the vertex or both point IN to the vertex. All you have to do is add a '-' sign to the L vector.

So the line where your ShadeValue is can be changed to:

float Cspot = MAX( LightVector.DotProduct(Lights[i].Direction), 0 );
// NOTE: -LightVector
ShadeValue = RotatedNormal.DotProduct( -LightVector );



* I've not explained that as well as I'd have liked (a million things going on in my head at the moment - Xmas etc), but you should get the idea from that.
The best thing you can do is plot two points on a piece of paper, one for the light position and one for the vertex position then draw the vectors on with their direction arrows. Mark the place where each dot product takes place with an angle.


--
Simon O''Connor
Creative Asylum Ltd
www.creative-asylum.com

Edited by - s1ca on December 23, 2001 6:07:12 PM
Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site
MENTAL
MENTAL
thanks a lot - i did understand what you said, i just forgot to inverse the lightvector for the dot product.

  
LightVector.Normalize ();

InvLightVector.X = - LightVector.X;
InvLightVector.Y = - LightVector.Y;
InvLightVector.Z = - LightVector.Z;

ShadeValue = MAX (LightVector.DotProduct (Lights[i].Direction), 0.0f) * RotatedNormal.DotProduct (InvLightVector);


that should do it. i'm gonna have fun optimising this one

now it's time to get the good ol' multitexturing to work... eek!

Edited by - MENTAL on December 23, 2001 6:26:49 PM

Topic Locked

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

Sign in to reply to this topic.