I have an extremely basic GLSL program which is failing to properly update a uniform value after the first draw call. No errors are received from glGetError
, no errors are reported in the info logs when compiling and linking the shaders, and all uniform locations are valid.
Vertex shader:
#version 120
uniform mat4 mvp;
uniform mat3 nmv;
attribute vec3 position;
attribute vec3 normal;
varying vec3 v_normal;
void main()
{
v_normal = normalize(nmv * normal);
gl_Position = mvp * vec4(position, 1.0);
}
Fragment shader:
#version 120
uniform vec3 lightDir;
uniform vec3 lightColor;
uniform vec3 materialColor;
varying vec3 v_normal;
void main()
{
vec3 n = normalize(v_normal);
float nDotL = max(0.0, dot(n, lightDir));
gl_FragColor = vec4(materialColor * lightColor * nDotL, 1.0);
}
Rendering code:
glUseProgram(program);
glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, mvp);
glUniformMatrix3fv(nmvLoc, 1, GL_FALSE, nmv);
glUniform3fv(lightDirLoc, 1, lightDir);
glUniform3fv(lightColorLoc, 1, lightColor);
for (auto mesh: meshes)
{
glUniform3fv(materialColorLoc, 1, mesh.color);
mesh.draw();
}
The rendered meshes are all drawn in the color of the first mesh, indicating that after initially setting the materialColor
uniform, the subsequent calls to change the uniform are ignored. However, here is a list of special conditions which independently allow the uniform to be updated properly:
- Calling
glUseProgram(program)
within the loop. - Setting the
mvp
or thenmv
uniforms within the loop. - Setting the
lightDir
uniform within the loop. - Removing one of the
uniform vec3
s from the shader program.
Please note that setting the lightColor
uniform within the loop will not update the materialColor
uniform. I have also checked GL_CURRENT_PROGRAM
within the loop, and the shader remains bound throughout.
I have been trying to fix this for hours and absolutely cannot find the issue. This shader setup is so simple that I don't believe it's a driver bug. I'm using OpenGL 2.1 on Mac OS X 10.8.3 with a NVIDIA GeForce 9400M.
Here is a call trace for a single frame:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(1);
glUniformMatrix4fv(1, 1, 0, 0x7fff55512550); // mvp
glUniformMatrix3fv(5, 1, 0, 0x7fff55512528); // nmv
glUniform3fv(0, 1, 0x7fff55512670); // lightDir
glUniform3fv(9, 1, 0x7fff555124e8); // lightColor
// Mesh 0
glUniform3fv(8, 1, 0x7fab820cd7ec); // materialColor
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 1);
glEnableVertexAttribArray(0);
glVertexAttribPointerARB(0, 3, GL_FLOAT, 0, 24, 0x00000000);
glEnableVertexAttribArray(2);
glVertexAttribPointerARB(2, 3, GL_FLOAT, 0, 24, 0x0000000c);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 21);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// Mesh 1
glUniform3fv(8, 1, 0x7fab823000bc); // materialColor
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 2);
glEnableVertexAttribArray(0);
glVertexAttribPointerARB(0, 3, GL_FLOAT, 0, 24, 0x00000000);
glEnableVertexAttribArray(2);
glVertexAttribPointerARB(2, 3, GL_FLOAT, 0, 24, 0x0000000c);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 24);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// Mesh 2
glUniform3fv(8, 1, 0x7fab8231f8fc); // materialColor
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 3);
glEnableVertexAttribArray(0);
glVertexAttribPointerARB(0, 3, GL_FLOAT, 0, 24, 0x00000000);
glEnableVertexAttribArray(2);
glVertexAttribPointerARB(2, 3, GL_FLOAT, 0, 24, 0x0000000c);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 21);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// Mesh 3
glUniform3fv(8, 1, 0x7fab820cf41c); // materialColor
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 4);
glEnableVertexAttribArray(0);
glVertexAttribPointerARB(0, 3, GL_FLOAT, 0, 24, 0x00000000);
glEnableVertexAttribArray(2);
glVertexAttribPointerARB(2, 3, GL_FLOAT, 0, 24, 0x0000000c);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 18);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
CGLFlushDrawable();
EDIT: Here is the code used to obtain the uniform locations. It is performed after the shaders have been compiled and linked, and all uniforms are verified to be valid.
GLint mvpLoc = glGetUniformLocation(program, "mvp");
GLint nmvLoc = glGetUniformLocation(program, "nmv");
GLint lightDirLoc = glGetUniformLocation(program, "lightDir");
GLint lightColorLoc = glGetUniformLocation(program, "lightColor");
GLint materialColorLoc = glGetUniformLocation(program, "materialColor");