Efficient vertex arrays without duplicating data?

Hi,

I’ve created an OpenGL ES app based on the simplecube demo in the symbian 60 examples. One thing that has struck me is the apparent inability of opengl to reuse vertex data when different normals or texture coordinates are required for each vertex.

eg.

  • for a cube each of the 8 vertex’s shares exactly 3 faces (6 triangles)
  • this poses a problem if you want flat shaded (not averaged) lighting to the sides of the cube
  • glDrawElements expects exactly the same number of normals and texcoords as vertices in the lists
  • this means you can’t have 3 normals (one for each face) per vertex unless you copy each vertex 3 times
  • this creates a vertex list 3 times as big (trivial for a cube but not for bigger objects)

Ideally (I’ve done this in my software only renderer in the past) each polygons vertex would be a structure with seperate indexes for the vertex list, the normal list and the texcoord list. Then you could reuse normals and texture coords without duplicating vertex points. This list of vertex structures can be passed to an equivalent of the glDrawElements call.

eg.

struct TTriangle
{
int v1, v2, v3; //index into the vertex array
int n; //index into the normal array
int u, v; //index into the textcoord array
};

TTriangle *triangles; //list of objects triangles

In terms of efficiency, if you create duplicate vertex’s so that you can have unique normals and texcoords this obviously increases memory usage and bandwidth, but also means that OpenGL is transforming and clipping 3 times as many vertex’s than needed. Also on large objects it would allow normals to be reused.

The most effecient method would be to send 8 vertices, 24 normals, 24 texcoords and 12 triangle index structs, instead of 24 vertices, 24 normals, 24 texcoords and 12 triangle index triplets.

Is there a way round this duplication of data to keep a minimal vertex, normal and texcoord list while still using the vertex array calls like (glDrawEllements etc)?

Thanks for your advice,
Chris.

Unfortunately there is no way around this. You just have to bite the bullet the replicate the data.

I must assure though that even if this seems very bad with a cube (i.e. when comparing the amount of transforms done currently and what would be the optimum), I wouldn’t be that worried. Typically objects that tend to have very many sharp edges (ones that have same position, but different normal) tend to have fewer faces than smooth objects and thus the inefficiency isn’t that bad after all.

The cube is an excellent example: even though you are transforming three times as many vertices as you would really need to, it’s just 24 in total. Typically even low-poly models with smooth faces tend to be in the order of hundreds of vertices. Thus you could render quite a few cubes before the transformation cost becomes an issue.

Sorry to disappoint you, but I can assure you: there is life after realizing this. :slight_smile:

Cheers,
Petri

Thanks Petri. I can see your logic that on average it would only be a negligable extra amount of processing in comparisson to a large smooth object. One exception maybe say a large city scape made entirely of complex sharp edged objects, but as you say, theres no way round it.

Do you think this is something that will be addressed in later versions of ES or indeed desktop OpenGL?

I wouldn’t bet my money on such a feature coming to OpenGL. It might come in the future, but at least I wouldn’t hold my breath quiet yet…

But I do agree that there are some special cases where you would get additional speed-ups, but I don’t they are a big enough use-case to introduce such additional complexity into OpenGL. It would cause quite a bit of problems to hardware that fetches the different vertex attributes.

Currently they are all usually packed together (which is very very good for memory coherence and caches), but if you’d fetch them all separately, that would probably cause such random memory accesses and bad cache behaviour that it might slow your application down more than you’d win by sharing the computations. Hardware isn’t good at random memory fetches.

I’m having the same problem - I’m glad I’m not the only one to come across this. I haven’t found much info on the internet about it either.

It would be good if you could pass a list of texture coordinate indices and normals indices to DrawElements:


void glDrawElementsEx(GLenum mode,
    GLsizei count,
    GLenum type,
    const GLvoid * indices,
    const GLvoid * normalsIndices,
    const GLvoid * textureIndices
)

Then you could setup your vertices, normals, texture coordinate arrays, then pass in optional index arrays for each. If you didn’t specify an array it would default to using the vertex indices.

Looks like I’m gonna do it the ol’ fashioned way for now though.

I am having a similar problem here. I managed to smooth things up for shared normals. But now i am in need for sharp edges. Since this thread is 2 years old, is there any news about this issue? has this been resolved by new OES versions or is it still our fate to duplicate vertex data?

Cheers

You still have to duplicate vertex data.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.