
The deviations in color represent normal vectors that are slightly offset from the general positive z direction, giving a sense of depth to the texture. This is because the normals are all closely pointing outwards towards the positive z-axis \((0, 0, 1)\): a blue-ish color. This (and almost all normal maps you find online) will have a blue-ish tint. An example normal map of the brick surface at the start of this chapter is shown below: With normal vectors transformed to an RGB color component like this, we can store a per-fragment normal derived from the shape of a surface onto a 2D texture. Vec3 rgb_normal = normal * 0.5 + 0.5 // transforms from to Normal vectors range between -1 and 1 so they're first mapped to : We can similarly store a normal vector's x, y and z component in the respective color components. If you think about color vectors in a texture they are represented as a 3D vector with an r, g, and b component. While normal vectors are geometric entities and textures are generally only used for color information, storing normal vectors in a texture may not be immediately obvious. This way we can sample a 2D texture to get a normal vector for that specific fragment. Similar to what we did with diffuse and specular maps we can use a 2D texture to store per-fragment normal data. To get normal mapping to work we're going to need a per-fragment normal. We now pass a per-fragment normal, instead of an interpolated surface normal, to the lighting algorithm. Since we only change the normal vectors per fragment there is no need to change the lighting equation. Applied to the brick plane it looks a bit like this:Īs you can see, it gives an enormous boost in detail and for a relatively low cost.

This technique to use per-fragment normals compared to per-surface normals is called normal mapping or bump mapping. What if we, instead of a per-surface normal that is the same for each fragment, use a per-fragment normal that is different for each fragment? This way we can slightly deviate the normal vector based on a surface's little details this gives the illusion the surface is a lot more complex:īy using per-fragment normals we can trick the lighting into believing a surface consists of tiny little planes (perpendicular to the normal vectors) giving the surface an enormous boost in detail. The brick surface only has a single normal vector, and as a result the surface is uniformly lit based on this normal vector's direction. From the lighting technique's point of view, the only way it determines the shape of an object is by its perpendicular normal vector. If we think about this from a light's perspective: how comes the surface is lit as a completely flat surface? The answer is the surface's normal vector. What we need is some way to inform the lighting system about all the little depth-like details of the surface. We can partly fix the flat look by using a specular map to pretend some surfaces are less lit due to depth or other details, but that's more of a hack than a real solution. The lighting doesn't take any of the small cracks and holes into account and completely ignores the deep stripes between the bricks the surface looks perfectly flat. Below we can see a brick texture applied to a flat surface lit by a point light. If we were to view such a brick surface in a lit scene the immersion gets easily broken. A brick surface is quite a rough surface and obviously not completely flat: it contains sunken cement stripes and a lot of detailed little holes and cracks. Most real-life surface aren't flat however and exhibit a lot of (bumpy) details.įor instance, take a brick surface. Textures help, but when you take a good close look at the meshes it is still quite easy to see the underlying flat surfaces. We boosted the realism by wrapping 2D textures on these flat triangles, hiding the fact that the polygons are just tiny flat triangles.

Normal Mapping Advanced-Lighting/Normal-MappingĪll of our scenes are filled with meshes, each consisting of hundreds or maybe thousands of triangles.
