Advertisement

Calculating Normals, Dot product etc

Started by March 15, 2001 05:36 PM
14 comments, last by Clouds3000 23 years, 8 months ago
I, being a beginner am trying to get to grips with different techniques etc when making Games. So far, my little program loads from a .txt file and in this file you can specify the vertices for loading the quads, the texture to be used on the quads and the normal for each quad so I can enable lighting. BUT I its abit much to have to write in normals for each quad and I presume that you can create equations etc to calculate these from the vertices. I seen Nates normals tutorial but it said that you needed to know about dot product and cross product to understand it and I was wondering what these both are, what else they are used for and where can I find a tutorial on them so I can generate my own normals. Thanks guys
Well if the mr-gamemaker.com site was still up like it used to be i would tell you to go there but since its down, only the message board is up i wont. The Dot and Cross Products are very important in the world of 3d graphics. The Cross product returns a vector, and this vector is perpendicular to the plane you created it from. Which is the normal. So to calculate the Cross Product, you need 2 vectors. Lets say you have a polygon with these three sets of points, (5,3,2) & (1,2,4) & (5,-3, 5). Ok to find the normal of this polygon, you need to create 2 vectors. Let P1 = (5,3,2), P2 = (1,2,4), P3 = (5,-3, 5). So your two vectors V1 and V2 are as follows. V1 = P2 - P1, V2 = P3 - P1. Now to find the normal you take the cross product of V1 and V2. So Let CP = the cross product between V1 and V2.

CP.x = (V1.y*V2.z)-(V1.z*V2.y)
CP.y = (V1.x*V2.z)-(V1.z*V2.x)
CP.z = (V1.x*V2.y)-(V1.y*V2.x)

Ok and if i did my math correctly you now have the normal of that polygon.

Now the Dot Product is a scalar (sp?) value. Its the angle between the two vectors you perform the dot product to. The angle is the cosine of the two vectors to be exact. The Dot product has many uses, one use is for determining the intensity of light on a vertex. Ok lets use the same 3 points from the cross product example in this example. The dot product is calculated as follows:

DP = (V1.x*V2.x)+(V1.y*V2.y)+(V1.z*V2.z)

Much simpler to calculate eh? Well i hope what all i did was helpfull to you. Notice i didnt use the actuall numbers in the calculation of the dot and cross product, so i hope you understand what i did.

-SirKnight
Advertisement
Basically, it''s like this:

The dot product takes two vector arguments and returns a scalar(single number). This number is the length of the projection of one vector onto another. It''s not very important for your application. You calculate it by doing a component wise multiply, then adding.
So (1,2,3) Dot (4,5,6) = 1*4+2*5+3*6=32

Cross product takes two vectors and returns a vector perpendicular to both. This can be used to generate normals out of polygon information. How, you ask? Simply take your two input vectors as 2 of the polygon edges, then their cross product will be the normal, as it is perpendicular to both. It is important to observe winding - ie, if you define your points counterclockwise, take the cross product counter-clockwise as well. To compute the cross product, you have to make a determinant:
Cross of (x,y,z) with (a,b,c)
| i j k |
| x y z | = i(y*c-b*z) -j(x*c-a*z) +k(x*b-a*y)
| a b c |
or in vector form, (y*c-b*z,a*z-x*c,x*b-a*y)
Let''s say you get a triangle, with points P1,P2, and P3.
The right hand rule determines how the cross product works. The right hand rule works like this:
Take your right hand, and point the fingers in the direction of the first vector. Stick your thumb out perpendicular to your fingers(doesn''t matter where for now). Then align your hand so that the palm points in the direction of the second vector, so you should be able to curl your fingers in to sweep out the angle between the two vectors. The thumb points in the direction of the result of the cross product.

So for P1,P2, and P3(defined in that order, and assuming counter-clockwise winding), we want to take the cross product of (P2-P3) with (P2-P1) to find the normal for the triangle.

Additionally, you want to normalize your normal. Otherwise, lighting calculations get messed up. A normalized vector is simply one whose magnitude is 1, so sqrt(x^2+y^2+z^2) better equal 1.
To normalize a vector simply divide all components by the magnitude of the vector. You should only do this once for static geometry, as it is a very time consuming operation.

As for the dot product, you can use that to figure out which way a vector is pointing. Let''s say you have a viewing vector, (x,y,z). Now you can figure out if a polygon is facing toward or away from this viewing vector by taking the dot product. If the dot product of two vectors is positive, they are facing the same direction. If it is negative, they are going in opposite directions.
So say your polygon normal is (a,b,c).
If (a*x+b*y+c*z)<0, then the vectors are facing opposite directions and the polygon is facing towards the viewing vector.

-sjelkjd

If you're intrested in learning a bit more about the dot and cross products then take a look for them in a couple of first year university physics books. They should have a couple of fancy diagrams that would really help. Plus it would give you some idea how it applies to other stuff like kinematics, which would be good to know anyways.

Or go to Google and search for "cross product tutorial". You should get a bunch of hits that can explain it.

-------
Andrew

Edited by - acraig on March 15, 2001 7:53:07 PM
just as a followup to SirKnight''s post, the Dot Product is only the angle between two vectors if they are normalized vectors. The actual formula is this:
u dot v = |u|*|v|*cos (theta)
The nice thing about the dot product is you only have to check signs, though. Cosine is positive for -pi/2<theta
I setup a function that calculated my normals, I used the technique from SirKnight and normalised them like sjelkjd said. Now all my polygons are drawn counter-clockwise starting with the top left vertex so I can enable GL_CULL. Now, after coding it into my program and testing it it seems to almost work. My walls are lit by the diffuse lighting but my floor and ceiling in my room are not, they are only lit when ambient lighting is enabled and they are calculated in the same way as the walls???
And if by chance I acidentally were to put the vertices of the ceiling and floor in the wrong order (not counter-clockwise) they wouldn''t show up when GL_CULL was enabled would they? Could this be the prob, its hard to draw a polygon count-clockwise when its not facing you.

Something that isn''t quite right is the fact that the polygons loaded from my file are quads, and I used SirKnight''s equation to calculate the normals which refers to triangles, I presumed that it would work because it uses the 1st 3 vertices of the quad to calculate the normal, and since if the first 3 vertices of the quad were to make a triangle it would be facing the same direction anyways, so it should still work should it not? And if it shouldn''t work, why are my walls lit by diffuse light?

Sorry if this all sounds like a load of rubbish, but cheers for the help.




Advertisement
sjelkjd, thanks for posting your follow up. I am so used to making my vectors normals before doing the dot product that i forgot you calculate it a little differently if they are not normalized. Oops. Also, even though my example used a triangle, the calculation of the cross product is still the same if you are using a quad. Because as you probably know, a quad is made up of two triangles. And both of those triangles lay on the same plane, so the normal to the first triangle is the same as the second triangle. But if one vertex of one of the triangles has a diff z value than the rest, you would have to then take the cross product of both triangles. But if one z value was diff then i dont think it would be called a quad anymore. But i could be wrong.

-SirKnight

Edited by - SirKnight on March 17, 2001 2:04:37 PM
Ok, this is driving me crazy. Could some of you guys please tell me if what I am doing is correct.

I have stored all my vertex coorinates in an array from a data file.

I take the coordinates (the float numbers used when using glVertex3f(etc);
I take the x coordinate, the y and z of each of 3 vertices and enter them into the equation, then use the new variables in
glNormal(x,y,z);
As I said above it seems to work on the walls, but not the floor and ceiling. The wierd thing is that if I Disable GL_CULL_FACE and re-arrange the floor/ceiling coordinates they light up with diffuse lighting, but they won''t appear when GL_CULL_FACE is enabled. Anyone any ideas?

Thanks
this is just a shot in the dark, but wouldn''t the normals for your floors simply be 0.0f, 1.0f, 0.0f and for your ceilings be 0.0f, -1.0f, 0.0f ??? assuming they are flat.

Scott

"If you try and don''t succeed, destroy all evidence that you tried."
Yea, but I can''t individually define normals to polygons because all the polygons (walls and floors/ceilings) are loaded from the data file in a ''for loop'', and everything in this loop has normals precalculated from the equations.

This topic is closed to new replies.

Advertisement