I'm trying to separate the vertex format specification from the vertex data. I was able to do that for the mesh vertices successfully. For instanced rendering I wanted to further separate the instance data (i.e. model matrices). Here is what I'm trying out, but nothing is rendered.
Loading the data:
glGenBuffers(1, &vbo_instanced);
glBindBuffer(GL_ARRAY_BUFFER, vbo_instanced);
glBufferData(GL_ARRAY_BUFFER, n_instances * sizeof(glm::mat4), ModelArray, GL_STATIC_DRAW);
Vertex format:
glGenVertexArrays(1, &vao_instanced);
glBindVertexArray(vao_instanced);
glEnableVertexAttribArray(0);
glVertexAttribFormat(0, 3, GL_FLOAT, GL_FALSE, 0);
glVertexAttribBinding(0, 0);
glEnableVertexAttribArray(1);
glVertexAttribFormat(1, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3));
glVertexAttribBinding(1, 0);
glVertexBindingDivisor(1, 1);
for(int i = 0; i < 4; i++){ //Model Matrices
glEnableVertexAttribArray(2 + i);
glVertexAttribBinding(2 + i, 1);
glVertexAttribFormat(2 + i, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4));
}
When rendering I do the following,
glBindVertexArray(vao_instanced);
glBindVertexBuffer(0, vbo_mesh, 0, sizeof(Vertex));
glBindVertexBuffer(1, vbo_instanced, 0, sizeof(glm::mat4));
glDrawArraysInstanced(GL_TRIANGLES, 0, n_vertices, n_instances);
but I'm pretty sure the stride argument in glBindVertexBuffer
of vbo_instanced
should be wrong because it is the stride per vertex.
Does anyone know what I'm doing wrong and how to fix it?
EDIT 1: It seems I made a mistake in the last argument of glVertexAttribFormat
, it should instead be,
glVertexAttribFormat(2 + i, 4, GL_FLOAT, GL_FALSE, 4 * i * sizeof(float));
But now, although everything gets rendered, my normals are wrong. Even if I don't transform them, they have a single value per instance instead of a single value per face.
This is what the normals look like,
And this is what it should actually look like,
Note that the normals are fine as long as I instead use the glVertexAttribPointer
method, i.e. bind the vbo_instanced
directly to the vao.
For reference, here is how I declare the attributes in my shader,
#version 330 core
layout(location = 0) in vec3 in_Position;
layout(location = 1) in vec3 in_Normal;
layout(location = 2) in mat4 ModelMatrix;
EDIT 2: I wanted to add that I have checked that all offset values are correct. Additionally, I used apitrace and checked that all vertex buffer data are correctly uploaded. Valgrind also doesn't show any errors.
Now for a weird finding, if I don't use vertex attribute array with index 1 and instead bind vertex positions at 0, vertex normals at 2, and Model Matrices at 3, everything is rendering correctly. Could this be some driver bug? I tried on two linux systems, both having nvidia gpus, with exactly the same results.
EDIT 3: I put together a minimal working example which you can find here. It uses SDL and GLEW and is written in C++11. If I set SKIP
to 1 (which means it skips attribute 1), I get what I expect, but if I set it to 0, the normals become messed up.
in_Position
andModelMatrix
are okay, exceptin_Normal
. In your code you setglVertexBindingDivisor(1, 1);
- which refers toin_Normal
location. What happen if you remove this or add divisors for others bindings? \$\endgroup\$glVertexBindingDivisor
refers to the binding index, the vbo is bound to index 1 whenglBindVertexBuffer
is called. But I will try it out just in case. \$\endgroup\$VertexAttribBinding
calls that associate attribute indices with buffer indices. It's not at all uncommon to have multiple attributes refer to a single interleaved or concatenated buffer via offsets and strides. \$\endgroup\$