I am trying to implement normal mapping and lighting in my fragment shader. But my codes do not seem to work. My idea is to pass an extra copy of ModelMatrix to the fragment shader so that it can transform the normals stored in the texture. But the reflected light actually occurs on the other side.
[Updates] After getting some advice, I calculated the TBN matrix in the vertex shader, transform the TBN basis to world space, convert lightPosition and eyePosition to tangentSpace. But this time the planet does not even light at all! Only the ambient light shows up. Then I found out that it was because the diffuse component evaluates to negative values, which are then clamped to 0. I can not seem to find the bug in the shader.
VertexShader:
#version 400
in layout(location=0) vec3 vertexPosition;
in layout(location=1) vec2 vertexUV;
in layout(location=2) vec3 vertexNormal;
in layout(location=3) vec3 vertexTangent;
in layout(location=4) vec3 vertexBitangent;
out vec2 UV;
out vec3 vertexPositionWorld;
out vec3 tangentLightPos;
out vec3 tangentViewPos;
out vec3 tangentFragPos;
uniform vec3 lightPositionWorld;
uniform vec3 eyePositionWorld;
uniform mat4 M;
uniform mat4 V;
uniform mat4 P;
void main()
{
gl_Position = P * V * M * vec4(vertexPosition, 1.0f);
vertexPositionWorld = vec3(M * vec4(vertexPosition, 1.0f));
UV = vertexUV;
// note scaling problem here
mat3 normalMatrix = transpose(inverse(mat3(M)));
// mat3 normalMatrix = inverse(transpose(mat3(M)));
vec3 T = normalize(normalMatrix * vertexTangent);
vec3 B = normalize(normalMatrix * vertexBitangent);
vec3 N = normalize(normalMatrix * vertexNormal);
mat3 TBN = transpose(mat3(T, B, N));
tangentLightPos = TBN * lightPositionWorld;
tangentViewPos = TBN * eyePositionWorld;
tangentFragPos = TBN * vertexPositionWorld;
}
FragmentShader:
#version 400
uniform sampler2D textureSampler_1;
uniform sampler2D textureSampler_2;
uniform vec3 AmbientLightPower;
uniform vec3 DiffuseLightPower;
uniform vec3 SpecularLightPower;
uniform float specularLightPower;
in vec2 UV;
in vec3 vertexPositionWorld;
in vec3 tangentLightPos;
in vec3 tangentViewPos;
in vec3 tangentFragPos;
out vec4 finalColor;
void main()
{
vec3 normal = texture(textureSampler_2, UV).rgb;
normal = normalize(normal * 2.0 - 1.0);
vec3 MaterialAmbientColor = texture( textureSampler_1, UV ).rgb;
vec3 MaterialDiffuseColor = texture( textureSampler_1, UV ).rgb;
vec3 MaterialSpecularColor = vec3(0.3,0.3,0.3);
// diffuse light
vec3 lightDirection = normalize(tangentLightPos - tangentFragPos);
float DiffuseBrightness = clamp(dot(lightDirection, normal), 0, 1);
// specular light
vec3 reflectedDirection = normalize(reflect(-lightDirection, normal));
vec3 viewDirection = normalize(tangentViewPos - tangentFragPos);
float SpecularBrightness = clamp(dot(reflectedDirection, viewDirection), 0, 1);
finalColor = vec4(
MaterialAmbientColor * AmbientLightPower +
MaterialDiffuseColor * DiffuseLightPower * DiffuseBrightness +
MaterialSpecularColor * SpecularLightPower * pow(SpecularBrightness, specularLightPower), 1.0f);
}