When using glDrawElementsInstanced you need to make your shaders use gl_InstanceiD
#version 410
layout (location = 0) in vec3 Position;
layout (location = 1) in vec2 TexCoord;
layout (location = 2) in vec3 Normal;
layout (location = 3) in mat4 WVP;
layout (location = 7) in mat4 World;
out vec2 TexCoord0;
out vec3 Normal0;
out vec3 WorldPos0;
flat out int InstanceID;
void main()
{
gl_Position = WVP * vec4(Position, 1.0);
TexCoord0 = TexCoord;
Normal0 = World * vec4(Normal, 0.0)).xyz;
WorldPos0 = World * vec4(Position, 1.0)).xyz;
InstanceID = gl_InstanceID;
};
glDrawElementsInstanced
use gl_InstanceID variable as if it were a static integer vertex attribute. When the first copy of the vertices is sent to OpenGL,
gl_InstanceID
will be zero. It will then be incremented once for each copy of the geometry and will eventually reach instanceCount - 1.
It behaves like this
for (int n = 0; n < instancecount; n++)
{
// Set the value of gl_InstanceID
glVertexAttrib1i(gl_InstanceID, n); // except this is internally incremented and not a real vertex attribute
// Make a normal call to glDrawElements
glDrawElements(mode, count, type, indices);
}
Except that this happens internally, and you only need to call glDrawArraysInstanced()
once. In order to use different transforms for each instance you can pass an array of uniform matrices and index that using gl_InstanceID
or you can use texture buffer objects and store transforms there.
So your drawing code should become like this, but note that you still need to pass uniform matrices for each intsance in an array or pass a texture buffer object once for all.
glDrawElementsInstanced(primitivetype, indices, GL_UNSIGNED_INT, 0, instanceCount-1);
and your vertex shader should become
uniform mat4 instancematrices[32];
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * instancematrices[gl_InstanceID] * gl_Vertex;
}