I'm drawing the following rectangle 100 times:
float vertices[] = {
0.05f, 0.05, // top right
0.05f, -0.05f, // bottom right
-0.05f, -0.05f, // bottom left
-0.05f, 0.05f // top left
};
unsigned int indices[] = { // note that we start from 0!
0, 1, 3, // first Triangle
1, 2, 3 // second Triangle
};
I'm passing to it a transformation matrix defined as follows
float translations[1600];
int index = 0;
float offset = 0.1f;
float width = 1.0f;
float height = 1.0f;
for (int y = -10; y < 10; y += 2)
{
float cy = ((float)y)/10.0f + offset;
for (int x = -10; x < 10; x += 2)
{
float angle = x * y;
float cx = ((float)x)/10.0f + offset;
float R[16] =
{ width * cos(angle), width * sin(angle), 0, 0, // first column
height * -sin(angle), height * cos(angle), 0, 0,
0, 0, 1.0f, 0,
cx, cy, 0, 1.0f}; // translation column
for (int i=0; i<16;i++) {
translations[index+i] = R[i];
}
index += 16;
}
}
However, when calling
glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0, 100);
I only get 25 rectangles. I can only get 100 if pass 400 as the amount to draw. Here is how I'm setting up the vertex attrib pointers:
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 4*sizeof(float), (void*)0);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 4*sizeof(float), (void*)(4*sizeof(float)));
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, 4*sizeof(float), (void*)(2*4*sizeof(float)));
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, 4*sizeof(float), (void*)(3*4*sizeof(float)));
glVertexAttribDivisor(1, 1);
glVertexAttribDivisor(2, 1);
glVertexAttribDivisor(3, 1);
glVertexAttribDivisor(4, 1);
Here is the full code
// store instance data in an array buffer
// --------------------------------------
float translations[1600];
int index = 0;
float offset = 0.1f;
float width = 1.0f;
float height = 1.0f;
for (int y = -10; y < 10; y += 2)
{
float cy = ((float)y)/10.0f + offset;
for (int x = -10; x < 10; x += 2)
{
float angle = x * y;
float cx = ((float)x)/10.0f + offset;
float R[16] =
{ width * cos(angle), width * sin(angle), 0, 0, // first column
height * -sin(angle), height * cos(angle), 0, 0,
0, 0, 1.0f, 0,
cx, cy, 0, 1.0f}; // translation column
for (int i=0; i<16;i++) {
translations[index+i] = R[i];
}
index += 16;
}
}
unsigned int instanceVBO;
glGenBuffers(1, &instanceVBO);
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(translations), translations, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
float vertices[] = {
0.05f, 0.05, // top right
0.05f, -0.05f, // bottom right
-0.05f, -0.05f, // bottom left
-0.05f, 0.05f // top left
};
unsigned int indices[] = { // note that we start from 0!
0, 1, 3, // first Triangle
1, 2, 3 // second Triangle
};
unsigned int VAO, VBO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
// bind the Vertex Array Object first, then bind and set vertex buffer(s),
// and then configure vertex attributes(s).
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// also set instance data
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO); // this attribute comes from a different vertex buffer
//glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
//glBindBuffer(GL_ARRAY_BUFFER, 0);
//glVertexAttribDivisor(1, 1); // tell OpenGL this is an instanced vertex attribute.
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 4*sizeof(float), (void*)0);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 4*sizeof(float), (void*)(4*sizeof(float)));
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, 4*sizeof(float), (void*)(2*4*sizeof(float)));
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, 4*sizeof(float), (void*)(3*4*sizeof(float)));
glVertexAttribDivisor(1, 1);
glVertexAttribDivisor(2, 1);
glVertexAttribDivisor(3, 1);
glVertexAttribDivisor(4, 1);
glBindVertexArray(0);
while (!glfwWindowShouldClose(window))
{
// input
// -----
process_input(window);
// render
// ------
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0, 100);
glBindVertexArray(0);
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
Shader
#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in mat4 transform;
out vec2 TexCoord;
void main()
{
gl_Position = transform * vec4(aPos, 0, 1.0);
}
I did find this question but the answer uses GL 4.2 and I'm not sure if the questions are the same. To write this code I followed learnopengl
's instancing chapter.