Normal mapping
Just some thoughts for myself as a reminder on how to work with normalmapping and shaders
- When you use varying variables in your shader (i.e. normals: binormal, tangent, normal) make sure to normalize them in your fragment shader as varyings are interpolated between vertex and fragment shader which mess up normalization done in the vertex shader.
- I found it easiest to debug/test my shaders by not using a diffuse texture but just using a very dark color for the diffuse part. I.e. 0.01 for RGB.
- Also, use a normal map which does not have very fine details but use a coarse one
-
I was using the shaders below though I still have some questions like: do I need to normalize the tangent and bitangent for the tangent matrix; it doesnt seem to matter though.
Also I had to put the lights at a negative z position (-50), when using positive z values I didn't see any lighting. This can be due to the light direction vector...this was exactly the case; I had to transform the light position into tangent space as well. - Also use at least two lights which makes testing the normalmap a lot clearer
- Use a hight specularity value so it has a sharp fallof (50-128)
- Use a moving light so you can better see if shading works; sometimes it's difficult to notice shading changes because they are minimal


Vertex shader
#define LIGHT_COUNT 2 attribute vec4 pos; attribute vec2 tex; attribute vec3 norm; attribute vec4 tan; uniform mat4 modelview; uniform mat4 projection; uniform mat4 modelview_projection; struct Light { vec3 position; vec4 diffuse_color; vec4 specular_color; }; uniform Light lights[LIGHT_COUNT]; varying vec2 texcoord; varying vec3 normal; varying vec3 tangent; varying vec3 binormal; varying vec3 light_directions[LIGHT_COUNT]; varying vec3 eye_position; varying vec3 eye_normal; void main() { gl_Position = modelview_projection * pos; eye_position = vec3(modelview * pos); texcoord = tex; normal = norm; eye_normal = normalize(vec3(modelview * vec4(normal,0.0))); tangent = normalize(tan.xyz); binormal = cross(eye_normal, tangent) * tan.w; binormal = normalize(binormal); mat3 tangent_space = mat3(tangent, binormal, eye_normal); for(int i = 0; i < LIGHT_COUNT; ++i) { vec3 lp = (vec3(modelview * vec4(lights[i].position, 0.0))); light_directions[i] = normalize(tangent_space * (lp - eye_position)); } }
Fragment shader
#define LIGHT_COUNT 2 uniform sampler2D diffuse_texture; uniform sampler2D normal_texture; struct Light { vec3 position; vec4 diffuse_color; vec4 specular_color; }; uniform Light lights[LIGHT_COUNT]; varying vec3 eye_position; varying vec3 normal; varying vec3 eye_normal; varying vec2 texcoord; varying vec3 tangent; varying vec3 binormal; varying vec3 light_directions[LIGHT_COUNT]; void main() { vec4 texel_color = vec4(0.0, 0.0, 0.0, 1.0); vec3 final_normal = normalize(eye_normal); vec3 normal_color = texture2D(normal_texture, texcoord).xyz * 2.0 - 1.0; normal_color = normalize(normal_color); mat3 tangent_matrix = mat3(tangent, binormal, final_normal); final_normal = normalize(tangent_matrix * normal_color); vec4 diffuse_color = texture2D(diffuse_texture, texcoord); texel_color += diffuse_color; for(int i = 0; i < LIGHT_COUNT; ++i) { float n_dot_l = max(dot(normalize(final_normal), light_directions[i]), 0.0); if(n_dot_l > 0.0) { texel_color += ( 0.4*(n_dot_l * lights[i].diffuse_color)); vec3 reflection = normalize(reflect(-normalize(light_directions[i]), final_normal)); float spec = max(0.0, dot(final_normal, reflection)); float fspec = pow(spec, 352.0); texel_color += (fspec * lights[i].specular_color) ; } } gl_FragColor = texel_color; }