[GLSL] Wrong lighting position when using Normal map

Started by
3 comments, last by Lopez 18 years, 1 month ago
Hi, I'm trying to learn more about Normal Mapping and I'm getting really close to finishing a working GLSL Normal Mapping shader, but I'm having a problem for which I hope someone here has a solution. Here is the situation: By reading and combining bits and pieces from different articles (these marvellous tutorials really got me going: First, Second) I managed to make a working GLSL shader that seems to work in Shader Designer (TyphoonLabs) but when using the shader in my own render-engine, problems arise. It seems I don't transform the light and/or camera position correctly into Tangent Space, so Specular and Diffuse Lighting are a bit "off" (see screenshot below). Here is the problem: The real path of the light follows the green line in the screenshot (it just rotates around the Y-axis at a fixed height above the plane), but the light on the "surface" of the quad follows the red line (more or less)! I hope you understand what I mean :) The result sure "looks" like Normal Mapping, but just the lighting is wrong. Surely there is something wrong in my shader, but I'm a bit stumped (as these are my first steps towards Normal Mapping). At first I thought my TBN-Matrix was wrong (perhaps I used wrong Texture Coordinates?), and to be sure I placed the Quad at the origin with the normal pointing towards the positive Y-axis and hardcoded the Tangent and Binormal vectors in my app ... but the problem still exists. These are the hardcoded values I'm using: Vector3 tangent = new Vector3(1.0, 0.0, 0.0); Vector3 normal = new Vector3(0.0, 1.0, 0.0); Vector3 binormal = new Vector3(0.0, 0.0, 1.0); This is my GLSL vertex shader:

varying vec4 viewTangetSpace;
varying vec4 lightTangetSpace;

attribute vec3 tangent;  //These are the hardcoded attributes from my app
attribute vec3 binormal; //These are the hardcoded attributes from my app

//Light and Camera position in WorldSpace, which I get from my app
uniform vec4 lightPos, cameraPos;

void main(void)
{
	gl_Position = ftransform();
	gl_TexCoord[0] = gl_MultiTexCoord0;

	mat3 TangentSpace_Matrix = mat3(tangent, binormal, gl_Normal); 
	
	vec3 viewDir = cameraPos.xyz - gl_Vertex.xyz;
	viewTangetSpace.xyz = viewDir * TangentSpace_Matrix;	
	viewTangetSpace.w = 1.0;
	viewTangetSpace = normalize(viewTangetSpace);

	vec3 lightVec = lightPos.xyz - gl_Vertex.xyz;
	lightTangetSpace.xyz = lightVec * TangentSpace_Matrix; 
	lightTangetSpace.w = 1.0;
	lightTangetSpace = normalize(lightTangetSpace);
}


This is my GLSL fragment shader:

varying vec4 viewTangetSpace;
varying vec4 lightTangetSpace;

uniform sampler2D texture;
uniform sampler2D normalMap;

void main()
{
	const float shine = 64.0;

	vec4 normalVector = texture2D(normalMap, vec2(gl_TexCoord[0]));
	normalVector = normalVector * 2.0 - 1.0;
	normalVector.a = 0.0;

	vec4 color = texture2D(texture, vec2(gl_TexCoord[0]));
	vec4 lightReflection = normalize( reflect(-lightTangetSpace, normalVector) );

	//specular lighting
	vec4 localView = normalize(viewTangetSpace);		
	float intensity = max(0.0, dot(lightReflection, localView) );
	vec4 specular = vec4(pow(intensity, shine));
	
	//diffuse lighting
  float NdotL = max(dot(normalVector, normalize(lightTangetSpace)), 0.0);
  vec4 diffuse = NdotL * color;

	gl_FragColor = 0.2 * color + (diffuse * color + 0.6 * specular);
}

I'm probably overlooking something trivial but I really can't see what I'm doing wrong. Perhaps someone here sees a solution? Thanks a lot in advance!
Advertisement
mat3 TangentSpace_Matrix = mat3(gl_NormalMatrix * TANGENT, gl_NormalMatrix * BINORMAL, gl_NormalMatrix * gl_Normal);


This is getting myself better results in RenderMonkey, as the light is no longer static.

I use quadratics in my shader rather than matricies, so I don't know too much about the TBN matrix. Sorry!
We should do this the Microsoft way: "WAHOOOO!!! IT COMPILES! SHIP IT!"
Sorry, that doesn't seem to do change anything. (btw: Isn't gl_NormalMatrix used to place a normal in eye-space?)

This is such a strange problem. I did some more testing today and added a way to manually translate my light on the XZ-plane above my quad, but also here the light on the surface behaves very, very wierd.

According to several articles I have to give the camera and light positions in Object-Space to the shader. Object-space is the same as world-space, isn't it? Not that it matters here cause the quad is located at the origin, but just to be sure :)
Some guesses:

I think you need the inverse of the TangentSpace_Matrix to transform the vector into tangent space.
Also this seems wrong:
"Vector3 tangent = new Vector3(1.0, 0.0, 0.0);
Vector3 normal = new Vector3(0.0, 1.0, 0.0);
Vector3 binormal = new Vector3(0.0, 0.0, 1.0);"

I'd rather:
"Vector3 tangent = new Vector3(1.0, 0.0, 0.0);
Vector3 binormal = new Vector3(0.0, 1.0, 0.0);
Vector3 normal = new Vector3(0.0, 0.0, 1.0);"

Then again, I'm not familiar with shaders too much...
Hi there,


firstly, calculate your 3x3 tangent mat like so...

	mat3 TBN_Matrix = gl_NormalMatrix * mat3(tangent, binormal, gl_Normal);


any you light vector as so...

	vec4 lightEye = gl_ModelViewMatrix *  gl_LightSource[0].position;	vec3 lightVec =0.02* (lightEye.xyz - mv_Vertex.xyz);				g_lightVec = lightVec * TBN_Matrix; 


.. and the frag ...

	vec3 bump = texture2D(tex2, gl_TexCoord[0].xy).rgb*2.0-1.0;	bump = normalize(bump);	float diffuse = clamp(dot(lightVec, bump), 0.0, 1.0);



Have you checked if you are calculating the tangent and binormals correctly?

try rendering the tangent and binormals to the vertex colors. if the color's don't match up at triangle edges, you have calculated the tangent and bitangent incorrectly.

Le me know how you get on


This topic is closed to new replies.

Advertisement