Reputation: 13876
I have a flat plane and an index buffer, or EBO with the indices marked on the image:
Now if I call:
glDrawElementsBaseVertex(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0, 0);
I get this:
This I understand. Further, If I do this:
glDrawElementsBaseVertex(GL_TRIANGLES, 9, GL_UNSIGNED_INT, 0, 0);
This makes sense too. But my understanding completely falls apart when I change one of the other parameters. If I do this:
glDrawElementsBaseVertex(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0, 3);
It looks like this:
So by passing the argument 3 to the basevertex argument (the last one), it's started using the index not from 3 positions into the index, and not even from 3 triangles into the index, but it's started about 6 triangles in, or more precisely index number 18. I can't understand this behaviour.
Also, I have read contradicting meanings for the argument of "indices" in these functions:
void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid * indices);
void glDrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, GLvoid *indices, GLint basevertex);
I've read that the indices pointer gives you the possibility to refer to an index buffer directly by providing a pointer, and if it is null then the index buffer is taken from the currently bound GL_ELEMENT_ARRAY_BUFFER. However from the documentation in one version it says:
indices Specifies a byte offset (cast to a pointer type) into the buffer bound to GL_ELEMENT_ARRAY_BUFFER to start reading indices from.
And in another version it says:
indices Specifies a pointer to the location where the indices are stored.
If I call glDrawElementsBaseVertex with the second last argument (indices) as (void*)3 I get the first triangle drawn red. If I specify (void*)6 I get no triangles highlighted. And if I specify (void*)9 I get the second triangle highlighted.
I can't make sense of any of this. So is it the case that this argument, indices, is NOT an optional pointer to the indices you wish to use instead of using the element array buffer currently bound?
Upvotes: 1
Views: 4266
Reputation: 1
We have vertex positions.
float positions[] =
{
-0.5f, -1.0f, 0.0f,
-1.5f, 1.0f, 0.0f,
-2.5f, -1.0f, 0.0f,
2.5f, -1.0f, 0.0f,
1.5f, 1.0f, 0.0f,
0.5f, -1.0f, 0.0f
};
We also have position indices of two triangular meshes.
uint8 indices[] =
{
0, 1, 2,
3, 4, 5
};
To draw these two meshes, we use glDrawElements
as shown below:
// --------------------------------------------------------
// The first triangular mesh.
struct
{
int32 numIndices = 3;
int32 baseIndex = 0;
} mesh_1;
glDrawElements(
/* mode = */ GL_TRIANGLES,
/* count = */ mesh_1.numIndices,
/* type = */ GL_UNSIGNED_BYTE,
/* offset = */ (void*)( sizeof( uint8 ) * mesh_1.baseIndex ) );
// --------------------------------------------------------
// The second triangular mesh.
struct
{
int32 numIndices = 3;
int32 baseIndex = 3;
} mesh_2;
glDrawElements(
/* mode = */ GL_TRIANGLES,
/* count = */ mesh_2.numIndices,
/* type = */ GL_UNSIGNED_BYTE,
/* offset = */ (void*)( sizeof( uint8 ) * mesh_2.baseIndex ) );
Note that the following lines must be of the same data type:
uint8 indices[] = /* type = */ GL_UNSIGNED_BYTE, /* offset = */ (void*)( sizeof( uint8 ) * mesh_1.baseIndex ) );
The data type must be one of the following:
uint8
,uint16
oruint32
.
The result will be this image.
If we want to draw several different meshes in this way, probably each mesh will store its indices starting from zero. For example, loading a scene using the assimp library, we will get the following set of indices:
uint8 indices[] =
{
0, 1, 2,
0, 1, 2
};
Let's draw these meshes as well.
// --------------------------------------------------------
// The first triangular mesh.
struct
{
int32 numIndices = 3;
int32 baseVertex = 0;
int32 baseIndex = 0;
} mesh_1;
glDrawElementsBaseVertex(
/* mode = */ GL_TRIANGLES,
/* count = */ mesh_1.numIndices,
/* type = */ GL_UNSIGNED_BYTE,
/* offset = */ (void*)( sizeof( uint8 ) * mesh_1.baseIndex ),
/* basevertex = */ mesh_1.baseVertex );
// --------------------------------------------------------
// The second triangular mesh.
struct
{
int32 numIndices = 3;
int32 baseVertex = 3;
int32 baseIndex = 3;
} mesh_2;
glDrawElementsBaseVertex(
/* mode = */ GL_TRIANGLES,
/* count = */ mesh_2.numIndices,
/* type = */ GL_UNSIGNED_BYTE,
/* offset = */ (void*)( sizeof( uint8 ) * mesh_2.baseIndex ),
/* basevertex = */ mesh_2.baseVertex );
The result will be the same image.
When we have loaded the scene, we need to somehow get the data we need to draw, the following code will help us with this:
int32 numVertices = 0;
int32 numIndices = 0;
for ( auto& mesh : scene.meshes )
{
mesh.numIndices = mesh.numTriangles * 3;
mesh.baseVertex = numVertices;
mesh.baseIndex = numIndices;
numVertices += mesh.numVertices;
numIndices += mesh.numIndices;
}
As an example, by loading the "Low Poly UFO Scene" scene, the result will be this image.
Upvotes: 0
Reputation: 21
If you want to have an offset for the indices, you can simply use glDrawElements like so:
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, (void*)(sizeof(GLuint)*6));
It will draw 3 elements with an offset of 6 for indices.
The last argument of glDrawElements can be two different things:
Upvotes: 2
Reputation: 81
A little late to reply but I just ran into a need to call this GL function and I too struggled with its behavior.
I'm willing to bet that the numbers you've included in your first image are NOT the actual index values in your index buffer, but simply indicate the ORDER that you are specifying vertices. Assuming your vertex buffer is organized as follows:
where the red numbers I've added are the vertex buffer array indices, your actual index buffer contents should begin with {0,1,6,1,7,6,...}.
So with basevertex equal to zero, calling glDrawElementsBaseVertex() does the following:
When i=0, element zero from your index buffer (which has a value of zero), causes element zero (red numbers in the above image) in your vertex buffer to be used as the first vertex of your first triangle. With i=2, element two from the index buffer (value of six), causes element six in your vertex buffer to complete the first triangle.
Quoting the documentation for glDrawElementsBaseVertex()
"the ith element transferred by the corresponding draw call will be taken from element indices[i] + basevertex of each enabled array."
Ya, that's a little confusing but it means that after the index value is retrieved from the index buffer, basevertex is added to it. So with a basevertex of 3, we have the following behavior:
When i=0, element zero from your index buffer is retrieved. As before, it has a value of zero but now three is added to it. So element three in your vertex buffer (again, red numbers in the above image) is used as the first vertex of your first triangle. With i=2, element two from the index buffer is retrieved which has a value of six but three is added to that, so element nine from your vertex buffer is used to complete the first triangle.
Hope this helps.
Upvotes: 0
Reputation: 2596
You should also show us how you number your vertices. From the screenshot it looks like the vertices are aligned by rows. In that case it correctly renders vertices in the third cell because that's where the 3rd vertex is.
You should set base vertex to 1 if you want to render the first half of cell 2, because that's where vertex 2 is.
Similarly, if you want to render the second half of cell 2 then you should set base pointer to 1 and index pointer to 3.
Upvotes: 0