Using lighting, we can simulate bumps and divots on objects using normal maps. Normal maps are a texture that indicate the geometric normal of a texel, which can be used by the fragment shader to simulate more detail than just using vertex normals.
Building Normal Maps
Since normal maps are just textures, they are almost already in our asset build pipeline. The one difference is that they are not in the sRGB color space because the RGB values in a texel actually represent the XYZ components of a normal vector! Mapping them as so would create an incorrect texture, so we need our build system to know whether or not it is building a color map or a normal map.
The normals in our normal map are in texture space where the vector (0, 0, 1) is a normal pointing straight out of the texture. That means the normals we sample from the normal map must be transformed into a geometric normal before being used. This requires the normal, tangent, and bitangent vectors that are usually calculated by 3D modeling software like Maya.
When we get these vectors in the vertex shader, we can transform them into world space and hand them off to the fragment shader to normalize and calculate a rotation matrix. This matrix can then be used to rotate the normal map vector into the correct orientation for lighting.
Before seeing the results of a normal map implementation, let's take a look at a normal map.
As normal maps are using RGB values as the XYZ components of a vector, it's not surprising to see a lot of blue as the default normal would be (0, 0, 1). For the text that says RAISED, notice how the top edges are green and the edges to the right are red. This look is indicative of a raised surface that will create bumps on an object. For the text that says SUNKEN, notice how the bottom edges are green with red to the left. This look is indicative to a sunken surface that will create divots on an object. We can see both of this in the animation below:
Notice how when the light is to the right of RAISED, the edges on the right brighten to indicate light is hitting them. Notice how the opposite happens for SUNKEN, where the right edges of the text are dark. The exact same effect happens to the top and bottom of both words in similar manners.
Let's take a look at another normal map to see the detail we can create with some simple brush strokes!
If we follow the same evaluation pattern we did for RAISED, we can see that the eyes will be bumps. For SUNKEN, we can see that the mouth and tongue will be divots. The animation below will also highlight that!
Finally, let's see how normal maps improve the lighting on a production ready texture!