Indexed VA for Normals

Hello,

I am having a bit of trouble with glDrawElements(). I know that glArrayElement is equivalent to both glNormal() and glVertex() calls, so it makes sense to me that glDrawElements() would also. Basically I have made an array of all the unique verts in my scene, indexed them in the order I want for a mesh triangle strips, and now I am trying to get my normal array working correctly. I am calculating surface normals for each triangle in the scene. I have read that when using vertex arrays you have to specify vertex normals. Can someone please explain this technique for me? Is there a way to use vertex arrays to specify surface normals?

Old GLman

If you are going to use DrawElements to draw your vertices with normal, you’ll need to have a normal for each vertex. What it sounds like you want to do is a flat shading model, where you use the face normal for each vertex. In this case, you will have to duplicate vertices.

Simple example: You have 2 triangles A and B. Those 2 triangles share 2 vertices (Say that vertex A2 and A3 are the same as B1 and B2). If you were to average the normals for those shared vertices you would do arrays somewhat like this.

normalArray = {normA1, normA2, normA3, normB3};
vertArray = {A1, A2, A3, B3};

indexArray = {0,1,2,1,2,3};

Now… if you want to use face normals, you have to duplicate vertices so you’d have something like so…

normalArray = {normA1, normA2, normA3, normB1, normB2, normB3};
vertArray = {A1, A2, A3, B1, B2, B3};

indexArray = {0,1,2,3,4,5};

Basically think about it like so… a vertex is more than just it’s position. It also includes it’s texcoords, color, normal, etc. If any of those properties change, you have a different vertex and it needs to be represented as such in a vertex array, even if it shares the same position.

Deiussum,

Thank you for your help. I am pretty sure I will be able to figure it out now. Since I do not want to store duplicate normals, I will go with the vertex normal method. Basically what I am doing is setting up a decent sized mesh out of triangle strips in the xz-plane. On the mesh I am testing out different effects with lighting, so speed and efficiency is pretty important for me. My only two questions now are: Is there a notcible difference between lighting with vertex normals rather than face normals? And even though I am sharing vertices for my mesh, I only have to specify one normal per vertex right? Thanks once again.

Old GLman

  1. Per vertex shading will give you a colour gradient from one vertex to the next as each will end up with a different colour. This way you wont notice any sharp edges in your image. However if the average normal is close to the surface normal you shouldn’t see too much of a difference. I think if you set glShadeModel(GL_FLAT) the result would be the same as specifying surface normals. Perhaps someone else can confirm.

  2. Yes you only have to specify one normal per vertex

Furrage,

Thanks for your help. So vertex normals are really the average of the surrounding surface normals. So it is entirely possible that the average vertex normal could be close to the surface normal. Just to clarify, vertex normals are really just approximations? Is it mathematically possible to find a vertex normal orthogonal to the vertex, and skip having to find the average? I have done a bit of digging and it looks like implementing vertex normal calculations will be easy, but I am just curious to the underlying details. Thanks again for your help.

Old GLman

[This message has been edited by Old GLman (edited 04-17-2002).]

Vertex normals are usually an average of all the face normals that share that vertex. You use a normal per vertex if you want smooth shading. Smooth shading generally gives you better results. The only exception might be if you are rendering a model that SHOULD have sharp edges. Like, for instance, a cube.

Using glShadeModel(GL_FLAT) isn’t necesarily the same as using the face normal for all the vertices. Using the GL_FLAT mode, one of the normals specified is used for the entire face, it doesn’t actually find the face normal for you and use that. (Which vertex is used depends on the primitive type… for triangles it uses the normal for vertex 1, for triangle strips and fans it uses the vertex i + 2). So basically if you average all your vertex normals to the faces, then try to set GL_FLAT mode, it’s going to use the first averaged normal for a triangle, not what the normal truly would be if you set all the vertices to use the face normal.

Thanks for your help guys. I have it working now, and I am happy with the results.

Old GLman