Simon's Graphics Blog

Work log for ideas and hobby projects.

Projected Solid Angle Is Projected

with 7 comments

There are two quantities flying around when writing a physically based renderer:

  • Irradiance, which is power per unit area
  • Radiance, which is power per unit area per unit projected solid angle

Any BSDF is the ratio between the two: a patch receives unit irradiance from some incident direction, the BSDF defines the radiance emitted for each outgoing direction.

At no point is (non-projected) solid angle used as a measure for the patch in question, yet many references and implementations consider probability density relative to this measure. In this post I will argue that using projected solid angle directly is more natural.

For example, it is common to see BSDF sampling written as:

\[\frac{1}{N}\sum^N_{j=1}{\frac{f(\omega, \omega_j)|\cos \theta_j|}{p(\omega_j)}}\]

Where \(p\) is the probability density of \(w_j\) with respect to solid angle. Ever wonder why that cosine is there? It’s to correct for the fact that you’re sampling with respect to solid angle, but the BSDF is defined in terms of projected solid angle.

So why am I making a fuss? Let’s look at the most common BSDF: Lambertian. This BSDF is a constant, and can be analytically importance sampled using a cosine wieghted hemisphere sampling scheme. For this scheme, \(p^{cw}\) (cosine-weighted sampling pdf wrt solid angle) is defined as:

\[p^{cw}(\omega_j) = \frac{|\cos \theta_j|}{\pi}\]

Plugging this into our sampling scheme, we get the following:

\[\frac{1}{N}\sum^N_{j=1}{\frac{\pi f(\omega, \omega_j)|\cos \theta_j|}{|\cos \theta_j|}} = \frac{1}{N}\sum^N_{j=1}{\pi f(\omega, \omega_j)}\]

We spent time computing the cosine for the sampling scheme, and again for the sum itself, but these terms then cancelled out. This not only wastes computation time, but relies on these quantities cancelling perfectly even when close to zero, which can be problematic in floating-point arithmetic.

Can we do better? Yes, consider sampling with respect to projected solid angle directly. Let’s call this function \(p_\perp\). It can be defined as follows:

\[p_\perp(\omega_j) = \frac{p(\omega_j)}{|\cos \theta_j|}\]

We can then adjust our sampling scheme to use this density function directly:

\[\frac{1}{N}\sum^N_{j=1}{\frac{f(\omega, \omega_j)|\cos \theta_j|}{p(\omega_j)}} = \frac{1}{N}\sum^N_{j=1}{\frac{f(\omega, \omega_j)}{p_\perp(\omega_j)}}\]

Hurrah, our cosine terms all cancelled out! In general you should only need to consider cosine terms when computing the form factor between patches (called the geometry term in the Veach formulation), for example when connecting two sub-paths together during bidirectional path tracing. To extend a path using BSDF sampling, cosine terms are generally not required.

Better yet, the probability density function for the Lambertian BSDF just got simpler. For cosine weighted hemisphere sampling, we can define \(p^{cw}_\perp\) as follows:

\[p^{cw}_\perp(\omega_j) = \frac{1}{\pi}\]

That looks pretty simple to compute. It should also seem more natural: if we are sampling a constant BSDF with its analytically-derived importance sampling scheme, you would expect the pdf to also be a constant.

The next time you refactor your path tracing framework, consider switching all your sampling functions to return pdfs with respect to either area (when sampling light/sensor surfaces) or projected solid angle (when sampling BSDFs or angular emission/importance functions). It’s well-defined, and in my experience does less work in common cases while being more numerically stable.

Written by Simon Brown

April 16th, 2011 at 11:01 am

7 Responses to 'Projected Solid Angle Is Projected'

Subscribe to comments with RSS or TrackBack to 'Projected Solid Angle Is Projected'.

  1. It is nice to look at things from different ways, I always thought that the extra cosine is only to attenuate light so directions at grazing angle do not carry much energy.

    D-POWER

    16 Apr 11 at 6:30 pm

  2. I see your point, but how do we now analytically importance sample non-constant BRDFs, e.g. Phong or Ward? It’s often hard to always include the cosine in the sampling method. In such cases I still think it’s more convenient to regard the cosine as an integrand term, and not put it into the density.

    ingenious

    16 Apr 11 at 8:21 pm

  3. I’m not changing the sampling function at all, I’m just returning the density wrt projected solid angle.

    It’s well-defined to simply divide the pdf wrt solid angle by |cos(theta)| to form the pdf wrt projected solid angle. I’m observing that this usually cancels a cosine term already present, such as in a cosine-weighted sampling scheme.

    Simon Brown

    16 Apr 11 at 8:27 pm

  4. Right, I did not express myself correctly. Nothing changes, only the cosine goes from the integrand to the density, and as a result the sampling procedures now return pdf wrt projected solid angle. This way the integrator doesn’t need to worry about the cosine. On the other hand, this is only numerically useful for Lambertian and specular sampling procedures. With all others you’ll actually end up computing 1/(1/cosTheta) which is mathematically equal to cosTheta, but in practice not :) Plus, projected solid angle doesn’t apply for volumetric scattering.

    ingenious

    16 Apr 11 at 8:49 pm

  5. I’m happy to be told there’s a better way to implement things, perhaps even the pdf function should return a flag to say what measure it is implemented for, so you can optimise for different BSDFs. It’s true it doesn’t always cancel, but for me Lambertian is the most common case by far.

    I can’t speak for sampling phase functions, but I can indeed imagine they are sampled differently. Thanks for the comments!

    Simon Brown

    16 Apr 11 at 9:07 pm

  6. Actually, how about this: the sampling code only ever returns the *reciprocal* of the pdf wrt projected solid angle. Seems like that would always be optimal in terms of precision and number of operations?

    Simon Brown

    16 Apr 11 at 9:20 pm

  7. It’s true, Lambertian and specular are indeed the most common BRDFs, at least in research scenes :)

    As for returning the reciprocal PDF, I’ve considered it before. The nice thing is that you can avoid divisions altogether this way. However, I did not go with this approach, because it was less natural and I often need the PDF value for multiple importance sampling. And in practice I often need to divide by something else (e.g. Russian roulette or some other probability), in which case there’s no additional division introduced by the sampling PDF.

    ingenious

    16 Apr 11 at 9:34 pm

Leave a Reply