Here's a method which involves no loops, due to Archimedes (225 BCE). The idea is to randomly sample the enclosed cylinder then map that onto the sphere or hemisphere.
1
2
3
4
5
6
7
8
9
10
11
12 | internal v3
SampleHemisphere(random_series *Series)
{
v3 Result = {};
f32 z = RandomBilateral(Series);
f32 r = SquareRoot(1 - z*z);
f32 theta = RandomBilateral(Series) * 2 * PI;
Result.x = r * Cos(theta);
Result.y = r * Sin(theta);
Result.z = z;
return (Result);
}
|
However, you probably don't actually want to sample the hemisphere uniformly; for light transport, you probably want to include the geometric cosine factor. The easiest way to do this is to randomly sample the unit disk, then map that onto a hemisphere sitting above it.
1
2
3
4
5
6
7
8
9
10
11
12
13 | internal v3
CosineSampleHemisphere(random_series *Series)
{
v3 Result = {};
f32 r2 = RandomBilateral(Series);
f32 r = SquareRoot(r2);
f32 theta = RandomBilateral(Series) * 2 * PI;
f32 z = SquareRoot(1 - r2);
Result.x = r * Cos(theta);
Result.y = r * Sin(theta);
Result.z = z;
return (Result);
}
|