About normal maps and tangent space
Normal maps for detailed per-pixel lighting are defined in tangent space. This sample uses a simple sphere mesh to show what this tangent space actually looks like and how it can be calculated for an arbitrary mesh at runtime.In the render displayed above, the little coordinate grid represents the tangent space for the vertex highlighted in red. The axis aligned outwards along the normal is the Z axis of the local tangent space. This axis matches the blue channel of a normal map, which consequently needs to be > 0.5 to get a normal to actually point out of the surface. This is why normal maps typically have a blue tint. The X axis corresponds to the U direction in the texture coordinates for the bump map and the Y axis corresponds to the V direction.
Details on how to calculate the tangent space, that is the tangents and binormals, for a set of vertices is provided in the further reading link below. The C# port of the code presented in that article can be found in the Sphere.cs file.
Computing the tangent frame on the fly
While working on a little soft body physics demo I ran into the problem that I had to recalculate the normals and tangents each frame, because the vertex positions were constantly changing. Vilio pointed out that the tangent frame can actually be calculated on the fly in the shader when rendering the mesh, using the ddx/ddy intrinsics. Some searching turned up this thread containing the HLSL code to actually do this and it works out pretty well. You can find a seperate demo at the bottom of this page showing this technique in action. I'm not sure if my implementation is entirely correct, since ddx/ddy are screen-space derivates and I don't think I'm using them as such. If anyone spots a glaring flaw in my approach, please do let me know.Credits for posting the HLSL code go to Spon3bob, but over here I found the technique was first described in the ShaderX5 book by Christian Schueler. That linked post also contains a nifty hack to calculate normals in a shader using much the same way, but from my brief tinkering on that I think that this technique is not suitable to employ in one go while rendering the mesh. I'm not sure if that's due to the fact that I didn't use an extra pass to blur the normals or because I messed something up, but since generating the normals on the CPU wasn't that bad to begin with I'll stick with that.
Sample mouse controls
- Left button click: select vertex- Right button drag: rotate camera
Files for this resource
| Filename | Size |
|
|
50.7 KB |
|
|
57.7 KB |
Further reading

