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:
glUseProgram(program)
within the loop.mvp
or the nmv
uniforms within the loop.lightDir
uniform within the loop.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");
Sometimes driver will optimize some of your uniforms (even if it should not especialy with older drivers). to test that try to use your material color in vertex shader (copy it to some varying variable and in fragment shader use that varying variable instead of uniform, that sometimes works for me,... of course it lower performance a bit)
try to use different profile version. In some cases newer drivers do not emulate older versions properly. Had you try core profile ? (i know its very tricky to implement with older code)
you can try nvemulate to test different driver settings
sometimes forgotten glEnd(); makes a lot of trouble try to add this code before your frame rendering code:
glEnd();
glEnd();
glEnd();
glEnd();
glEnd();
glEnd();
glEnd();
glEnd();
glEnd();
glEnd();
glEnd();
... here comes your rendering code
if this helps than you forgott to call glEnd(); somewhere or have glEnd; instead of glEnd();
[Edit1]
After your added the CPU side mesh draw related code its clear that you hard-coded all VBO and uniform
positions but your fragment and vertex shaders have not static locations anywhere see
and look for glGetUniformLocation
usage. Also in shaders you can state something like this:
layout(location = 0) in vec3 pos;
but that is for more recent GLSL in older version it might be a bit different and too lazy to search for syntax and keyword...
Still not solved?
what is the type of mesh.color
looking at the addresses passed into the call trace they seem rather high, perhaps you should be passing in an address to the data not the actual data, 0x7fab823000bc
glUniform3fv(materialColorLoc, 1, &mesh.color); perhaps try hard coding and using glUniform3f()
From all the addresses in the trace I'd guess any vec3 you send to GL are of type float name[3]
, aren't they? Assuming this I cannot spot an error in your code. As you stated there's no error-state returned by glGetError, it MUST be a driver bug.
I saw in the trace that you start every mesh doing a glBindBuffer(GL_ARRAY_BUFFER, 0) - this is not really necessary. But anyhow, I cannot imagine this to be the source, either.
Sadly, you cannot test stuff like glBindUniformLocation before linking, as that is not part of OpenGL.
My experience shows: if you issue a glUniform3fv and all parameters are correct, then the uniform is updated and that change is visible right away. As that is not the case, here, it must be a driver bug, so the only things you could possibly do is: add other unnecessary calls to your rendering loop to make the change visible (which you already did if I read this correctly).
User contributions licensed under CC BY-SA 3.0