<aside> 💡 We use a 2D texture to store per-fragment normal data

</aside>

Color vectors in a texture they are represented as a 3D vector with an r, g, and b component. We can similarly store a normal vector's x, y and z component in the respective color components.

Normals are stored into the texture by mapping [-1, 1] values to [0, 1], so to restore the original normal values we do normal*2.0 - vec3(1.0)

// Map from [-1,1] to [0,1]
vec3 rgb_normal = normal * 0.5 + 0.5; 

// Map from [0,1] to [-1,1]
vec3 rgb_normal = rgb_normal*2.0 - vec3(1.0);

<aside> 💡 This (and almost all normal maps you find online) will have a blue-ish tint. This is because the normals are all closely pointing outwards towards the positive z-axis (0,0,1): ⇒ a blue-ish color

normal_mapping_normal_map.png

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. For example, you can see that at the top of each brick the color tends to be more greenish, which makes sense as the top side of a brick would have normals pointing more in the positive y direction (0,1,0) which happens to be the color green!

</aside>

NOTE: The linked normal map (see Figure 2) is different from the original map (see Figure 1). The reason for this is that OpenGL reads texture coordinates with the y(or v) coordinate reversed from how textures are generally created. The linked normal map thus has its y (or green) component inversed (you can see the green colors are now pointing downwards)

Figure 1 - Original normal map

Figure 1 - Original normal map

Tangent Space

Figure 2 - Linked normal map

Figure 2 - Linked normal map

<aside> 💡 Reason: When the orientation of the object changes, the lighting doesn't look right! This happens because the sampled normals of this plane still roughly point in the positive z direction (outward from the screen) even though they should mostly point in the positive y direction. As a result, the lighting thinks the surface's normals are the same as before when the plane was pointing towards the positive z direction; the lighting is incorrect. The image below shows what the sampled normals approximately look like on this surface:

normal_mapping_ground_normals.png

</aside>

<aside> 💡 Tangent Space → A coordinate space where the normal map vectors always point towards the positive z direction; all other lighting vectors are then transformed relative to this positive z direction. This way we can always use the same normal map, regardless of orientation.

Tangent space is a space that's local to the surface of a triangle.

</aside>

TBN matrix

normal_mapping_tbn_vectors.png

Math:

To construct such a change-of-basis (Change of Basis) matrix, that transforms a tangent-space vector to a different coordinate space, we need three perpendicular vectors that are aligned along the surface of a normal map: an up, right, and forward vector: