Specular Lighting

We learned about how to apply diffuse lighting and ambient via shaders in the previous post. In this post, we are going to learn how to apply specular which is the last stage of Phong reflection model. The surface that the light hits can be made brighter via specular reflection.

Let's visualize it:

Specular Lighting
In short, the intensity of specular illumination on the surface changes according to the position of the camera. If you remember from the last post, we calculates diffuse intensity via dot product, and we are going use it again for specular. Also, we are going to use reflect method in the fragment shader of the cube. This method gives us reflection vector according to the normal vector. After we can configure the power of specular lighting with the pow method. The pow method here is used to set the size of the reflection. If we give small values then this reflection size will be bigger than according to big values. You can try each number and you will get it what I mean. Also I changed something about diffuse lighting and ambiend lighting in the fragment shader.

Firstly, we need to the position of the camera for specular lighting. I created a uniform for cameraPosition. Then I transform it according to the world position, and pass it to the fragment shader:
#version 330 core

layout(location = 0) in vec3 aPos;
layout(location = 1) in vec2 aTexCoord;
layout(location = 2) in vec3 aNormal;

uniform mat4 uTransform;
uniform mat4 projection;
uniform mat4 view;

uniform vec3 lightPosition;
uniform vec3 cameraPosition;

out vec2 passTexCoord;
out vec3 passNormal;
out vec3 lightVector;
out vec3 cameraVector;

void main()
    gl_Position = vec4(aPos, 1.0) * uTransform * view * projection;
    passTexCoord = aTexCoord;

    passNormal = (vec4(aNormal, 0.0) * uTransform).xyz;
    lightVector = lightPosition - (vec4(aPos, 1.0) * uTransform).xyz;
    cameraVector = cameraPosition - (vec4(aPos, 1.0) * uTransform).xyz;
This is the fragment shader. Briefly, it is explained in the comment lines.
#version 330 core

in vec2 passTexCoord;
in vec3 passNormal;
in vec3 lightVector;
in vec3 cameraVector;

out vec4 FragColor;

uniform sampler2D textureSampler;
uniform vec4 lightColor;

void main()
    // ambient lighting
    float ambient = 0.1;
    vec4 ambientColor = lightColor * ambient;
    // diffuse lighting
    vec3 normalizedNormal = normalize(passNormal);
    vec3 normalizedLightVector = normalize(lightVector);
    float calcDot = dot(normalizedNormal, normalizedLightVector);
    float brightness = max(calcDot, 0.0);
    float diffuse = brightness;
    vec4 diffuseColor = lightColor * diffuse;

    // specular lighting
    // this is instensity setting for reflection
    float reflectivity = 0.9;
    // reflection vector is opposite of the light vector so we need take it as negative
    // so we can find reflection vector according to the normal
    vec3 reflectionVector = reflect(-normalizedLightVector, normalizedNormal);
    vec3 normalizedReflectionVector = normalize(reflectionVector);
    vec3 normalizedCameraVector = normalize(cameraVector);
    float spec = dot(normalizedCameraVector, normalizedReflectionVector);
    float spec2 = max(spec, 0);
    // define size of reflection
    float specular = pow(spec2, 8);  
    vec4 specularColor = lightColor * specular * reflectivity;

    FragColor = texture(textureSampler, passTexCoord) * (ambientColor + diffuseColor + specularColor);
I updated the update method of the Camera class. Because we need to the camera position:
        public void Update()
            foreach (var shader in this.shaderManager.Shaders)
                int uniformLocation_cameraPosition = GL.GetUniformLocation(shader.Value.ShaderProgram, "cameraPosition");
                GL.Uniform3(uniformLocation_cameraPosition, Position);
Let's check the result:
specular lighting
Let's make the power 64:
Specular lighting
The difference can be seen.

No comments:

Post a Comment