c++openglglslshaderspecular

opengl shader directional lights specular reflection increasing with distance


the title says it all.. using opengls built in lighting system, specularlight does not increase or decrease with distance from the object, but by shader implementation does.

Vertex Shader:

#version 330

layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in vec3 normal;

out vec2 texCoord0;
out vec3 normal0;
out vec3 worldPos0;

uniform mat4 transform;
uniform mat4 normalRotation;
uniform mat4 transformProjected;

void main()
{
    gl_Position = transformProjected * vec4(position, 1.0);
    texCoord0 = texCoord;

    normal0 = normalize((normalRotation * vec4(normal, 0.0))).xyz;
    worldPos0 = (transform * vec4(position, 1.0)).xyz; 
}

Fragment Shader:

#version 330

in vec2 texCoord0;
in vec3 normal0;
in vec3 worldPos0;

out vec4 fragColor;

struct BaseLight
{
    vec3 colorDiffuse;
    vec3 colorSpecular;
    float intensityDiffuse;
};
struct DirectionalLight
{
    BaseLight base;
    vec3 direction;
};

uniform vec3 tint;
uniform sampler2D sampler;

uniform vec3 eyePos; // camera pos

uniform vec3 ambientLight;
uniform vec3 emissiveLight;

//material 
uniform float specularIntensity;
uniform float specularPower;

uniform DirectionalLight directionalLight;

vec4 calcLight(BaseLight base,vec3 direction, vec3 normal)
{
    float diffuseFactor = dot(normal, -direction);

    vec4 diffuseColorFinal = vec4(0,0,0,0);
    vec4 specularColorFinal = vec4(0,0,0,0);

    if(diffuseFactor > 0)
    {
      diffuseColorFinal =  vec4(base.colorDiffuse,1) * diffuseFactor * base.intensityDiffuse;

      vec3 directionToEye = normalize(eyePos - worldPos0);
      vec3 reflectDirection = normalize(reflect(direction, normal));

      float specularFactor = dot(directionToEye, reflectDirection);
      specularFactor = pow(specularFactor, specularPower);

      if(specularFactor > 0)
          specularColorFinal = vec4(base.colorSpecular,1) * specularFactor   * specularIntensity;
    }
    //
   return diffuseColorFinal + specularColorFinal;
}



void main()
{
    vec4 colorD = texture(sampler, texCoord0.xy) * vec4(tint,1);
    vec3 normal = normal0;
    vec4 totalLight = vec4(ambientLight,1) + vec4(emissiveLight,1); 

     totalLight += calcLight(directionalLight.base,-directionalLight.direction,normal);


    fragColor = colorD * totalLight;
}

enter image description here enter image description here

As you can see from the 2 images the specular light takes up a larger surface area the farther the camera gets from the plane.In my test with opengls built in lighting, this doesnt happen. is there a way to fix this? im new to lighting, maybe this is normal for directional light sources? thanks for the help!

Im also setting my eyePos uniform to my cameraPos. i dont know if that helps.


Solution

  • Basically you need to have distance between the fragment and the light dist . This can be a problem for directional light though because you have only the direction and distant is assumed to be infinite. Maybe switch to point light?

    when youo have the 'dist' you use a formula

    att = 1.0 / (Kc + Kl*dist + Kq*dist^2)
    Kc - constant attenuation
    Kl - linear attenuation
    Kq - quadratic attenuation 
    

    simpler version (only Kq used, rest set to 1.0):

    float attenuation = 1.0 / (1.0 + light.attenuation * pow(distanceToLight, 2));
    

    then in the lighting equation you basically multiply calculated color by this att factor:

    vec4 finalColor = ambient + (diffuseColorFinal + specularColorFinal)*att
    

    http://www.ozone3d.net/tutorials/glsl_lighting_phong_p4.php#part_4

    http://tomdalling.com/blog/modern-opengl/07-more-lighting-ambient-specular-attenuation-gamma/