Trouble with Specular Lighting in OpenGL

1.3k Views Asked by At

I'm having some issues with my specular lighting, I have ambient and diffuse but I am now looking at specular to try make a nice looking model.

I have the following in my vertexShader:

#version 330

layout (location = 0) in vec3 Position;
layout (location = 1) in vec3 Normal;

out vec4 Colour0;

// Transforms
uniform mat4 gModelToWorldTransform;
uniform mat4 gWorldToViewToProjectionTransform;

// Ambient light parameters
uniform vec3 gAmbientLightIntensity;

// Directional light parameters
uniform vec3 gDirectionalLightIntensity;
uniform vec3 gDirectionalLightDirection;

// Material constants
uniform float gKa;
uniform float gKd;
uniform float gKs;
uniform float gKsStrength;

                                                                   
void main()
{  
    // Transform the vertex from local space to homogeneous clip space 
    vec4 vertexPositionInModelSpace = vec4(Position, 1);
    vec4 vertexInWorldSpace = gModelToWorldTransform * vertexPositionInModelSpace;
    vec4 vertexInHomogeneousClipSpace = gWorldToViewToProjectionTransform * vertexInWorldSpace;
    gl_Position = vertexInHomogeneousClipSpace;

    // Calculate the directional light intensity at the vertex
    // Find the normal in world space and normalise it
    vec3 normalInWorldSpace = (gModelToWorldTransform * vec4(Normal, 0.0)).xyz;
    normalInWorldSpace = normalize(normalInWorldSpace);

    // Calculate the ambient light intensity at the vertex
    // Ia = Ka * ambientLightIntensity
    vec4 ambientLightIntensity = gKa * vec4(gAmbientLightIntensity, 1.0);

    // Setup the light direction and normalise it
    vec3 lightDirection = normalize(-gDirectionalLightDirection);
    
    //lightDirection = normalize(gDirectionalLightDirection);
    // Id = kd * lightItensity * N.L
    // Calculate N.L
    float diffuseFactor = dot(normalInWorldSpace, lightDirection);
    diffuseFactor = clamp(diffuseFactor, 0.0, 1.0);

    // N.L * light source colour * intensity
    vec4 diffuseLightIntensity = gKd * vec4(gDirectionalLightIntensity, 1.0f) * diffuseFactor;

    vec3 lightReflect = normalize(reflect(gDirectionalLightDirection, Normal));

    //Calculate the specular light intensity at the vertex
    float specularFactor = dot(normalInWorldSpace, lightReflect);
    specularFactor = pow(specularFactor, gKsStrength);
    vec4 specularLightIntensity = gKs * vec4(gDirectionalLightIntensity, 1.0f) * specularFactor;
   
    // Final vertex colour is the product of the vertex colour
    // and the total light intensity at the vertex 

    vec4 colour = vec4(0.0, 1.0, 0.0, 1.0);
    Colour0 = colour * (ambientLightIntensity + diffuseLightIntensity + specularLightIntensity);
}

Then in my main.cpp I have the some code to try and get this working together, the specular light is definitely doing something, only, rather than making the model look shiny, it seems to intensify the light to the point where I can't see any details.

I create the following variables:

// Lighting uniforms location

GLuint gAmbientLightIntensityLoc;
GLuint gDirectionalLightIntensityLoc;
GLuint gDirectionalLightDirectionLoc;
GLuint gSpecularLightIntensityLoc;

// Materials uniform location
GLuint gKaLoc;
GLuint gKdLoc;
GLuint gKsLoc;
GLuint gKsStrengthLoc;

I then set my variables like so in the renderSceneCallBack() function which is called in the main:

// Set the material properties
glUniform1f(gKaLoc, 0.2f); 
glUniform1f(gKdLoc, 0.9f);
glUniform1f(gKsLoc, 0.5f);
glUniform1f(gKsStrengthLoc, 0.5f);

I then create a initLights() function which I would like to handle all lighting, this is also called in the main:

static void initLights()
{
    // Setup the ambient light
    vec3 ambientLightIntensity = vec3(0.2f, 0.2f, 0.2f);
    glUniform3fv(gAmbientLightIntensityLoc, 1, &ambientLightIntensity[0]);
    
    // Setup the direactional light
    vec3 directionalLightDirection = vec3(0.0f, 0.0f, -1.0f);
    normalize(directionalLightDirection);
    glUniform3fv(gDirectionalLightDirectionLoc, 1, &directionalLightDirection[0]);

    vec3 directionalLightIntensity = vec3(0.8f, 0.8f, 0.8f);
    glUniform3fv(gDirectionalLightIntensityLoc, 1, &directionalLightIntensity[0]);

    //Setup the specular Light
    vec3 specularLightIntensity = vec3(0.5f, 0.5f, 0.5f);
    glUniform3fv(gSpecularLightIntensityLoc, 1, &specularLightIntensity[0]);
}

Can anyone see what I might be doing wrong, I could have some of the calculatiuons wrong and I just don't see it. Both the ambient/diffuse lighting are working correctly. This photo illustrates whats currently happening, ambient on the left, diffuse in the middle and specular with strength set to 30 on the right.

enter image description here

Answer

I forgot to pass this value into the main:

gKsStrengthLoc = glGetUniformLocation(shaderProgram, "gKsStrength");
    //assert(gDirectionalLightDirectionLoc != 0xFFFFFFFF);

Everything works now using the answer selected

1

There are 1 best solutions below

2
On BEST ANSWER

Your value for gKsStrength looks way too small:

glUniform1f(gKsStrengthLoc, 0.5f);

This value controls how shiny the object is, with higher values making it more shiny. This makes sense if you look at the calculation in the shader:

specularFactor = pow(specularFactor, gKsStrength);

The larger the exponent, the faster the value drops off, which means that the specular highlight becomes more narrow.

Typical values might be something like 10.0f for moderately shiny, 30.0f for quite shiny, and even higher for very shiny materials.

With your value of 0.5f, you get a very wide specular "highlight". Your value for the specular intensity is also fairly high (0.5), so the highlight is going to cover most of the object, and saturate the colors for large parts.