Ajinkya Sanas
Ajinkya Sanas

Reputation: 25

Specular lighting in LWJGL 3 not working [Phong Shading]

I implemented lighting in my engine. But there is some problem the object does not lights up properly The object that gets rendered 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 Later result but the specular does not work at all.

Upvotes: 1

Views: 80

Answers (1)

racz16
racz16

Reputation: 721

There are a couple of problems in your code, but I'm not entirely sure which causes the problem.

Problems

  • In the vertex shader, you don't calculate 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.
  • In the fragment shader you use directly the 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.
  • In the 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.

Other random observations

  • In the vertex shader, you multiply the position twice with worldMatrix, but why? It seems like wasted performance (maybe the compiler optimizes it).
  • In the 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.
  • In the same vein the camera is always at the origin and the directional light's direction always points to the origin. If it's intentional, it's okay, it just seems unusual.
  • In the Material struct (and in other places) you use vec4s instead of vec3s, 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.

Upvotes: 0

Related Questions