1
\$\begingroup\$

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.

uniformlist

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;
}
\$\endgroup\$
  • 5
    \$\begingroup\$ What do you mean by "doesn't work"? Is the program crashing? Is it drawing the wrong colors? Is it drawing a blank screen? \$\endgroup\$ – Icy Defiance Oct 9 '14 at 20:17
  • \$\begingroup\$ You mention uniform indices rather than locations. It is easy to confuse the two (and sometimes they might happen to have the same value). Make sure you are using the values returned from glGetUniformLocation, and not the value you might pass as the second parameter to glGetActiveUniform. \$\endgroup\$ – GuyRT Oct 10 '14 at 14:44
  • \$\begingroup\$ @IcyDefiance a blank screen. \$\endgroup\$ – Unresolved External Oct 10 '14 at 21:43
  • \$\begingroup\$ @GuyRT Ok, I confused the two. I mean location not index. Inside "AddUniformLocation(...)" I'm using "glGetUniformLocation(program, name)" for retrieving the location. See edited code above. \$\endgroup\$ – Unresolved External Oct 10 '14 at 21:57
  • 1
    \$\begingroup\$ @davidvanbrink thanks for the reply. Yes, every time a program is created, I check glGetShaderInfoLog and print it to the screen. See update #3. \$\endgroup\$ – Unresolved External Oct 12 '14 at 13:10
2
\$\begingroup\$

glUniform*() only affects the currently bound program. Therefore one must call glUseProgram() before making any calls to glUniform*().

\$\endgroup\$
  • \$\begingroup\$ +1; for modern OpenGL the glProgramUniform calls are available too, which don't require a glUseProgram. \$\endgroup\$ – Maximus Minimus Dec 5 '14 at 0:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.