Cosine weighted hemisphere

image

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

image

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

image

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/

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

8 Responses to Cosine weighted hemisphere

  1. IRYOKU says:

    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 🙂

  2. davepermen says:

    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;

  3. oseiskar says:

    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)

  4. Prog says:

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

  5. Jonas Collberg says:

    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.

  6. Pingback: Sample uniform direction within cone - MathHub

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s