Sign in to follow this  
mikeathan

Problems with glDrawElements()

Recommended Posts

I have problem trying to render an object using glDrawElements() . I am loading external objects in my class, Mesh that contain m_pVertex and m_nNormal, both sub classes of Mesh. i initialize indices as follows: GLushort *faces_indices; for(int i=0; i < mesh.m_nFace; i++){ indices[i*3] = (GLushort)mesh.m_pFace[i].v0()+1; indices[(i*3)+1] = (GLushort)mesh.m_pFace[i].v1()+1; indices[(i*3)+2] =(GLushort) mesh.m_pFace[i].v2()+1; } ---------------------------------- My problem is that the connectivity of the object is wrong.The points are correct but when i go to GL_LINES mode some faces are missing. I have tried everything, my guess is that the indices are different from faces . Can you help me ? glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3,GL_FLOAT,sizeof(CVertex3D),&Mesh[i].m_pVertex[0]); glNormalPointer(GL_FLOAT,sizeof(CNormal3D),&Mesh[i].m_pNormal[0]); glDrawElements(gl_mode,3*Mesh[i].m_nFace,GL_UNSIGNED_SHORT,indices); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_VERTEX_ARRAY);

Share this post


Link to post
Share on other sites
The indices are different for GL_LINES.

Your setup is sufficient for GL_POINTS and GL_TRIANGLES. For GL_POINTS each vertex is rendered individually, with GL_TRIANGLES 3 indices form a triangle.

So now imagine what happens with GL_LINES. The first edge of the triangle will be rendered fine (i.e. T1.vertex1 and T1.vertex2). The second line however will be formed from T1.vertex3 and T2.vertex1.

Short (a bit exaggerated) example:


Consider the following index setup. Using GL_TRIANGLES, everything is fine.
3 6

/\ /\

/ \ / \

1----2 4----5


Now GL_LINES:

3_ 6

\_ \

\ \

1----2 4 5



You see? 3 lines (one incorrect) instead of 2 triangles.

Share this post


Link to post
Share on other sites
Hi thanks for the reply , i thought i could switch to every GL_MODE with indices. My problem though is different. When i render the object the surface and the points seems to be ok ,but the normals dont appear right . I calculate the normals and they are correct if i render the object with glBegin() glEnd().
Thats why i thought the indices are not setup up correctly.
Are there any other options for glNormalPointer or is the below statement correct ? glNormalPointer(GL_FLOAT,sizeof(CNormal3D),&Mesh[i].m_pNormal[0]);
when the normals are in :
Mesh[i].m_pNormal[0].x(),
Mesh[i].m_pNormal[0].y()
Mesh[i].m_pNormal[0].z()

Share this post


Link to post
Share on other sites
No i thought i need one normal for each face, i also just realize that my geometry has problems so i have to fix that first. I guess that the problem starts from the indices. The vertices are fine , i am using a 4 vertices cube , but when i am copying the faces to an indices array (which is the size of faces*3), the cube has problems . I get confused with the indices , are the same with faces or not ?

Share this post


Link to post
Share on other sites
It seems that in your set-up you have 1 array per vertex property. The properties you are dealing with are vertex positions and vertex normals (and perhaps others, but they are all handled the same way). A cube has 8 corners, and so it requires at least 8 vertices. However, if you pick out one of them and approach it from different adjacent faces, you'll see that one of the properties is constant (namely the position), the other property is different (namely the normal). But a single vertex can have only one composition of all it properties. Hence, you need only 8 vertices if both the positions and normals would be the same, but in your case you need 6*4=24 (noof faces by noof corners per face) vertices due to the varying normals. The faces are quads but rendered as triangles, so you have to feed the GPU with 6*2=12 triangles, requiring 12*3=36 indices.

In summary, you need the arrays
mesh.m_pVertex[24] // vertex positions
mesh.m_pNormal[24] // vertex normals
mesh.m_pFace[36] // triangle indices

Then fill in the array e.g. like follows: Iterate over the 6 faces, generate the 4 vertices in CW order for the current face, and for each vertex write the position to m_pVertex and copy the face normal to m_pNormal. So, for each face 4 vertex positions and 4 vertex normals are written to the arrays. Then generate the indices for the array. E.g. if the current "base index" (i.e. the index of the 1st of the 4 vertices for the current face) is i, the possible index list for a face (remember: a quad split into 2 triangles) can be i, i+1, i+2, i, i+2, i+3.

Share this post


Link to post
Share on other sites
Hi thansk again for your reply , apparently the geometry is correct but the normals are the problem now. As you can see in the screenshot here : http://www.flickr.com/photos/mikeathan/2713266941/


the left cube is the one drawn using glDrawElements() and the second is drawn using glBegin()/glEnd(). Both they use the same normals but when they are drawn they don't reflect the light the same .
The second example shows the problem better using a different object

http://www.flickr.com/photos/mikeathan/2713277677/

Again the first is rendered using glDrawElements() and the second using glBegin/End();

Any ideas ?/

Share this post


Link to post
Share on other sites
I doubt of the identity of the normals over a face.

Look e.g. at the top face of the cube. The front corner of the top face has the same gray color as the top-left corner of the front face as well as the right-top corner of the left face. This shows clearly that the normals of the top-front vertices of those 3 faces are identical! That's an error.

Moreover, there is a gradient from the front to the rear. Hence the normals at the front of the top face differ from those at its rear.

As already stated, all normals of a given face must be the same to yield in the correct rendering.

E.g. the vertex position of the top face may be
m_pVertex[0] = { +1, +1, +1 };
m_pVertex[1] = { -1, +1, +1 };
m_pVertex[2] = { -1, +1, -1 };
m_pVertex[3] = { +1, +1, -1 };
and the corresponding normals (all the same values!)
m_pNormal[0] = { 0, +1, 0 };
m_pNormal[1] = { 0, +1, 0 };
m_pNormal[2] = { 0, +1, 0 };
m_pNormal[3] = { 0, +1, 0 };
and its indices are
m_pIndex[0] = 0;
m_pIndex[1] = 1;
m_pIndex[2] = 2;
m_pIndex[3] = 0;
m_pIndex[4] = 2;
m_pIndex[5] = 3;

Notice that no other face will use the vertices with indices 0 up to 3. They all have their own quadruple of vertices, and each quadruple is to be build analogously to those shown above. This is necessary since in your case the vertices all differ and hence cannot be shared by two of the quads.


EDIT: Please bear in mind that the immediate mode is in fact a piece of software that build a vertex array from the calls. So it is able to handle things its own way. E.g. it duplicates a once set normal over and over again for each glVertex call until another glNormal is called. Such things are not done (by the driver) if you use VAs/VBOs directly. So you cannot rely on getting the same result. You have to verify the usage of VAs/VBOs by its own.

Share this post


Link to post
Share on other sites

Hi again. A problem i saw is that when i change the coordinates like changing the vertices or face_indices index, and keeping the same order for the normal array , the object is not constructed properly but the faces appear like the normals have been applied . The object reflects correctly the light even when the geometry is wrong.

is that an exception? is there something wrong with the verts/faces/normals, even when they appear correct ? or should i check the normals ?

The same verts/faces/normals works fine with glbegin/end .
Also the texture for glDrawElements and glbegin/end works fine too.

Share this post


Link to post
Share on other sites
This is the calculate normals function :
for(int i=0;i<faceList.size();i++){
v1=faceList[i].v1-1;
v2=faceList[i].v2-1;
v3=faceList[i].v3-1;
//v1
a.x=vList[v1].x;
a.y=vList[v1].y;
a.z=vList[v1].z;
//v2
b.x=vList[v2].x;
b.y=vList[v2].y;
b.z=vList[v2].z;
//v3
c.x=vList[v3].x;
c.y=vList[v3].y;
c.z=vList[v3].z;

u.x = c.x - a.x;
u.y = c.y - a.y;
u.z = c.z - a.z;
v.x = b.x - a.x;
v.y = b.y - a.y;
v.z = b.z - a.z;
Cross(u, v, w);
Normalize(w);

normals[i*3]=w.x;
normals[(i*3)+1]=w.y;
normals[(i*3)+2]=w.z;

}

I thought that the number of normals have to be the same number of faces , does it have to be the same number of vertices instead?if yes why does it works fine with glbegin/end


Share this post


Link to post
Share on other sites
Any time you render geometry using glBegin and glEnd, you're using something called "immediate mode." It's slow and clumsy on the GPU, but gives you control over just about everything.

When you use glDrawElements you're using vertex arrays. Normals are just a part of the "state" that makes up the OpenGL state machine, so when using immediate mode, you can change the normal state whenever and as frequently (or infrequently) as you want. Vertex arrays, however, work on a per-element basis, so you need to specify one normal/color/texcoord (depending on what clientstate you have enabled) for every vertex.

Share this post


Link to post
Share on other sites
Hi, thanks for the replies . The problem was the normals , i loaded the normals from the file and everything is works fine now . When i was calculating the normals it was for the faces only and not for each vertex.
Thank again.!!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this