I implemented lighting in my engine. But there is some problem the object does not lights up properly The specular lighting does not work at all
Here is the vertex shader :
#version 330
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 tex_coords;
layout (location = 2) in vec3 normals;
uniform mat4 projectionMatrix;
uniform mat4 worldMatrix;
uniform mat4 viewMatrix;
out vec2 coords;
out vec3 vertexNormals;
out vec3 vertexPos;
void main() {
vec4 mVerPos = worldMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * viewMatrix * worldMatrix * vec4(position, 1.0);
coords = tex_coords;
vertexNormals = normalize(worldMatrix * vec4(normals, 0.0)).xyz;
vertexPos = mVerPos.xyz;
}
Here is the fragment shader :
#version 330
struct Material {
vec4 ambient;
vec4 diffuse;
vec4 specular;
int hasTexture;
float reflectance;
};
struct PointLight {
vec3 color;
vec3 position;
float intensity;
float constant;
float linear;
float exponent;
};
struct DirLight {
vec3 position;
vec3 color;
float intensity;
};
out vec4 fragColor;
in vec2 coords;
in vec3 vertexNormals;
in vec3 vertexPos;
uniform sampler2D sampler;
uniform vec3 ambientColor;
uniform Material material;
uniform PointLight pointLight;
uniform float specularPower;
uniform DirLight dirLight;
vec4 ambientC;
vec4 diffuseC;
vec4 specularC;
void setUpColor(Material material, vec2 coords) {
if (material.hasTexture == 1) {
ambientC = texture(sampler, coords);
diffuseC = ambientC;
specularC = ambientC;
}
else {
ambientC = material.ambient;
diffuseC = material.diffuse;
specularC = material.specular;
}
}
vec4 calcLightColor(vec3 lightColor, float lightIntensity, vec3 position, vec3 to_light_dir, vec3 normal) {
vec4 diffuseColour = vec4(0, 0, 0, 0);
vec4 specColour = vec4(0, 0, 0, 0);
// Diffuse Light
float diffuseFactor = max(dot(normal, to_light_dir ), 0.0);
diffuseColour = diffuseC * vec4(lightColor, 1.0) * lightIntensity * diffuseFactor;
// Specular Light
vec3 camera_direction = normalize(-position);
vec3 from_light_dir = -to_light_dir;
vec3 reflected_light = normalize(reflect(from_light_dir, normal));
float specularFactor = max(dot(camera_direction, reflected_light), 0.0);
specularFactor = pow(specularFactor, specularPower);
specColour = specularC * lightIntensity * specularFactor * material.reflectance * vec4(lightColor, 1.0);
return (diffuseColour + specColour);
};
vec4 calcPointLight(PointLight light, vec3 position, vec3 normal)
{
vec3 light_direction = light.position - position;
vec3 to_light_source = normalize(light_direction);
vec4 lightColor = calcLightColor(light.color, light.intensity, position, to_light_source, normal);
// Attenuation
float distance = length(light_direction);
float attenuationInv = light.constant + light.linear * distance +
light.exponent * distance * distance;
return lightColor / attenuationInv;
}
vec4 calcDirLight(DirLight light, vec3 position, vec3 normal) {
return calcLightColor(light.color, light.intensity, position, normalize(light.position), normal);
}
void main() {
setUpColor(material, coords);
vec4 diffuseSpecularComp = calcDirLight(dirLight, vertexPos, vertexNormals);
diffuseSpecularComp += calcPointLight(pointLight, vertexPos, vertexNormals);
fragColor = ambientC * vec4(ambientColor, 1) + diffuseSpecularComp;
}
Here is the source code : https://www.dropbox.com/scl/fo/hwlnz913jm6c9xli2dsb6/h?dl=0&rlkey=b2zj0w6kttwu3b1di9rejwnq3
When I changed the value of zero at float diffuseFactor = max(dot(normal, to_light_dir ), 0.0);
and at float specularFactor = max(dot(camera_direction, reflected_light), 0.0);
the to something above like 0.1
this what I get but the specular does not work at all.
There are a couple of problems in your code, but I'm not entirely sure which causes the problem.
vertexNormals
correctly. It shouldn't be a problem in your specific case, because seemingly you don't scale your mesh nonuniformly, but it's worth mentioning because it's a common mistake. You multiply the object space normal with the world matrix, but you should instead multiply it with the inverse transposed of the world matrix.vertexNormals
, but it's not correct. Although you normalized the normal in the vertex shader, but the fragment shader doesn't get that specific vector. It gets the linear interpolation (basically a weighted average) of the 3 vertexNormals
and the result is not necessarily normalized. So you should normalize it in the fragment shader as well.setUpColor
function, why do you assign the same value to ambientC
, diffuseC
, and specularC
? Usually, there are different textures for these, but at least for diffuse and specular.position
twice with worldMatrix
, but why? It seems like wasted performance (maybe the compiler optimizes it).DirLight
struct you have a position
member, but directional lights don't have a position, they just have a direction. I see that you compute the direction from the position, but it seems unusual.Material
struct (and in other places) you use vec4
s instead of vec3
s, but I guess, the last components are always ones. It's a waste of memory, you could just set the alpha value to 1.0f
at the end of main
.Joey de Vries has amazing tutorials, including the Phong shading (using C++). In the One last thing section he also explains why it's important to use the inverse transposed matrix to transform the normal.