Course contentsShow
← Unity Game Development
Lesson 600 of 8289. Rendering and VisualsFree lesson

Simulating Surface Detail with Normal Mapping

Apply tangent-space normal maps to simulate complex geometric surface details and lighting variations without increasing the underlying polygon count.

In this lesson, you will learn how to leverage tangent-space normal maps to trick the eye into seeing intricate geometric details without adding a single polygon to your mesh.

The Illusion of Depth

When light hits an object, the way it bounces off depends on the direction the surface is facing (the "normal"). If you have a flat, low-poly plane, all light bounces off at the same angle, making it look perfectly smooth. However, real-world surfaces like bricks or cracked stone have tiny crevices that scatter light.

If you were to model these details geometrically, your polygon count would skyrocket, crushing your performance budget. Instead, we use a Normal Map—a texture where the RGB channels represent the X, Y, and Z coordinates of surface normals. By applying this to a material, the shader "lies" to the lighting engine, telling it that the surface is tilted in specific directions even though the underlying geometry remains flat.

Tangent Space Explained

Normal maps are almost always calculated in Tangent Space. This is crucial because it makes the texture "relative" to the surface it is mapped to. If you rotate a cube, the normal map rotates with it, ensuring the shadows and highlights remain consistent with the surface orientation. The "Tangent" and "Binormal" vectors provide the local coordinate system that allows the shader to transform the stored normal data into world space during the rendering process.

In Unity’s shader graph or standard material inspectors, you simply assign your normal texture to the Normal Map slot. Ensure the texture type is set to Normal Map in the import settings; Unity will then process the image data to ensure the vectors are compressed and interpreted correctly by the GPU.

// Simplified logic of how a shader uses a Normal Map:
float3 normal = UnpackNormal(tex2D(_NormalMap, uv));
// 'normal' is now used to calculate diffuse/specular lighting
// instead of the flat geometric normal of the mesh.

Key Takeaway: Normal mapping decouples visual complexity from geometric complexity, allowing you to achieve high-fidelity surface lighting while keeping your performance impact low.