In the above picture you can see the sampling points from uniform hemisphere sampling.

The left images shows cosine-weighted sampling of the hemisphere – the right uniform sampling (both with 100 000 sampling points)

The top hemisphere shows cosine-weighted sampling – the bottom hemisphere shows uniform sampling (both with 100 000 sampling points).

If you only use 100 or 1000 sampling points it is very hard to see actually a difference between both sampling methods.

The code for uniform sampling:

vector3f UniformRandomHemisphereDirection( normal3f n )
{
int abortCounter = 0;
while(true)
{
vector3f b(randomFloat() - 0.5f, randomFloat() - 0.5f, randomFloat() - 0.5f);
b.normalize();
if (b * n > 0)
{
return b;
}
abortCounter++;
if (abortCounter > 500)
{
return b; // for some reason (NaN's perhaps) we don't found a normal
}
}
}

The code for cosine-weighted sampling:

vector3f CosWeightedRandomHemisphereDirection2( normal3f n )
{
float Xi1 = (float)rand()/(float)RAND_MAX;
float Xi2 = (float)rand()/(float)RAND_MAX;
float theta = acos(sqrt(1.0-Xi1));
float phi = 2.0 * 3.1415926535897932384626433832795 * Xi2;
float xs = sinf(theta) * cosf(phi);
float ys = cosf(theta);
float zs = sinf(theta) * sinf(phi);
vector3f y(n.x, n.y, n.z);
vector3f h = y;
if (fabs(h.x)<=fabs(h.y) && fabs(h.x)<=fabs(h.z))
h.x= 1.0;
else if (fabs(h.y)<=fabs(h.x) && fabs(h.y)<=fabs(h.z))
h.y= 1.0;
else
h.z= 1.0;
vector3f x = (h ^ y).normalize();
vector3f z = (x ^ y).normalize();
vector3f direction = xs * x + ys * y + zs * z;
return direction.normalize();
}

The same topic is discussed here: http://www.rorydriscoll.com/2009/01/07/better-sampling/

### Like this:

Like Loading...

This line: float theta = acos(sqrt(1.0-Xi1));

Should not be: float theta = acos(Xi1);

See slide 30 here:

http://web.cs.wpi.edu/~emmanuel/courses/cs563/S07/talks/emmanuel_agu_mc_wk10_p2.pdf

The sqrt is seen on r,phi formulations not in phi,theta (AFAIK):

http://www.rorydriscoll.com/2009/01/07/better-sampling/

But I may be misunderstanding something 🙂

Actually nevermind, I’m wrong! Feel free to delete the comments!

in your UniformRandomHemisphereDirection method, instead of looping and aborting and stuff, just return the negative direction if it faces into the wrong one. that way, it’ll always face properly.

essentially this:

return fabs(b * n) * b;

The lines

vector3f b(randomFloat() – 0.5f, randomFloat() – 0.5f, randomFloat() – 0.5f);

b.normalize();

are incorrect (unless randomFloat samples from a Gaussian distribution with mean 0.5). You should add a rejection step (reject if b.norm() > 1.0) before normalization to obtain uniformly distributed points in a ball. (see http://en.wikipedia.org/wiki/Rejection_sampling)

Can someone please explain what (h ^ y) does in CosWeightedRandomHemisphereDirection2? Thanks.

It’s the cross product but the author forgot to mention that.

Prog> The ^ operator must be the cross product. He’s calculating two tangential vectors (x and z) that are perpendicular to both the normal and each other. This is done to transform from the local coordinate system (where the y-axis goes towards the “north pole” of the hemisphere) to the world coordinate system. So he basically rotates the y-axis so that it aligns with the normal n.

Pingback: Sample uniform direction within cone - MathHub