0
votes

I've been running into a weird phenomenon with my OpenGL 3.2 code. I'm drawing a series of objects, each of which has a 2D (color) texture and some fairly standard material settings (diffuse/specular color etc.) assigned to it, and I'd like to send the material settings to my fragment shader(s) via a uniform buffer. The GLSL declaration of the respective uniform block looks like this:

layout(std140) uniform MaterialBlock {
    vec4 diffuseColor, specularColor;
    float shininess, ambient, emission;
} material;

And this is what my render cycle looks like in pseudocode:

glUseProgram(objectShaderId);

for each object {

    // Set material
    glBindBuffer(GL_UNIFORM_BUFFER, materialBufferId);
    MaterialBlockPtr = glMapBuffer(GL_UNIFORM_BUFFER, GL_WRITE_ONLY);
    <set object's material values via MaterialBlockPtr>
    glUnmapBuffer(GL_UNIFORM_BUFFER);

    // Set texture
    glBindTexture(GL_TEXTURE_2D, textureId);

    // Draw
    glBindVertexArray(object.vertexArrayId);
    glDrawElements(GL_TRIANGLES, object.faceCount, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);

}

This all works well enough as long as a) only a single object is on screen, or b) all objects using this shader share the same material settings, or c) the other objects use a different shader.

As soon as two objects use the same shader, but have different material settings (e.g. one has a blue, one has a green diffuse color), and both are in the frame, they start to flicker like crazy – each one switching between its own material settings and those of the other object seemingly at random. Obviously, some of the drawing happens with the material values of the previous call still in the uniform buffer, but why? Have I missed something essential about uniform buffers? Can calls to glDraw* somehow overlap my writing data to the buffer, or can the contents of the buffer influence what's on screen after the call to glDraw* took place?

For the record, I'm developing this on OS X 10.7.5 on a GeForce GT650M.

1
Does the problem go away if you call glFlush() after drawing each object?user1118321

1 Answers

1
votes

ok Im pretty sure that there is something very wrong with this:

layout(std140) uniform MaterialBlock {
    vec4 diffuseColor, specularColor;
    float shininess, ambient, emission;
} material

Im very sure that material ambient and emission being themselves colours were supposed to also be declared as vec4 arrays, I suspect in your drawing code you have something like

//this is just an example and assumption
float material_ambient[4];
float material_emmission[4];
//to setup material ambient and emmissive colour
material_ambient = {1.0, 1.0, 1.0, 1.0};
material_emmision = {1.0, 1.0, 1.0, 1.0};

glUniform4f(material_ambient_id, material_ambient[0], material_ambient[1], material_ambient[2], material_ambient[3]);
glUniform4f(material_emissive_id, material_emissive[0], material_emissive[1], material_emissive[2], material_emissive[3]);

and the very obvious problem here would be that you'd be trying to send 4 element arrays to float variables in the shaders...hope this helps