I have implemented Blinn-Phong shading in my fragment shader to calculate the lighting of each fragment with multiple lights. The computation seems to be all good except for one part. My directional light is computed correctly but my position light is not.
Pictures talk more than word so:
Wrong light positions:
The shader works like this:
I update the light array with their positions in world space. And then for each object, I upload their material information and draw them using this fragment shader to get the correct color. The vertex shader's only task (regarding lighting) is to pass on normals for the fragment. All my computation are done in world space.
I already checked the position of each light and they are correct. Which is why I came here. I think I made a mistake when I compute the cosine of the incident angle but I don't know where.
Here is the code of my fragment shader:
Edit : I corrected some mistakes with the nice help of Nico Schertler, here is the new code with both fragment and vertex shader
Edit 2 : After another round of check, it was in fact not a misplaced light position. But an error in the computation of dot vector between the normal and the light direction.
Fragment Shader
#version 330 compatibility
struct light {
vec4 position; // position.w indicates if it's a direction or point lighting
vec3 diffuse; // diffuse color of the light
vec3 specular; // specular color of the light
float attenuation; // attenuation of the light
};
struct material {
vec3 diffuse;
vec3 specular;
vec3 ambient;
float shininess;
};
uniform material objMaterial;
uniform light lights[9];
uniform int nbLight;
uniform mat4 viewMatrix; // Matrix to view coordinate
uniform mat4 viewInvMatrix; // invert view matrix to find the position of the viewer
in vec3 worldNormal; // normal in worldspace
in vec3 position; // position in worldspace
vec3 ambiant = vec3(0.2,0.2,0.2);
void main()
{
int i;
vec3 viewDirection = normalize((viewInvMatrix * vec4(0.0, 0.0, 0.0, 1.0) - vec4(position, 1.)).xyz);
vec3 lightDirection, lightPositon;
vec3 normalizeWorldNormal = normalize(worldNormal);
float attenuation;
vec3 totalLight = ambiant * objMaterial.ambient;
float cosAngIncidence;
float blinnTerm;
for(i=0; i<9; i=i+1){
if(i < nbLight){
lightPositon = lights[i].position.xyz;
if (0.0 == lights[i].position.w) // directional light?
{
attenuation = 1.0; // no attenuation
lightDirection = normalize(lightPositon);
}
else // point light
{
vec3 positionToLightSource = lightPositon - position;
lightDirection = normalize(positionToLightSource);
float dis = length(positionToLightSource);
attenuation = 1.0 / (lights[i].attenuation * dis);
}
cosAngIncidence = dot(normalizeWorldNormal, lightDirection);
cosAngIncidence = clamp(cosAngIncidence, 0, 1);
vec3 halfAngle = normalize(lightDirection + viewDirection);
blinnTerm = dot(normalizeWorldNormal, halfAngle);
blinnTerm = clamp(blinnTerm, 0, 1);
blinnTerm = cosAngIncidence != 0.0 ? blinnTerm : 0.0;
blinnTerm = pow(blinnTerm, objMaterial.shininess*5);
totalLight = totalLight
+ (lights[i].diffuse * objMaterial.diffuse * attenuation * cosAngIncidence)
+ (lights[i].specular * objMaterial.specular * attenuation * blinnTerm);
}
}
gl_FragColor = vec4(totalLight.xyz, 1.0);
}
Vertex Shader
#version 330 compatibility
layout(location=0) in vec3 vx_pos;
layout(location=1) in vec3 vx_nor;
layout(location=3) in vec3 vx_col;
uniform mat4 modelMatrix; // Matrix to world coordinate
uniform mat4 normalInvTransMatrix; // Matrix for normal in world coordinate
uniform mat4 viewMatrix; // Matrix to view coordinate
uniform mat4 projectionMatrix; // Matrix to projection coordinate
out vec3 worldNormal;
out vec3 position;
void main() {
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(vx_pos,1.0);
worldNormal = vec3(normalInvTransMatrix * vec4(vx_nor, 0.));
position = vec3(modelMatrix * vec4(vx_pos,0.));
}