Quote:
My approach is as found often in tutorials:
Vertex Shader:
1) calculate the TBN-matrix for the current vertex
2) transform the light direction into the tangential space with the TBN-matrix
3) pass this light direction to the fragment shader
Fragment shader:
4) calculate the dot product of the light direction and the current normalmaps normal
5) use this value to lighten the pixel
1) because you transformed the vertex into the camera's coordinates system, you have to do the same with the TBN matrix.(assuming the modelview matrix is a combination of only rotations and translations you can use gl_NormalMatrix).
2)the TBN matrix transforms a vector
from tangent space. So you actually need it's
inverse [sad]. This is why it's better to send the TBN matrix as varying to the fragment shader in order to use it to transform the normal retrived from the normal-map.(EDIT: Well, because the TBNMatrix is orthogonal, it's inverse is equal to it's transpose [embarrass])
So here is how it should be done (code not tested)
Vertex shader:
attribute vec3 tangent;varying mat3 TBNMatrix;void main(void){ gl_Position = ftransform(); gl_TexCoord[0] = gl_MultiTexCoord0; vec3 N = gl_Normal; vec3 T = tangent; vec3 B = cross(T, N); TBNMatrix = gl_NormalMatrix * mat3(T, B, N);//Now TBNMAtrix is expressed in camera coordinates system /* A more correct (I think) but slower Alternative is: vec3 N = normalize(gl_NormalMatrix * gl_Normal); vec3 T = normalize(mat3(gl_ModelViewMatrix) * tangent); vec3 B = cross(T, N); TBNMatrix = mat3(T, B, N); */}
Fragment shader:
uniform sampler2D texture;uniform sampler2D normalmap;varying mat3 TBNMatrix;void main(void){ vec4 texture = texture2D(texture, vec2(gl_TexCoord[0])); vec3 bumpnormal = 2.0*texture2D(normalmap, vec2(gl_TexCoord[0])).xyz - vec3(1.0); bumpnormal=TBNMatrix*bumpnormal;//here bumpnormal is transformed from tangent to camera coordinates system vec3 lightDirGlobal = vec3(1.0, 0.0, 0.0);//It's fixed with respect to the camera float strength = max(dot(bumpnormal, lightDirGlobal), 0.0); gl_FragColor = vec4(strength * texture.rgb, 1.0);}
EDIT: If you still want to send the light direction to the fragment shader (an use less varyings) because the TBNMatrix is orthogonal.
Vertex shader:
attribute vec3 tangent;vec3 lightDirGlobal = vec3(1.0, 0.0, 0.0);//Fixed w.r.t the cameravarying vec3 lightDirTangential;void main(void){ gl_Position = ftransform(); gl_TexCoord[0] = gl_MultiTexCoord0; vec3 N = gl_Normal; vec3 T = tangent; vec3 B = cross(T, N); TBNMatrix = gl_NormalMatrix * mat3(T, B, N);//Now TBNMAtrix is expressed in camera coordinates system /* A more correct (I think) but slower Alternative is: vec3 N = normalize(gl_NormalMatrix * gl_Normal); vec3 T = normalize(mat3(gl_ModelViewMatrix) * tangent); vec3 B = cross(T, N); TBNMatrix = mat3(T, B, N); */ lightDirTangential = lightDirGlobal * TBNMatrix;//equivalent to: transpose(TBNMatrix) * lightDirGlobal;}
Fragment shader:
uniform sampler2D texture;uniform sampler2D normalmap;varying vec3 lightDirTangential;void main(void){ vec4 texture = texture2D(texture, vec2(gl_TexCoord[0])); vec3 bumpnormal = 2.0*texture2D(normalmap, vec2(gl_TexCoord[0])).xyz-vec3(1.0); float strength = max(dot(bumpnormal, lightDirTangential), 0.0); gl_FragColor = vec4(strength * texture.rgb, 1.0);}
[Edited by - knighty on April 18, 2009 10:10:50 AM]