Mailing Lists: Apple Mailing Lists
Image of Mac OS face in stamp
Re: glDrawElements and Arrays
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: glDrawElements and Arrays



On 26 Jan 2004, at 20:43, Lee Morgan wrote:

Well, do to everyone (approximation) informing me that open-GL's array
functions would greatly increase the performance I went and looked at
(the very few) examples I could find using them (all of the GLUT
examples apparently use display lists - which makes me wonder if their
even better?) Anyways to cut to the point I've set up a simple app to
help me learn some tricks of speeding up my main app - I've made me an
array of vertices and enabled the array like so...

static GLfloat vertices[] = { 0.0, 0.5, 0.0,
-0.5, 0.0, 0.0,
0.5, 0.0, 0.0,
0.0, -0.5, 0.0,
0.5, 0.0, 0.0,
-0.5, 0.0, 0.0};

glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices);

Now I can get this to render fine with glArrayElement() or
glDrawArrays; however I can't get it to render at all using
glDrawElements() I've looked through the Red Book but haven't came up
with much... I know that glDrawElements() only takes uByte, uShort, or
uInt for its type - so I tried switching my array over to be GLubyte
and calling glDrawElements like so...

glDrawElements(GL_TRIANGLES, 18, GL_UNSIGNED_BYTE, vertices);

But it doesn't render anything to the screen.
Any idea where I'm going wrong here?

Also, is there any (semi-simple) examples on using the
APPLE_vertex_array_object and APPLE_element_array extensions? I've
looked (briefly) at both Vertex Optimization and VertexPerformanceTest
but they seem to concentrate solely on the APPLE_array_range extension
or can you not have one without the other? To be completely honest I'm
a bit lost when it comes to finding any kind of information on the
extensions I've looked over their specs but its a little hard to grasp
- I guess I'll just have to read over them a few more times.

The specs are indeed a bit daunting at first :-)

You are meant to pass in an array of _indices_ into glDrawElements,
not the vertices again.

You need two sets of data to use glDrawElements. You need your
arrays of per-vertex information, like GL_VERTEX_ARRAY for the position,
GL_NORMAL_ARRAY for the normals, etc. You also need an array of
indices. This array contains the indices of the vertices (and normals, etc.)
in the other arrays that form the vertices of the triangles.

Here is an example:

GLfloat afVertex[] =
{
0.0, 0.0, 0.0,
10.0, 0.0, 0.0,
10.0, 10.0, 0.0
0.0, 1.0, 0.0
};

GLushort anIndex[] =
{
0, 1, 2,
0, 2, 3
};

glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 3, GL_FLOAT, 0, afVertex );

glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, anIndex );

You can image glDrawElements iterating of the array of indices, and doing the
equivalent of a glVertex() call using the data from the vertex array at the given
index.

Even faster would be to use GL_ELEMENT_ARRAY_APPLE, like this:

glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_ELEMENT_ARRAY_APPLE );

glVertexPointer( 3, GL_FLOAT, 0, afVertex );
glElementPointerAPPLE( GL_UNSIGNED_SHORT, anIndex );

glDrawElementArrayAPPLE(
GL_TRIANGLES,
0, // start at index 0
6 // number of indices in the array
);

This is faster because the index array can be passed to the video card, and it will do
all the processing for you, rather than the CPU having to resolve the vertices and pass
them to the video card.

You can keep all this data together using APPLE_vertex_object, which lets you swap
your arrays of geometry into being active in a similar fashion to making textures active.

GLuint nMeshID;

glGenVertexArraysAPPLE( 1, & nMeshID );

glBindVertexArrayAPPLE( nMeshID );

// Now- enable all your client state, and setup your vertex/element pointers

When you want to draw your array, just call glBindVertexArrayAPPLE( nMeshID )
again, then call glDrawElementArrayAPPLE. This prevents you having to pass in all
the pointer information every time you want to draw your mesh.

Also, if you want to ensure that your data is uploaded to the video card and cached
there, you need to use the APPLE_vertex_array_range extension. This is very
simple to use providing your data is structured to use it. After you have setup your
mesh for rendering (use glEnableClientState and glWhateverPointer) you can tell
OpenGL to cache your data using the following command:

glEnableClientState( GL_VERTEX_ARRAY_RANGE_APPLE );

glVertexArrayRangeAPPLE(
sizeof( afVertex), // number of bytes in our vertex buffer
afVertex // pointer to beginning of vertex buffer
);

// This sets the caching policy.
// GL_STORAGE_CACHED_APPLE- geometry doesn't change
// GL_STORAGE_SHARED_APPLE- geometry is likely to change
glVertexArrayParameteriAPPLE(
GL_VERTEX_ARRAY_STORAGE_HINT_APPLE,
GL_STORAGE_CACHED_APPLE
);

Each time the data changes, you notify OpenGL using the following:

glFlushVertexArrayRangeAPPLE(
sizeof(afVertex),
afVertex
);

If you start requiring extra per-vertex data in your mesh, such as normals, colours,
texture coordinates, then you are going to have to use more advanced vertex formats.
It's not efficient for the video card to read in data from multiple different arrays. Instead,
you should interleave everything into one big array, like this:

struct MyVertex
{
struct {
GLfloat x;
GLfloat y;
GLfloat z;
} position;

struct {
GLfloat x;
GLfloat y;
GLfloat z;
} normal;

struct {
UInt8 r;
UInt8 g;
UInt8 b;
UInt8 a;
} colour;
};

MyVertex aVertex[] =
{
{ { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }, { 255, 255, 255, 255 } },
{ { 10.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }, { 255, 255, 255, 255 } },
{ { 10.0, 10.0, 0.0 }, { 0.0, 0.0, 1.0 }, { 255, 255, 255, 255 } },
{ { 0.0, 10.0, 0.0 }, { 0.0, 0.0, 1.0 }, { 255, 255, 255, 255 } },
};

GLushort anIndex[] =
{
0, 1, 2,
0, 2, 3
};

When it comes time to submit your data, you'll need to calculate the
offsets into your aVertex array of the start of each array, which is quite simple
using a macro:

#define FieldOffset(type, field) (long)(&((type *) 0)->field)

Now, you have to pass some slightly more specific information into OpenGL
about where to find all the different parts of the per-vertex data.

Here's how I do it:

void* pVertexPointer = ((char*) aVertex);
void* pNormalPointer = ((char*) aVertex) + FieldOffset( MyVertex, normal );
void* pColourPointer = ((char*) aVertex) + FieldOffset( MyVertex, colour );

glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_NORMAL_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );

glVertexPointer( 3, GL_FLOAT, sizeof(MyVertex), pVertexPointer );
glNormalPointer( 3, GL_FLOAT, sizeof(MyVertex), pNormalPointer );
glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof(MyVertex), pColourPointer );

Now, you can use APPLE_vertex_array_range to completely cache all of your
streams of vertex data, since they are interleaved and stored in the same
contiguous chunk of memory:

glEnableClientState( GL_VERTEX_ARRAY_RANGE_APPLE );

glVertexArrayRangeAPPLE(
sizeof( aVertex), // number of bytes in our vertex buffer
aVertex // pointer to beginning of vertex buffer
);

If you want your indices to be cached on the video card too, you'll need to allocate
a chunk of memory which is contiguous, and big enough to hold both your vertex
array and your index array. Then you need to write your vertex array into the
beginning of this buffer, and your index array afterwards (or vice-versa, whatever
rows your boat), and then pass this buffer through to glVertexArrayRangeAPPLE.

(NOTE: A warning about using unsigned bytes for colours; see another recent
thread on this mailing list concerning the performance implications of doing this
on ATI hardware! :-) )

For your benefit, if you can get a hold of a recent revision of The Red Book, otherwise
known as the OpenGL Programming Guide, it will explain a lot about using the
OpenGL vertex array functionality, and numerous other aspects of OpenGL. If you've
once read and digested that, you'll have a better foundation to build upon when you
come to plough through the OpenGL extension specs (which often take me a few
re-reads to grok too :-)

--
James Milne
_______________________________________________
mac-opengl mailing list | email@hidden
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/mac-opengl
Do not post admin requests to the list. They will be ignored.

References: 
 >glDrawElements and Arrays (From: Lee Morgan <email@hidden>)



Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Contact Apple | Terms of Use | Privacy Policy

Copyright © 2011 Apple Inc. All rights reserved.