Relationship between Normal list and FaceList in glDrawElement() ?

Recently I am trying to improve my existing 3D engine, so I have decided to change from immediate mode to Vertex Array. But I am facing some problem with how to assign the normal to the correct indice of the mesh. I use google to search for the answer but was not able to get a completed tutorial on it, they just show you the spec of glDrawElements or the manual of using it but without an effective example.

Below is a cube with 12 vertices, 6 face with 6 normal for each face.
Vertices
8
0 0.026 0
10 0.026 0
10 10.026 0
0 10.026 0
0 0.026 -2
10 0.026 -2
10 10.026 -2
0 10.026 -2

Face // 1 base index.
6
2 6 5 1
3 7 6 2
4 8 7 3
1 5 8 4
4 1 2 3
8 5 6 7

Normal
6
0 1 0
-1 0 0
0 -1 0
1 0 0
0 0 1
0 0 -1

The snippet code for rendering this cube is as follow.

 
		internal void RenderVertexArray()
		{
			//  Collect Element Indice

			// 6 face 
			int FaceNum=FaceList.Count;
			ArrayIndex=null;
			ArrayIndex = new int[FaceNum*4];
			 count=0;
			int norCount=0;
			for(i=0;i<FaceNum;i++)
			{
				Face3d pObj=FaceList[i] as Face3d;	
				ArrayIndex[count++]=pObj.Index[0];
				ArrayIndex[count++]=pObj.Index[1];
				ArrayIndex[count++]=pObj.Index[2];
				ArrayIndex[count++]=pObj.Index[3];
			}
		pNorList=null;
			int numVertex=4;
			int xyz=3;
			// Each normal with 3 component x,y,z and each face
			// have 4 vertices so sum up to be 72.

			pNorList=new double[bilFace*numVertex*xyz];
			// Collect Normal 
		   	int c=0;
		// Collect Normal 
		int c=0;
			for(i=0;i<FaceNum;i++)
			{
				Face3d pFace=FaceList[i] as Face3d;
				Point3D vert=pFace.GetNormal();
				for(j=0;j<pFace.Index.Length;j++)
				{
					pNorList[c++]=vert.X; 
					pNorList[c++]=vert.Y; 
					pNorList[c++]=vert.Z; 
				}
			}
		Point3D testtem=new Point3D(0,0,0);
			int test=Marshal.SizeOf(testtem);
			Gl.glEnableClientState(Gl.GL_NORMAL_ARRAY);
			Gl.glEnableClientState(Gl.GL_VERTEX_ARRAY);
			Gl.glVertexPointer(3, Gl.GL_DOUBLE, test,ref VertexList[0].x);
			Gl.glNormalPointer(Gl.GL_DOUBLE,0,pNorList);
			Gl.glDrawElements(Gl.GL_QUADS, ArrayIndex.Length, Gl.GL_UNSIGNED_INT, mesh.ArrayIndex);
			Gl.glDisableClientState(Gl.GL_VERTEX_ARRAY);
			Gl.glDisableClientState(Gl.GL_NORMAL_ARRAY);				
}

I am able to display the cube in wireframe mode, but when I render it in shading mode the cube doens’t looks what it suppose to be( the normal direction is wrong). Can anyone point out where I am wrong. Thanks in advance.

It seems to me face indices and normals are messed up.

If the rectangular prism is solid from outside view, then the indices and normals should look like this;

Face // 1 base index.
6
2 1 5 6
3 2 6 7
4 3 7 8
1 5 8 4 // not changed
4 1 2 3 // not changed
8 7 6 5

Normal
6
0 -1 0
1 0 0
0 1 0
-1 0 0
0 0 1 // not changed
0 0 -1 // not changed

Originally posted by songho:
[b] It seems to me face indices and normals are messed up.

If the rectangular prism is solid from outside view, then the indices and normals should look like this;

Face // 1 base index.
6
2 1 5 6
3 2 6 7
4 3 7 8
1 5 8 4 // not changed
4 1 2 3 // not changed
8 7 6 5

Normal
6
0 -1 0
1 0 0
0 1 0
-1 0 0
0 0 1 // not changed
0 0 -1 // not changed [/b]
Then, is it the way I call

Gl.glNormalPointer(Gl.GL_DOUBLE,0,pNorList);Gl.glDrawElements(Gl.GL_QUADS, ArrayIndex.Length, Gl.GL_UNSIGNED_INT, mesh.ArrayIndex);
is correct?
I means the number of normal that assign to the vertex indice?

Originally posted by HanWu:
I means the number of normal that assign to the vertex indice?
Whithout considering normals, you need 8 vertices in the vertex array and 24 indices (ArrayIndex.Length = 24) for the above case.

However, if you want to have sharp edges at a shared vertex, then the number of vertices are increased. Consider the following diagram. V0 is shared with front, right and up faces, but normals are not same at V0.

In this case, you must define V0 three times in the vertex array in order to match the same amount of elements in the normal array. Therefore, you need 24 vertex elements in vertex array same as the number of normals. But, the index length is remaining same as before.

[quote]Originally posted by songho:
[b]

Gl.glVertexPointer(3,Gl.GL_DOUBLE,0,mesh.vertex);
  

Can you give me an example on how to assign the V0 three times to the vertex array regarding to my case (the cube). Thanks.

Originally posted by HanWu:
[b]For the command below, is it the mesh.vertex now will contain 3 times of the vertex number.

Gl.glVertexPointer(3,Gl.GL_DOUBLE,0,mesh.vertex);  

[/b]
The first param of glVertexPointer is the number of coords per vertex. “3” means the vertex is is a 3D point, (x,y,z).

Can you give me an example on how to assign the V0 three times to the vertex array regarding to my case (the cube).
Take a look at a cube with 2 units of side length, and centred at origin;

    v6----- v5
   /|      /|
  v1------v0|
  | |     | |
  | |v7---|-|v4
  |/      |/
  v2------v3

// vertex coords array
GLfloat vertices[] = {1,1,1,  -1,1,1,  -1,-1,1,  1,-1,1,        // v0-v1-v2-v3 (front)
                      1,1,1,  1,-1,1,  1,-1,-1,  1,1,-1,        // v0-v3-v4-v5 (right)
                      1,1,1,  1,1,-1,  -1,1,-1,  -1,1,1,        // v0-v5-v6-v1 (up)
                      -1,1,1,  -1,1,-1,  -1,-1,-1,  -1,-1,1,    // v1-v6-v7-v2
                      -1,-1,-1,  1,-1,-1,  1,-1,1,  -1,-1,1,    // v7-v4-v3-v2
                      1,-1,-1,  -1,-1,-1,  -1,1,-1,  1,1,-1};   // v4-v7-v6-v5

// normal array
GLfloat normals[] = {0,0,1,  0,0,1,  0,0,1,  0,0,1,             // v0-v1-v2-v3 (front)
                     1,0,0,  1,0,0,  1,0,0, 1,0,0,              // v0-v3-v4-v5 (right)
                     0,1,0,  0,1,0,  0,1,0, 0,1,0,              // v0-v5-v6-v1 (up)
                     -1,0,0,  -1,0,0, -1,0,0,  -1,0,0,          // v1-v6-v7-v2
                     0,-1,0,  0,-1,0,  0,-1,0,  0,-1,0,         // v7-v4-v3-v2
                     0,0,-1,  0,0,-1,  0,0,-1,  0,0,-1};        // v4-v7-v6-v5

// index array of vertex array for glDrawElements()
GLubyte indices[] = {0,1,2,3,
                     4,5,6,7,
                     8,9,10,11,
                     12,13,14,15,
                     16,17,18,19,
                     20,21,22,23};

Notice that the vertex, V0, (1,1,1) is defined 3 times in vertex coords array to make front, right and up faces(quads). But, the normals at V0 are all different for each face; (0,0,1), (1,0,0) and (0,1,0).

Hi, Thanks for your explaination. Now I know what I should do. Anyway, if we have to define the vertex 3 times then we can straight away use the command Gl.glDrawArray(Gl.GL_QUADS,0,mesh.numOfVertex); instead of glDrawElements is it?

Yes, for this case, glDrawArrays() and glDrawElements() have no difference. Notice the indices are listed straight from beginning(0) to end(23) as exactly same order of vertex array without hopping, because of different normals at a shared vertex.