Source code for pbrt, the renderer described in the third edition of "Physically Based Rendering: From Theory To Implementation", by Matt Pharr, Wenzel Jakob, and Greg Humphreys.
The current implementation of Sphere::Sample() computes sinTheta
from cosTheta using the expression
std::sqrt(1-sinTheta*sinTheta).
While convenient and computationally cheap, this approach suffers from
severe cancellation errors for small angles, causing the sphere to
effectively collapse down to a point. Numerical errors start to kick in
below sinThetaMax < 1.5 degrees in single precision.
As far as numerical issues go, this isn't that terrible — a point light
is a relatively good approximation to a distant sphere. Yet, 1.5 degrees
seems relatively large and we can easily do better by computing
sinTheta directly using a Taylor series expansion. This commit
introduces such an approximation and also reorganizes the computation to
be a bit more efficient.
The current implementation of
Sphere::Sample()
computessinTheta
fromcosTheta
using the expressionstd::sqrt(1-sinTheta*sinTheta)
.While convenient and computationally cheap, this approach suffers from severe cancellation errors for small angles, causing the sphere to effectively collapse down to a point. Numerical errors start to kick in below
sinThetaMax
< 1.5 degrees in single precision.As far as numerical issues go, this isn't that terrible — a point light is a relatively good approximation to a distant sphere. Yet, 1.5 degrees seems relatively large and we can easily do better by computing
sinTheta
directly using a Taylor series expansion. This commit introduces such an approximation and also reorganizes the computation to be a bit more efficient.