1. Transformation Matrices
We rely on matrices to model transformations. Since we work in 3D, you would expect us to use 3 × 3 matrices. However, matrices of this size cannot be used to model translations. In order to make this possible, we need 4 × 4 matrices.
Transformation matrices have already been implemented for you.
You will find them in math/transformation-matrices.h
.
2. Transformations
As explained here, transformations are actually faked. If we need to render a large sphere, we actually shrink the camera. After having found the intersection for a shrunk camera, we need to scale back the hit position to normal size. It is therefore necessary that for each transformation, we have both the corresponding matrix but also its inverse.
Computing the inverse is an expensive operation. However, we can be smart about it. When we create a matrix for a translation by the vector \(\vec v(x,y,z)\), we get
Instead of trying to directly invert this matrix, we can think in terms of transformations. What is the inverse operation of moving everything a distance \((x, y, z)\)? Simple: it’s moving it back a distance \((-x, -y, -z)\). Finding the matrix for this transformation is very easy:
To make this trick possible, we need to build this inverse matrix \(T^{-1}\) immediately when building the regular \(T\) matrix. If we wait too long, the information about which transformation the matrix represents might be forgotten and we would have to resort to a more complex algorithm to invert the matrix.
For this reason, we introduced the class Transformation
. This class pairs up both the
matrix \(T\) and its inverse \(T^{-1}\). Whenever we need a translation transformation, we set up both matrices and
group them in a Transformer
object.
3. Transformer Primitive
Lastly, we need to define a scaling Primitive
.
The Transformer
class has already been written for you and takes care of most of the complexity.
It takes a Transformation
object and uses it to transform and "untransform" rays and hit locations.