I am learning how to use glDrawElementsInstanced() based on this tutorial:
The geometry renders without any problems:
But I am struggling to understand how this function actually works.
Questions:
1). When calling glVertexAttribPointer(), the data from the transformation matrices is sent down 4 floats at a time (due to the fact that each attribute can contain no more than 4 components), meaning that the transformation matrix data is spread across 4 attributes (2,3,4,5 - 1 column of the matrix per attribute) . The stride is set the sizeof(glm::mat4) which is 64 bytes. But being that in this case, 4 floats make up 1 attribute, shouldn't the stride for attributes 2,3,4,5 be set to (sizeof(float) * 4)?
2). Following on from the previous question; in the vertex shader, the attribute transform_matrix is said to be at location 2, rather than spread across 2,3,4,5. That being the case:
a). How does GLSL interpret this? The attribute is received in the shader as a mat4 at location 2, but as previously mentioned, the attributes are actually spread across the locations 2,3,4,5 as floats so how is it that GLSL was able to condense these 4 floats across 4 attributes to just 1 mat4 across 1 attribute?
b). How does the shader know when to switch from the first transformation matrix (index 0 of transform_matrix array) to the second transformation matrix (index 1 of transform_matrix array) in order to render the two geometries in different places (as show in above image)? I assume this has something to do with the call to glDrawElementsInstanced() but I'm not sure as to how exactly this would work in the shader. Maybe someone can provide some detail on how this process works?
See the relevant source code below:
// Main.cpp:
std::array<glm::mat4, 2> transform_matrix =
{
MVP.projection.matrix * glm::translate(glm::mat4(1.0F), glm::vec3(-0.8F, 0.0F, -3.0F)) // 0
* glm::rotate(glm::mat4(1.0F), glm::radians(24.0F), glm::vec3(1.0F, 0.0F, 0.0F)),
MVP.projection.matrix * glm::translate(glm::mat4(1.0F), glm::vec3(2.2F, 0.0F, -3.8F)) // 1
* glm::rotate(glm::mat4(1.0F), glm::radians(115.0F), glm::vec3(0.0F, 1.0F, 0.0F))
};
unsigned int transform_vbo;
glGenBuffers(1, &transform_vbo);
glBindBuffer(GL_ARRAY_BUFFER,transform_vbo);
glNamedBufferData(transform_vbo, sizeof(transform_matrix), &transform_matrix, GL_STATIC_DRAW);
// positions (0) and colour (1) attributes already sent to OpenGL:
for (int i = 2; i < 6; i++)
{
glEnableVertexAttribArray(i);
glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4),
(const void*)(sizeof(float) * ((i - 2)*4)));
glVertexAttribDivisor(i, 1);
}
Cube_VAO.Bind();
while (!glfw.WindowShouldClose())
{
shader.ClearBuffers(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glfw.ResizeWindow(MVP);
glDrawElementsInstanced(GL_TRIANGLES, CubeIndices.size(), GL_UNSIGNED_SHORT, 0, 2);
glfw.SwapBuffers();
}
// Shader.glsl:
#vertex shader
#version 330 core
layout(location = 0) in vec4 position;
layout(location = 1) in vec4 colours;
layout(location = 2) in mat4 transform_matrix;
out vec4 colour_transfer;
void main()
{
gl_Position = transform_matrix * position;
colour_transfer = colours;
};
#fragment shader
#version 330 core
in vec4 colour_transfer;
out vec4 colour;
void main()
{
colour = colour_transfer;
};
..