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:
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:
This is the fragment shader. Briefly, it is explained in the comment lines.
#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;
}
#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)
{
GL.UseProgram(shader.Value.ShaderProgram);
...
int uniformLocation_cameraPosition = GL.GetUniformLocation(shader.Value.ShaderProgram, "cameraPosition");
GL.Uniform3(uniformLocation_cameraPosition, Position);
}
}
Let's check the result:
Let's make the power 64:
The difference can be seen.
No comments:
Post a Comment