Thursday, March 29, 2018

Distributing cosine weighted points on the hemisphere

This is a continuation of my previous post on making uniform sample distributions over the unit sphere, but in this case I'll be covering cosine weighted distributions over the hemisphere.  The reason for this is that cosine weighted distributions are especially useful for generating ray samples when raytracing global illumination, and there happens to be a pretty elegant method to achieve this result.

In the case that we're sampling for global illumination we're sampling the hemisphere of light that could hit a particular point on the surface.  Our hemisphere distribution is cosine weighted due to the geometric properties described by Lambert's cosine law, in essence describing how a slanted surface has more surface area over the same width (or how a constant surface area that's slanted covers less width versus head-on).  In other words the amount of light that hits a certain amount of surface area is proportional to the cosine of the angle the light hits the surface.


So if you imagine our surface as the fixed-length hypotenuse of a right triangle, as as the angle becomes greater the adjacent side becomes smaller, approaching 0 at 90 degrees, and as the angle becomes smaller approaching 0 degrees the adjacent side approaches the length of the hypotenuse.  The ratio of the adjacent side to the hypotenuse is the cosine of the angle.  This is all a very wordy way to say something that's pretty obvious in practice.  It is a geometric property, and it is the essence of lambertian reflectance since when your surface is perfectly diffuse the only thing left to describe the "shading" is the distribution of light energy over the geometry itself, and in that way it's pretty independent of the shading model.

If we're being particularly stingy about our ray samples (as we probably should be) in many cases it's a good idea to consider this cosine weighted property in that sampling rather than sampling uniformly and weighting after the fact.  One of the simplest ways to do this is called Malley's method.

The idea behind Malley's method is to uniformly distribute points on the unit disk and then project them up to the hemisphere, creating a cosine weighted distribution.  How we create our disk distribution is up to us.

So first let's start with methods for the disk distribution.  The straightforward way to do this is to create the points using random polar coordinates .  Due to the property of a circle that a=pi*r2, the density of points follows a quadratic curve.  We can compensate for this by taking the sqrt(r).  So for our two random numbers (phi,r) where phi goes from 0 to 2pi and r goes from 0 to 1 our disk coordinates are:

(sin(φ)√r, cos(φ)√r)


To project to the hemisphere we know that sqrt(r) is our radius, and as a right triangle our hypotenuse is 1, so using the Pythagorean theorem a2+z2=1, and in out case a=√r so z=sqrt(1-r).  We then know given our two random numbers (phi,r) our cosine weighted points on the sphere can be found by:

(sin(φ)√r, cos(φ)√r, √1-r)


Now as was the case with the previous point distribution, usually completely random points are not desirable.  One interesting method I've found of generating a nice distribution is to use the golden angle to make the disk points.  So instead of using a random phi value use multiples of the golden angle.


As a bonus sampling idea, there may be some reason that you want to generate points on the disk like above but project them uniformly to the sphere.  One type of projection that could help with that is the Lambert azimuthal equal-area projection, which can be found in detail on Wikipedia here.  Keep in mind to scale your disk to be radius 2 for this projection.


And that's pretty much it for this post!  Sampling the unit sphere is a pretty low-level topic but hopefully these posts have been a useful starting point, especially for someone who might not know what to search for in order to find useful info.

No comments:

Post a Comment

Blending between line segments

Say you have two line segments and you want to blend smoothly from one to the other.  A simple blendshape between the two does not take into...