سؤال

I am having troubles getting the correct output from my OpenGL application after switching from normal drawing with VBOs/VAOs to instanced arrays with VBOs/VAOs. The output is supposed to be a bunch of spheres, but instead it's crazy positioned vertices forming strange triangles. I've checked the vertex positions in the debugger console, but there didn't seem to be anything suspicious. They were all in the range from -10 to 10 and in the scene they are going to probably +/-30.

Here are the important parts of my code. Please tell me if I am not seeing something. I would greatly appreciate it!

char const *attribInSphereModelMatrix = "inSphereModelMatrix";
std::vector<glm::mat4> dNodesModelMatrices;

...

attributes[ATTRIB_SPHERE_MODEL_COLUMN0] = shader->getAttribLocation(attribInSphereModelMatrix);
attributes[ATTRIB_SPHERE_MODEL_COLUMN1] = attributes[ATTRIB_SPHERE_MODEL_COLUMN0] + 1;
attributes[ATTRIB_SPHERE_MODEL_COLUMN2] = attributes[ATTRIB_SPHERE_MODEL_COLUMN0] + 2;
attributes[ATTRIB_SPHERE_MODEL_COLUMN3] = attributes[ATTRIB_SPHERE_MODEL_COLUMN0] + 3;

...

// Create the vertex array object
glGenVertexArrays(1, &sphereVertexArray);
glBindVertexArray(sphereVertexArray);

// Create the buffer object to hold the sphere view matrix
glGenBuffers(1, &sphereModelMatrixBuffer);
glBindBuffer(GL_ARRAY_BUFFER, sphereModelMatrixBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::mat4) * dNodes.size(), &dNodesModelMatrices[0], GL_STATIC_DRAW);

// All matrix data is in one VBO, set the appropriate offsets
glEnableVertexAttribArray(attributes[ATTRIB_SPHERE_MODEL_COLUMN0]);
glVertexAttribPointer(attributes[ATTRIB_SPHERE_MODEL_COLUMN0], 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), NULL);
glVertexAttribDivisorARB(attributes[ATTRIB_SPHERE_MODEL_COLUMN0], 1);

glEnableVertexAttribArray(attributes[ATTRIB_SPHERE_MODEL_COLUMN1]);
glVertexAttribPointer(attributes[ATTRIB_SPHERE_MODEL_COLUMN1], 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (const GLvoid *)(sizeof(glm::vec4)));
glVertexAttribDivisorARB(attributes[ATTRIB_SPHERE_MODEL_COLUMN1], 1);

glEnableVertexAttribArray(attributes[ATTRIB_SPHERE_MODEL_COLUMN2]);
glVertexAttribPointer(attributes[ATTRIB_SPHERE_MODEL_COLUMN2], 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (const GLvoid *)(2 * sizeof(glm::vec4)));
glVertexAttribDivisorARB(attributes[ATTRIB_SPHERE_MODEL_COLUMN2], 1);

glEnableVertexAttribArray(attributes[ATTRIB_SPHERE_MODEL_COLUMN3]);
glVertexAttribPointer(attributes[ATTRIB_SPHERE_MODEL_COLUMN3], 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (const GLvoid *)(3 * sizeof(glm::vec4)));
glVertexAttribDivisorARB(attributes[ATTRIB_SPHERE_MODEL_COLUMN3], 1);

Once I'm ready with the setup I go to the drawing.

glEnableVertexAttribArray(attributes[ATTRIB_SPHERE_MODEL_COLUMN0]);
glEnableVertexAttribArray(attributes[ATTRIB_SPHERE_MODEL_COLUMN1]);
glEnableVertexAttribArray(attributes[ATTRIB_SPHERE_MODEL_COLUMN2]);
glEnableVertexAttribArray(attributes[ATTRIB_SPHERE_MODEL_COLUMN3]);

...

glDrawElementsInstanced(GL_TRIANGLES, numSphereTris, GL_UNSIGNED_INT, NULL, (int)dNodes.size());

And here are the important parts of the vertex shader:

in mat4 inSphereModelMatrix;

...

void main()
{
    vec4 v = vec4(inPosition, 1.0);
    mat4 modelViewMatrix = viewMatrix * inSphereModelMatrix;

    ...

    gl_Position = projectionMatrix * modelViewMatrix * v;
}

The result looks like this:

end result

Please help me somehow. I've been struggling with this for the past 3 days. Thank you all!

EDIT: I have been wondering if it had something to do with the column/row major order, so I've tried transposing the matrix, but I came to the conclusion that was not what's causing the issue.

هل كانت مفيدة؟

المحلول

I've got it! I have tried using a texture buffer object and gl_InstanceID inside the shaders to actually fetch the matrix columns and it worked! I can't believe how something equivalent to what I have previously done should not work and using texture buffer objects (TBOs) works... However, I am going to post the important parts of the code for future references.

/// A texture buffer object to pass to the shaders
GLuint sphereModelMatrixTBO;

/// A texture holding the matrices data
GLuint sphereModelMatrixTex;
.
.
.
/// Vector containing the model matrices of the spheres
std::vector<glm::mat4> dNodesModelMatrices;
.
.
.
glGenBuffers(1, &sphereModelMatrixTBO);
glBindBuffer(GL_TEXTURE_BUFFER, sphereModelMatrixTBO);
glBufferData(GL_TEXTURE_BUFFER, sizeof(glm::mat4) * dNodes.size(), &dNodesModelMatrices[0], GL_STATIC_DRAW);

And in the draw routine I do the following:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_BUFFER, sphereModelMatrixTex);
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, sphereModelMatrixTBO);

glUniform1i(uniforms[UNIFORM_MODEL_MATRIX_BUFFER], 0);
.
.
.
glDrawElementsInstanced(GL_TRIANGLES, numSphereTris, GL_UNSIGNED_INT, NULL, (int)dNodes.size());

The vertex shader looks now as following:

uniform samplerBuffer sphereModelMatrixBuffer;
.
.
.
vec4 col1 = texelFetch(sphereModelMatrixBuffer, gl_InstanceID * 4);
vec4 col2 = texelFetch(sphereModelMatrixBuffer, gl_InstanceID * 4 + 1);
vec4 col3 = texelFetch(sphereModelMatrixBuffer, gl_InstanceID * 4 + 2);
vec4 col4 = texelFetch(sphereModelMatrixBuffer, gl_InstanceID * 4 + 3);
mat4 modelMatrix = mat4(col1, col2, col3, col4);

And that's all you need to do to have a fully functioning fast OpenGL application! This is how it looks like now:

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top