I have a strange problem I can't figure out. On the CPU I have 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 indexes 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));
}
}
The "uniformList" is a map with name of the uniform in the shader and the index 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 index 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.
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);
Regarding this I don't believe the problem is in the fragment shader itself, but probably something with the upload of the uniforms. I hope someone has time to look through this, thanks in advance! :)
UPDATE #1: showing below how I retrieve the uniform location:
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);
}
}
UPDATE #2: I'm writing some scenarios here, some works, some doesn't (by working I mean the model is rendered). I'm getting insane, I really hope it isn't something very silly that is wrong. :)
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);
UPDATE #3:
bool Program::ShaderInfoLog(GLuint shader, GLenum shaderType)
{
GLint compiled;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if (!compiled)
{
GLsizei length;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
GLchar* log = new GLchar[length+1];
glGetShaderInfoLog(shader, length, &length, log);
cerr << GetShaderType(shaderType) << ": " << endl << log << endl;
delete[] log;
return false;
}
return true;
}
glGetUniformLocation
, and not the value you might pass as the second parameter toglGetActiveUniform
. \$\endgroup\$glGetShaderInfoLog
and print it to the screen. See update #3. \$\endgroup\$