PDA

View Full Version : glDrawElements - Drawing first few elements from a larger index and vertex array



Spankenstein
09-02-2012, 03:57 PM
Hi folks,

I'm setting up my vertex array object and I'm having troubles drawing anything on the screen.

I have checked with a simple triangle of 3 vertices and everything works as intended but I am now trying something more complex and it doesn't work.

This is how my VAO is setup



// Generate and bind VAO
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);

// Vertex Buffer
GLuint vbuffer;
glGenBuffers(1, &vbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vbuffer);

// Vertex Attributes

// Position
glEnableVertexAttribArray(0); // layout(location = 0) [GLSL]
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexPositionTexture), (void*)BUFFER_OFFSET(0));

// Texture UV
glEnableVertexAttribArray(1); // layout(location = 1) [GLSL]
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(VertexPositionTexture), (void*)BUFFER_OFFSET(12));

// Index buffer
GLuint ibuffer;
glGenBuffers(1, &ibuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuffer);

// This only needs to be done once as the indices never change
glBufferData(GL_ELEMENT_ARRAY_BUFFER, maxIndices * sizeof(GLushort), &m_indices[0], GL_STATIC_DRAW);

glBindVertexArray(0);


The indices are generated with this method, they account for the maximum number of quadrangles I can draw in one draw call.



int numIndices = 0;

for (int i = 0; i < maxQuadrangles; i++)
{
// CW Winding [0, 1, 2] [1, 3, 2]
m_indices[numIndices++] = 0 + i;
m_indices[numIndices++] = 1 + i;
m_indices[numIndices++] = 2 + i;

m_indices[numIndices++] = 1 + i;
m_indices[numIndices++] = 3 + i;
m_indices[numIndices++] = 2 + i;
}


The array for vertices is also initialised to the maximum size possible for each draw call



std::array<VertexPositionTexture, maxVertices> m_vertices;


If I wish to draw a quadrangle then I copy the appropriate vertices for each quadrangle to draw



// Copy the vertex data to the drawer's large vertices array
std::array<VertexPositionTexture, 4> v = quadrangle.getVertices();
std::copy(v.begin(), v.end(), m_vertices.begin() + (m_numQuadrangles * 4));
m_numQuadrangles++;


Now for the part that doesn't appear to work.



// Bind VAO (restores all buffer bindings and attribute settings that were previously set up)
glBindVertexArray(m_vao);

// Update the vertex buffer with the new data (Copy data into the vertex buffer object)
glBufferData(GL_ARRAY_BUFFER, maxVertices * sizeof(VertexPositionTexture), &m_vertices[0], GL_DYNAMIC_DRAW);

glDrawElements(GL_TRIANGLES, m_numQuadrangles * 2, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));

// Unbind VAO
glBindVertexArray(0);

// Reset number of quadrangles
m_numQuadrangles = 0;


What I am trying to do with the code above is copy the entire vertices array m_vertices to the vertex buffer.

Then depending on the number of quadrangles added for this batch I wish to only use part of the index and vertex buffers.

So m_numQuadrangles * 2 means I wish to use 2 triangles per quadrangle in the batch.

I have also tried



glDrawRangeElements(GL_TRIANGLES, 0, m_numQuadrangles * 6, m_numQuadrangles * 2, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));


BUFFER_OFFSET is defined as



#define BUFFER_OFFSET(i) ((char *)NULL + (i))


Why am I getting nothing drawn to the screen?

Dan Bartlett
09-02-2012, 06:10 PM
One potential problem: the buffer currently bound to GL_ARRAY_BUFFER isn't part of VAO state - it's context state, so you need to bind the buffer object before loading new data to it.

Spankenstein
09-03-2012, 04:11 AM
One potential problem: the buffer currently bound to GL_ARRAY_BUFFER isn't part of VAO state - it's context state, so you need to bind the buffer object before loading new data to it.

Like so?



// Bind VAO (restores all buffer bindings and attribute settings that were previously set up)
glBindVertexArray(m_vao);

// Update the vertex buffer with the new data (Copy data into the vertex buffer object)
glBindBuffer(GL_ARRAY_BUFFER, vbuffer);
glBufferData(GL_ARRAY_BUFFER, maxVertices * sizeof(VertexPositionTexture), &m_vertices[0], GL_DYNAMIC_DRAW);

// 'count' parameter is the number of indices to use from the 'm_indices' array
glDrawElements(GL_TRIANGLES, m_numQuadrangles * 6, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));

// Unbind VAO
glBindVertexArray(0);

// Reset number of quadrangles
m_numQuadrangles = 0;


It works but I would like to make sure it is correct.

If the indices change at any point would I have to do the same for them too? In other words calling glBindBuffer for the index buffer each time the index data changes.

Thanks for your help :)

Dan Bartlett
09-03-2012, 05:18 AM
Like so?



// Bind VAO (restores all buffer bindings and attribute settings that were previously set up)
glBindVertexArray(m_vao);

// Update the vertex buffer with the new data (Copy data into the vertex buffer object)
glBindBuffer(GL_ARRAY_BUFFER, vbuffer);
glBufferData(GL_ARRAY_BUFFER, maxVertices * sizeof(VertexPositionTexture), &m_vertices[0], GL_DYNAMIC_DRAW);

// 'count' parameter is the number of indices to use from the 'm_indices' array
glDrawElements(GL_TRIANGLES, m_numQuadrangles * 6, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));

// Unbind VAO
glBindVertexArray(0);

// Reset number of quadrangles
m_numQuadrangles = 0;


It works but I would like to make sure it is correct.

Yeah, that's right.

OpenGL stores a reference to the buffer currently bound to GL_ARRAY_BUFFER when you make the glVertexAttribPointer/gl[***]Pointer call for the specified attribute, so you can have multiple buffer objects referenced by a single VAO. This means that the GL_ARRAY_BUFFER binding point is not needed for the draw call, so isn't stored with the VAO. If you were to use multiple VBOs with dynamic data, you would need to upload data to each of these in turn.




If the indices change at any point would I have to do the same for them too? In other words calling glBindBuffer for the index buffer each time the index data changes.

Thanks for your help :)
The GL_ELEMENT_ARRAY_BUFFER binding is a part of VAO state, so there's no need to do the same for indices. If you look at the state tables in the OpenGL appendices, they have one table with "Vertex Array Object State" + one table with "Vertex Array Data (not in Vertex Array objects)" so if you're unsure you can check which table a certain piece of state is in.

Spankenstein
09-04-2012, 08:31 AM
If you look at the state tables in the OpenGL appendices, they have one table with "Vertex Array Object State" + one table with "Vertex Array Data (not in Vertex Array objects)" so if you're unsure you can check which table a certain piece of state is in.

Hi Dan. Could you please post a link to the table you mentioned? I'm having trouble locating it.

Alfonse Reinheart
09-04-2012, 08:37 AM
It's in the OpenGL specification. Searching for the words "Vertex Array Object State" will take you right there.

Spankenstein
09-04-2012, 09:00 AM
Thanks very much :)