Geometry and Transformations
1.3 Normals
A normal vector is a vector which is perpendicular to a surface at particular point. To calculate it, we take the cross product of any two nonparallel vectors which are tangent to the surface at a point.
For example, in the diagram below, C is a normal vector of the plane formed by A and B:
Normals look a lot like vectors, but behave differently, particularly when it comes to transformations. My Rust implementation of pbrt will follow the original implementation in defining them as a separate type, Normal3d
.
Normal3d
includes all of the functionality of Vector3d
, with the exception of the cross product.
The c++ pbrt implementation also includes a method called FaceForward
, which flips a surface normal so that it lies in the same hemisphere as a given vector. This is implemented for all four combinations of Normals and Vectors, and provides an opportunity to further experiment with Rust generics. Here's the FaceForward
trait:
#![allow(unused)] fn main() { /// Flip a surface normal so that it lies in the same hemisphere as a given vector. /// This is useful for computing the reflection direction. /// This trait provides default behavior for any combination of vector types. pub trait FaceForward<T: Dot<T, U> + Clone + Neg<Output = T>, U: Scalar>: Dot<T, U> { fn face_forward(&self, other: T) -> T { if self.dot(&other) < zero() { other.clone() } else { -other.clone() } } } /// Implements the FaceForward trait for any combination of vector types. impl<U: Scalar, T: Dot<T, U> + Clone + Neg<Output = T>, V: Dot<T, U>> FaceForward<T, U> for V{} }
This trait provides default behaviour for any type which can perform a dot() operation with some other type, where that type can be cloned and negated.