PDA

View Full Version : Problem with uniforms



Unresolved External
10-12-2014, 12:47 PM
I have a strange problem I can't figure out. On the CPU I have a class that handles the material properties for a model.



material = new Material();
material->Emissive = vec3(0.1, 0.0, 0.0);
material->Ambient = vec3(0.1, 0.0, 0.0);
material->Diffuse = vec3(1.0, 0.0, 0.0);
material->Specular = vec3(1.0, 1.0, 1.0);
material->Shininess = 10.0f;
material->Alpha = 1.0f;


To send them to the GPU, I have some methods in my Program class (a class for adding shaders, vertex attributes, uniforms etc):


program->Uniform3fv("uniEmissive", material->Emissive);
program->Uniform3fv("uniAmbient", material->Ambient);
program->Uniform3fv("uniDiffuse", material->Diffuse);
program->Uniform3fv("uniSpecular", material->Specular);
program->Uniform1f("uniShininess", material->Shininess);
program->Uniform1f("uniAlpha", material->Alpha);


Which internally looks like this



// This map stores names and locations for a uniform
map<GLchar*, GLint> uniformList;


void Program::Uniform3fv(GLchar *name, glm::vec3 value)
{
if (!UniformListContains(name))
{
AddUniformLocation(name);
}


if (UniformListContains(name))
{
glUniform3fv(uniformList[name], 1, glm::value_ptr(value));
}
}



void Program::AddUniformLocation(GLchar *name)
{
GLint location = glGetUniformLocation(program, name);


if (location != -1)
{
uniformList.insert(pair<GLchar*, GLint>(name, location));
}
else
{
printf("Error: the uniform \"%s\" doesn't exist, or isn't used, in program\n", name);
}
}



The uniformList is a map with name of the uniform in the shader and the location of the uniform. So first in this function it looks if it is in the list, if not it adds it. Then it uploads the value to the GPU, by looking in the uniformList for this name, and if found it retuns the location for the uniform. This is how the uniformList looks when everything for this program has been uploaded. Which seems correct to me, because none of the indices are -1.


1479

So, now to the problem. In my fragment shader I have this code


vec3 N = normalize(normal);
vec3 L = normalize(lightDir);
vec3 R = reflect(-L, N);
vec3 V = normalize(-position);

vec3 emissive = uniEmissive;
vec3 ambient = uniAmbient;
vec3 diffuse = uniDiffuse * max(dot(N, L), 0.0);
vec3 specular = uniSpecular * pow(max(dot(R, V), 0.0), uniShininess);

fragColor = vec4(emissive + ambient + diffuse + specular, uniAlpha);


This, doesn't work! But if I remove "emissive" it renders the model properly. Also, if I just use vec4(emissive, uniAlpha) it also renders the model, and with a very dark red color, which is correct.

Another way it is working is by "hard coding" the material properties in the shader, note: emissive is used here also.



vec3 Emissive = vec3(0.1, 0.0, 0.0);
vec3 Ambient = vec3(0.1, 0.0, 0.0);
vec3 Diffuse = vec3(1.0, 0.0, 0.0);
vec3 Specular = vec3(1.0, 1.0, 1.0);
float Shininess = 10.0;
float Alpha = 1.0;

vec3 emissive = Emissive;
vec3 ambient = Ambient;
vec3 diffuse = Diffuse * max(dot(N, L), 0.0);
vec3 specular = Specular * pow(max(dot(R, V), 0.0), Shininess);

fragColor = vec4(emissive + ambient + diffuse + specular, Alpha);


Also, I tried some other combinations with the uniforms, some of them works. Look at the comments in the code block below.



vec3 diffuse = uniDiffuse * max(dot(N, L), 0.0);
vec3 specular = uniSpecular * pow(max(dot(R, V), 0.0), uniShininess);

// This works, 1.0 instead of uniAlpha.
fragColor = vec4(uniEmissive + uniAmbient + diffuse + specular, 1.0);

// Doesn't work, added uniAlpha
fragColor = vec4(uniEmissive + uniAmbient + diffuse + specular, uniAlpha);

// These are working
fragColor = vec4(uniEmissive, uniAlpha);
fragColor = vec4(uniEmissive + uniAmbient, uniAlpha);
// Adding diffuse doesn't work.
fragColor = vec4(uniEmissive + uniAmbient + diffuse, uniAlpha);
// Just diffuse, works!
fragColor = vec4(diffuse, uniAlpha);


Also running glGetShaderInfoLog gives no errors. When I say not working I mean that the model isn't rendered at all. I hope someone has time to look through this, thanks in advance! :)

qnoper
10-12-2014, 05:09 PM
Hello :-).

Maybe you didn't call glUseProgram before yours uniform function?

For these "old school", I remembered I have some issues with glUniform if I didn't call glUseProgram before ^^.

And I'm sorry for my bad english ^_^.

Best regards, Qnoper.

Unresolved External
10-14-2014, 10:37 AM
Hi Qnoper! That did it, thank you!! I've been stuck with this problem for days!

Although it works, I cannot really see why some uniform combination worked before and some not. Also, the constructor for my program-class calls "glUseProgram" and no other program was used in between the call to the constructor and the uploading of the uniforms.



// This calls "glUseProgram", and program class has a private member that stores the program-id
program = new Program("coloredNew.vs.glsl", "coloredNew.fs.glsl");


vao = new VertexArray();


ebo = new ElementBuffer(elements, GL_STATIC_DRAW);


GLsizeiptr verticesSize = vertices.size() * sizeof(vertices[0]);
GLsizeiptr normalsSize = normals.size() * sizeof(normals[0]);
verticesCount = vertices.size();


vbo = new VertexBuffer(verticesSize + normalsSize, GL_STATIC_DRAW);
vbo->AddSubData(verticesSize, (GLfloat*)vertices.data());
vbo->AddSubData(normalsSize, (GLfloat*)normals.data());


program->VertexAttribPointerByIndex(0, 3, GL_FLOAT, verticesSize);
program->VertexAttribPointerByIndex(1, 3, GL_FLOAT, normalsSize);

// After qnoper's reply I added this line here, and now all uniforms can be used in the fs at the same time. Use-method wraps "glUseProgram"
program->Use();


program->UniformMatrix4fv("uniProj", Settings::ProjectionMatrix);
program->Uniform3fv("uniEmissive", material->Emissive);
program->Uniform3fv("uniAmbient", material->Ambient);
program->Uniform3fv("uniDiffuse", material->Diffuse);
program->Uniform3fv("uniSpecular", material->Specular);
program->Uniform1f("uniShininess", material->Shininess);
program->Uniform1f("uniAlpha", material->Alpha);


UPDATE: now I'm even more confused. Now I commented out "//program->Use();" and now it's working!

e_biddulph
10-19-2014, 08:13 AM
I suggest using glProgramUniform3fv (https://www.opengl.org/sdk/docs/man/html/glProgramUniform.xhtml) (which you don't need to call glUseProgram for) so that there's no requirement to call Use() and thus less chance of making an error.

GClements
10-19-2014, 04:21 PM
I suggest using glProgramUniform3fv (https://www.opengl.org/sdk/docs/man/html/glProgramUniform.xhtml)

Note that glProgramUniform requires OpenGL 4.1, which would be a bit excessive if the program is otherwise capable of working with OpenGL 2.0.