Advertisement

[tutorial 10] trouble with normals

Started by July 16, 2004 11:34 AM
9 comments, last by vincoof 20 years, 4 months ago
When the tutorial loads the triangles, it sets *every* normal to (0,0,1) so this causing the lighting to change based on your rotation. If you spin 180 degrees, everything goes black. How do I properly set the normals?
--monkey
You can either load normals from the model, if the file format contains normals, or you can compute normals yourself. In this case the easiest way is to compute cross product between two edges of the triangle. Start with this. Later you can move on better algorithms (that smoothen normals when vertices are shared over many polygons).
Advertisement
There must be something else that is wrong, because it works fine for me. Are you using the most recent drivers for you video card?
"None of us learn in a vacuum; we all stand on the shoulders of giants such as Wirth and Knuth and thousands of others. Lend your shoulders to building the future!" - Michael Abrash[JavaGaming.org][The Java Tutorial][Slick][LWJGL][LWJGL Tutorials for NeHe][LWJGL Wiki][jMonkey Engine]
Quote: Original post by CaptainJester
There must be something else that is wrong, because it works fine for me. Are you using the most recent drivers for you video card?
Yes I am. But I don't see why it would work with incorrect normals. From what I understand a surface's normal is perpendicular the surface, and it's used for lighting. So if the normal was pointing the wrong way, the walls would be dark, since it's the wrong side of the face to light up.
Quote: Original post by vincoof
You can either load normals from the model, if the file format contains normals, or you can compute normals yourself. In this case the easiest way is to compute cross product between two edges of the triangle. Start with this. Later you can move on better algorithms (that smoothen normals when vertices are shared over many polygons).
Doesn't an edge consist of 2 vertices? Then wouldn't a triangle have 3 edges? Do you have any articles/tutorials/examples that would explain how to compute the cross product of the 2 edges of the traingles?

Thanks
--monkey


Those normals are pointing correctly! The camera is always pointing towards the - negative z axis thus the normals must be pointing right back towards it. ie towards the positive +z axis. Remember, thats 1 for the z value of the normal. There are no curved surfaces in that example.
To compute the crossproduct of two sides of a triangle, you do the following:

If you have the three vertices, let's call them P1,P2,P3.
Each vertex, of course, has a x, y and z component.

You work with the cross product of P2-P1 with P3-P1. The only problem is you might have to check the order in which to compute it, because the direction might go opposite to the direction you actually want.
Advertisement
Quote: Original post by ninmonkey
Doesn't an edge consist of 2 vertices?

Yes of course.

Quote: Original post by ninmonkey
Then wouldn't a triangle have 3 edges?

Yes, but the normal is computed as the cross product of two edges. It has no meaning to compute the cross products over three edges.
Note that you can select any pair of edges out of the three available : the result of the cross product will be the same.
Well, almost. In fact, the order of the edges is important, as Alray pointed out. That is, cross_product(A,B) is not the same as cross_product(B,A). Whatsoever, as a first try you may not care about that and use two-sided lighting. Enable it by calling :
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);

Quote: Original post by ninmonkey
Do you have any articles/tutorials/examples that would explain how to compute the cross product of the 2 edges of the traingles?

You don't mean that you don't know of to compute a cross product, do you ?
Quote: You work with the cross product of P2-P1 with P3-P1. The only problem is you might have to check the order in which to compute it, because the direction might go opposite to the direction you actually want.
and
Quote: Well, almost. In fact, the order of the edges is important, as Alray pointed out. That is, cross_product(A,B) is not the same as cross_product(B,A). Whatsoever, as a first try you may not care about that and use two-sided lighting. Enable it by calling :
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
This appears to work with 2 side lighting on. It doesn't work correct on some triangles with it disabled.
    //calc normal of triangle using cross product of vectors v1, v2    //v1 = (p1.x - p2.x, p1.y - p2.y, p1.z - p2.z)    //v2 = (p1.x - p3.x, p1.y - p3.y, p1.z - p3.z)    Vector v1, v2, vNormal;    v1.x = sector1.triangle.vertex[0].x - sector1.triangle.vertex[1].x;    v1.y = sector1.triangle.vertex[0].y - sector1.triangle.vertex[1].y;    v1.z = sector1.triangle.vertex[0].z - sector1.triangle.vertex[1].z;            v2.x = sector1.triangle.vertex[0].x - sector1.triangle.vertex[2].x;    v2.y = sector1.triangle.vertex[0].y - sector1.triangle.vertex[2].y;    v2.z = sector1.triangle.vertex[0].z - sector1.triangle.vertex[2].z;            vNormal.CrossProduct(v1, v2);    vNormal.Normalize();     glNormal3f((GLfloat)vNormal.x, (GLfloat)vNormal.y, (GLfloat)vNormal.z);


1) Is my math correct assuming two sided lighting is on?

2) If two sided lighting is off, would the incorrect normals be fixed If the components were multiplied by -1? (I think they are "reversed" since the order is not being checked by me)

3) How do I check which one should be first? Compare the components of v1 against v2 for what?

4) The man page says glNormal() doesn't require a unit vector, but do you think it's a good idea to normalize it anyway?

5) If I wanted to find the normal of an n-sided polygon, would the same math work as long as I use 2 edges that share one vertex?

Thanks!
--monkey
Quote: Original post by ninmonkey
1) Is my math correct assuming two sided lighting is on?

Yes it is.

Quote: Original post by ninmonkey
2) If two sided lighting is off, would the incorrect normals be fixed If the components were multiplied by -1? (I think they are "reversed" since the order is not being checked by me)

No it would not be fixed. The problems comes from the winding order of the faces.
If the artist that created the model OR the software that exported the model in this file format does not respect winding order, you're doomed to use two-sided lighting.

Quote: Original post by ninmonkey
3) How do I check which one should be first? Compare the components of v1 against v2 for what?

In most cases, you can't check anything suitable. Algorithms that do that are very complex, they do not fit toall cases, and they're out of the scope of this tutorial. The only solution is : work with artists that order faces correctly, and use exporters that handle it correctly too.

Quote: Original post by ninmonkey
4) The man page says glNormal() doesn't require a unit vector, but do you think it's a good idea to normalize it anyway?

If your model is going to be scaled, then don't bother normalizing it and stick to enabling GL_NORMALIZE. If your model is never scaled (or scaled with uniform scaling) it's better to normalize the normal so that you save processing time on the server side. For uniform scaling, use glEnable(GL_RESCALE_NORMAL);

Quote: Original post by ninmonkey
5) If I wanted to find the normal of an n-sided polygon, would the same math work as long as I use 2 edges that share one vertex?

Yes, considering the face is coplanar (well, otherwise that would not be a "face" then). In fact, you can use any pair of edges you want, you don't even need them to share a vertex. The only thing you have to be sure is that the edges used in cross-product are not colinear, otherwise the result of the cross-product is a null vector.
edit: I see vinc slid in there and rounded out the final four questions before me. I'll leave these just for posterity and extra support, even though they're less complete than his in some ways. :)

2) You have to ensure that the normals point in a direction consistent with their front-face direction, determined by their winding order and your cull-face settings.

3) You are sending the vertices in a given winding order, most likely. If those vertices are, respectively: v0, v1, v2; then I believe the proper cross is (v0-v1) x (v0-v2). This should result in a normal facing in the "front" face direction. I could be wrong about this, though.

4) I do. Your normals only get normalized if GL_NORMALIZE is enabled, and that can incur unnecessary overhead if *some* of your normals are unity length to begin with. On the other hand, the normalization might be optimized on the graphics hardware and might be ultimately faster than doing it manually, especially if you use a dumb algorithm on a dumb compiler (i.e., resulting in three actual FDIVs for a normalize operation).

5) If nothing else I've said was incorrect, yes, as long as all the vertices are co-planar.

Later,
ZE.

[twitter]warrenm[/twitter]

This topic is closed to new replies.

Advertisement