Images as Textures (5 pts)

Implementation

Added files:

  • normalmap.cpp
  • lodepng.h
  • lodepng.cpp

Significantly adjusted files:

  • mesh.cpp

Perturbing normals through a normal map is a common method to fake detailed geometry. I have added support for loading normal maps through PNG files, which is done using the dependency-free lodepng PNG encoder/decoder, similarly to image textures. Normal maps can be specified as direct children to Shape objects, which required slightly modifying this class to support this.

The eval method maps from uv-space to image-space by scaling the uv coordinates appropriately and computing the correct index in the image vector. As with image textures, I have added support for additionally offsetting these uv coordinates or applying a custom scaling. Note that we additionally have to map the retrieved RGB values in $[0, 1]^3$ to $[-1, 1]^3$, as well as adjust for Nori's left-handedness.

The trickiest part in this implementation was supporting rotate transforms on objects with normal maps. First, I was simply computing a new shading frame inside the Mesh class based on the retrieved normal from the normal map. However, this can result in flipped normals when we rotate the object, e.g. by 180 degrees. To fix this, we need to compute the local tangent and bitangent based on the uv-coordinates, and then build the frame using tangent, bitangent and the new normal.

Validation

I validated my implementation by comparing with Mitsuba. I have used the following two normal maps, which I got from a project report of last year:

Normal Map 1
Normal Map 2

Normal Map on a plane (no rotation)

This scene is illuminated with an origin at the center of the plane (plus some offset). The repeated texture nicely illustrates how the normal map behaves for light coming from different directions, which was incredibly useful for debugging.

Mitsuba 3 Mine

Normal Map on a plane (rotation of plane 180 degrees around y-Axis and 45 degrees around x-Axis)

These rotations previously resulted in incorrect (flipped) normals, before I have adjusted the code to compute local tangents and bitangents.

Mitsuba 3 Mine

Normal Map on a sphere

For validation purposes, I have also tested normal maps on a spherical object.

Mitsuba 3 Mine