Client-Side Vertex Arrays

From OpenGL Wiki
Revision as of 23:44, 29 March 2011 by V-man (talk | contribs) (Fixing link)
Jump to: navigation, search

Before VBOs, there was plain old vertex arrays. This means that your vertices and vertex attributes and indices are in RAM.
Of course, this doesn't give the best performance since every time you want GL to draw, the driver has to upload the vertices to the GPU.

Sample Code

I suggest that you interleave your vertex attributes for best performance. The order of of attributes should not matter for performance because it's just a pointer to a memory location for the GPU.
Make a structure for your vertex attributes in your C++ code :

 struct MyVertex
 {
 float x, y, z;        //Vertex
 float nx, ny, nz;     //Normal
 float s0, t0;         //Texcoord0
 float s1, t1;         //Texcoord1
 float s2, t2;         //Texcoord2
 float padding[4];
 };

Padding is added to make the vertex structure a multiple of 32 bytes since some GPUs prefer it that way, such as ATI/AMD.
Setup your vertices :

 MyVertex vertex[50];
 vertex[0].x=0.0;
 vertex[0].y=0.0;
 vertex[0].z=0.0;
 and so on....

Setup your indices. Unsigned short is used (16 bit) since that is what most GPUs prefer. Some of them can deal with 32 bit indices as well.
Don't use anything ridiculous like unsigned byte.

 unsigned short index[99];
 index[0]=0;
 index[1]=5;
 index[2]=3;
 and so on....

Call your gl***Pointer functions to make a INTERLEAVED ARRAY.
Also, if you are using VBOs in some other part of your code, you would have to bind VBO 0 by calling glBindBuffer(GL_ARRAY_BUFFER, 0)
You may also need to call glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)

 glEnableClientState(GL_VERTEX_ARRAY);
 glVertexPointer(3, GL_FLOAT, sizeof(MyVertex), &vertex[0].x);
 glEnableClientState(GL_NORMAL_ARRAY);
 glNormalPointer(GL_FLOAT, sizeof(MyVertex), &vertex[0].nx);
 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 glTexCoordPointer(2, GL_FLOAT, sizeof(MyVertex), &vertex[0].s0);
 glClientActiveTexture(GL_TEXTURE1);
 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 glTexCoordPointer(2, GL_FLOAT, sizeof(MyVertex), &vertex[0].s1);
 glClientActiveTexture(GL_TEXTURE2);
 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 glTexCoordPointer(2, GL_FLOAT, sizeof(MyVertex), &vertex[0].s2);

Now it's time to render. I have not included the part about setting up texture combiners, or shader, or binding shaders.

 glDrawRangeElements(GL_TRIANGLES, x, y, z, GL_UNSIGNED_SHORT, index);

x would be the very first index, which might be 0. y would be the last vertex which would be 49 (not 50!). z would the number of indices to be processed.

You might also want to read http://www.opengl.org/wiki/Vertex_Formats

In summary:

  • Make you vertex structure.
  • Make it multiple of 32 bytes in size.
  • Use 16 bit integer.
  • Try not to make many redundent calls to GL so that your performance stays the best.
  • Don't use glInterleaved array because almost nobody uses it and it's limited. You can read about it here http://www.opengl.org/wiki/Common_Mistakes