Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenGLES 2.0 separate buffers for vertices, colors and texture coordinates

I've been learning OpenGL for a few days now by following some tutorials and coding some experiments of my own. But there is one thing I really don't understand which blocks me from continuing. I've been googling for a few hours now and didn't find an answer yet to my question.

Where should I specify every separate color value and texture coordinate for every individual vertex? Should those properties always be listed in the same array (struct) as the vertex positions? Like so:

const Vertex Vertices[] = {
    // Front
    {{1, -1, 0}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}},
    {{1, 1, 0}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
    {{-1, 1, 0}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},
    {{-1, -1, 0}, {0, 0, 0, 1}, {0, 0}},

    ...

Or is there a way to put color values and texture coordinates in separate arrays? But then the question arises: how do I call glDrawElements with separate arrays?

In case you are wondering why I want to separate these values: I'm currently making my own .obj parser in obj-c and I was wondering: what if you load a model without a texture and only want to show a color on the object? Or: what if you want load a model with only a texture mapped to it but no separate color per vertex? And: Isn't putting color values and texture coordinate bloating the Vertex struct with too much data.

like image 217
polyclick Avatar asked Jan 06 '12 11:01

polyclick


2 Answers

Actually it is the usual way to separate the vertex data into position, color, etc. using several arrays/buffers.

Last time I came in contact with ES 2.0 was in the context of WebGL (which is has a slightly different spec but is ultimately based on ES 2.0).

What is basically done is writing the data to seperate buffers using

glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), positions, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), colors, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

...

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(ushort), indices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

with positions and colors being float arrays containing the vertex data and indices containing the indices as unsigned shorts in this case.

To render this data, you'd use the buffers and attribute pointers to your shader:

glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(vertexPositionAttribute, 3,  GL_FLOAT, false, 0, 0);

glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glVertexAttribPointer(vertexColorAttribute, 4, GL_FLOAT, false, 0, 0);

Finally bind the index buffer:

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);

and render:

glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, 0);

To get the attributes:

glUseProgram(shaderProgram);

vertexPositionAttribute= glGetAttribLocation(shaderProgram, "vertexPosition");
glEnableVertexAttribArray(vertexPositionAttribute);

vertexColorAttribute = glGetAttribLocation(shaderProgram, "vertexColor");
glEnableVertexAttribArray(vertexColorAttribute );

...

If you don't have custom shaders(using fixed function) you might be able to use

glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexPointer(3,  GL_FLOAT, false, 0, 0);

glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glColorPointer(4, GL_FLOAT, false, 0, 0);

instead. I'd advise against it, though, as it is outdated (if at all available in ES 2.0). If you still want to use it, you can skip the whole buffer business altogether and use

glVertexPointer(3, GL_FLOAT, false, 0, positions);
glColorPointer(4, GL_FLOAT, false, 0, colors);

with

glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, indices);

I hope that wasn't too confusing and helps a bit. For further reading, although targeted at OpenGL, I'd suggest the Nehe tutorials.

like image 152
warhead Avatar answered Jan 01 '23 11:01

warhead


You can of course have your data in different buffers. Keep in mind that it is the glVertexAttribPointer call that determines an attribute's source. So to use a different buffer for an attribute, just bind a different GL_ARRAY_BUFFER before calling glVertexAttribPointer. glDrawElements doesn't have anything to do with it:

glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
glVertexAttribPointer(0, ...);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glVertexAttribPointer(1, ...);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glDrawElements(...);

glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);

When not using VBOs (which I'm not sure is possible in ES 2.0), just call glVertexAttribPointer with a different array for each attribute:

glVertexAttribPointer(0, ..., positionArray);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, ..., colorArray);
glEnableVertexAttribArray(1);

glDrawElements(..., indexArray);

glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);

But it is usually more performant to keep a single vertex's attributes together like in your example, as this is more cache friendly. If nearly all your objects use all arrays, then keeping them together and just not enabling the attribute for the few objects that don't use it, may be a better idea. But if the used attributes really differ from object to object, the separate buffer solution may be a better idea. You can also store all separate attribute arrays one after the other in a single VBO and use corresponding buffer offsets in the glVertexAttribPointer calls, so you still only need one VBO per object.

But of course you can only use one index array per object and not different index arrays for positions and colors. This may require you to postprocess the data read from an OBJ file a bit, as OBJ files can indeed use different indices for positions, normals and texCoords.

like image 30
Christian Rau Avatar answered Jan 01 '23 10:01

Christian Rau