Unresolved External

10-12-2014, 11:47 AM

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! :)

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! :)