mmp / pbrt-v3

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.
http://pbrt.org
BSD 2-Clause "Simplified" License
4.87k stars 1.18k forks source link

Improve numerical behavior of Sphere::Sample() #212

Closed wjakob closed 5 years ago

wjakob commented 5 years ago

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.

mmp commented 5 years ago

Awesome!