Sampling the Visible Sphere

Fred Akalin

(Note: this article is a summary of this thread on ompf2.)

The usual method for sampling a sphere from a point outside the sphere is to calculate the angle of the cone of the visible portion and uniformly sample within that cone, as described in Shirley/Wang.

However, one detail that is glossed over is that you still need to map from the sampled direction to the point on the sphere. The usual method is to simply generate a ray from the point and the sampled direction and intersect it with the sphere. However, this intersection test may fail due to floating point inaccuracies (e.g., if the sphere is small and the distance from the point is large).

I've found a couple of existing ways to deal with this. As described in the pbrt book, pbrt simply assumes that the ray just grazes the sphere if the intersection fails, and then projects the center of the sphere onto the ray (code here). mitsuba moves the origin of the ray closer to the sphere (in fact, from within it) before doing the test (falling back to projecting the center onto the ray if that still fails) (code here).

However, this seems inelegant. I've come up with a better way, which involves converting the sampled cone angle \(\theta\) (as measured from the segment connecting the point to the sphere center) into an angle \(\alpha\) from the inside of the sphere, and then simply using \(\alpha\) and the sampled polar angle \(\varphi\) onto the sphere. This turns out to be simple, and in my unscientific tests a bit faster.

Here's a crude diagram showing the geometry:

You can see that \[ L = d \cos \theta - \sqrt{r^2 - d^2 \sin^2 \theta} \] and also by the law of cosines, \[ L^2 = d^2 + r^2 - 2 d r \cos \alpha\text{.} \] We're actually more interested in \(\cos \alpha\), so solving for that we get \[ \cos \alpha = \frac{d}{r} \sin^2 \theta + \cos \theta \sqrt{1 - \frac{d^2}{r^2} \sin^2 \theta}\text{.} \] An alternate form, which may be easier to analyse, recalling that \(\sin \theta_{\max} = r/d\), is \[ \cos \alpha = \frac{\sin^2 \theta}{\sin \theta_{\max}} + \cos \theta \sqrt{1 - \frac{\sin^2 \theta}{\sin^2 \theta_{\max}}}\text{.} \]

So sampling pseudocode would look like:

(cos θ, φ) = uniformSampleCone(rng, cos θmax)
D = 1 - d² sin² θ / r²
if D ≤ 0 {
  cos α = sin θmax
} else {
  cos α = (d/r) sin² θ + cos θ √D
ω = sphericalDirection(cos α, φ)
pSurface = C + r ω

I haven't done any analysis yet on the most robust way [in the floating-point sense] to do the calculations above.)

There's no backfacing since we clamp \(\cos \alpha\) to \(\sin \theta_{\max}\), which is analogous to the case when the ray from \(P\) misses the sphere.

Note that one cannot just compute \(\alpha_{\max}\) and uniformly sample the cone from inside the sphere, as that doesn't produce the same distribution over the visible region as sampling the cone from outside the sphere. To preserve correctness, you would have to use the (uniform) PDF over the surface area of the visible portion of the sphere, but you would have to then convert that to a PDF with respect to projected solid angle from \(P\), which is suboptimal to just doing the sampling with respect to projected solid angle from \(P\) as described above.