Unity 2018 Shaders and Effects Cookbook
上QQ阅读APP看书,第一时间看更新

Creating a shader with normal mapping

Every triangle of a 3D model has a facing direction, which is the direction that it is pointing toward. It is often represented with an arrow placed in the center of the triangle and is orthogonal to the surface. The facing direction plays an important role in the way light reflects on a surface. If two adjacent triangles face different directions, they will reflect lights at different angles, hence they'll be shaded differently. For curved objects, this is a problem: it is obvious that the geometry is made out of flat triangles.

To avoid this problem, the way the light reflects on a triangle doesn't take into account its facing direction, but its normal direction instead. As stated in the Adding a texture to a shader recipe, vertices can store data; the normal direction is the most used information after the UV data. This is a vector of unit length (which means it has a length of 1) that indicates the direction faced by the vertex.

Regardless of the facing direction, every point within a triangle has its own normal direction that is a linear interpolation of the ones stored in its vertices. This gives us the ability to fake the effect of high-resolution geometry on a low-resolution model.

The following screenshot shows the same geometric shape rendered with different per-vertex normals. In the image, on the left, normals are orthogonal to the face represented by its vertices; this indicates that there is a clear separation between each face. On the right, normals are interpolated along the surface, indicating that even if the surface is rough, a light should reflect as if it's smooth. It's easy to see that even if the three objects in the following screenshot share the same geometry, they reflect light differently. Despite being made out of flat triangles, the object on the right reflects light as if its surface was actually curved:

Smooth objects with rough edges are a clear indication that per-vertex normals have been interpolated. This can be seen if we draw the direction of the normal stored in every vertex, as shown in the following screenshot. You should note that every triangle has only three normals, but as multiple triangles can share the same vertex, more than one line can come out of it:

Calculating the normals from the 3D model is a technique that has rapidly declined in favor of a more advanced one-normal mapping. Similar to what happens with texture mapping, the normal directions can be provided using an additional texture, usually called a normal map or bump map.

Normal maps are usually images where the red, green, and blue channels of the image are used to indicate the X, Y, and Z components of the normal direction. There are many ways to create normal maps these days. Some applications, such as CrazyBump (http://www.crazybump.com/) and NDO Painter (http://quixel.se/ndo/), will take in 2D data and convert it to normal data for you. Other applications such as Zbrush 4R7 (http://www.pixologic.com/) and AUTODESK (http://usa.autodesk.com) will take 3D-sculpted data and create normal maps for you. The actual process of creating normal maps is out of the scope of this book, but the links in the previous text should help you get started.

Unity makes the process of adding normals to your shaders quite an easy process in the Surface Shader realm using the UnpackNormals() function. Let's see how this is done.