Friday, September 12, 2014

Random diffuse rays

In my lazy coding for the path tracer in the last post I chose a ray that is uniformly random in direction but above the surface.  I used a pretty standard trick here.  First I choose a point in the cube [-1,1]^3.  Then I see if it is in the sphere r < 1.

do {
      scattered_direction = vec3(x: -1.0 + 2.0*drand48(), y: -1.0 + 2.0*drand48(), z: -1.0 + 2.0*drand48())
 } while dot(scattered_direction,scattered_direction) > 1.0


Then I stick a loop around that to test until

while dot(scattered_direction, hit_info.2) < 0.001

Here hit_info.2 is the surface normal.   I could go in and produce correct diffuse rays, but that would involve coordinate systems and all that.  Instead I wondered if I could use the trick shown on the right below:
Left: choose a point in the cube, and keep it if it is in the sphere, and keep that if it is above the normal.  Right, pick the cube (not shown) and then keep if in sphere and that is it (they are all above the normal).
It's not obvious to me that this is Lambertian, but it might be.  But it's probably closer than the one on the left.   I dumped that code in (excuse the lazy reuse of variables):

 do {
      scattered_direction = vec3(x: -1.0 + 2.0*drand48(), y: -1.0 + 2.0*drand48(), z: -1.0 + 2.0*drand48())
 } while dot(scattered_direction,scattered_direction) > 1.0
 let sphere_tangent_point = -unit_vector(hit_info.2)
 scattered_direction = scattered_direction - sphere_tangent_point


And this yields:

uniform rays
diffuseish rays


















Looks like darker shadows which makes sense: rays go straight up.  It would require some calculus to see if the rays are Lambertian, and this was an exercise to avoid work so I am not doing that.  My money is on it being more oriented to the normal than true diffuse, but not bad.

5 comments:

friedlinguini said...

I came up with the same technique some years back. My reasoning was that a cosine plotted in polar coordinates looks like a circle, which would be the equivalent of a cosine distribution in 2D. In 3D that would be it would look like a sphere (mumble, handwave, something about the cross section and rotational symmetry around the normal). Treat that sphere as a PDF, uniformly sample inside the sphere, and you're using rejection sampling to generate directions with a cosine distribution about the normal. I didn't try a more formal proof, but it looked good enough in the toy path tracer I was writing.

Peter Shirley said...

I like that logic. My only concern is the "beams" in a certain direction get fatter so it may grow faster than cosine theta. Let's put our programming hat on and figure out a way to test it empirically. Some numercal integration of a known integral maybe?

Andrew P. Agosto said...

After a long time I got something fresh and quality content on massage therapy services. I searched a lot for the related material but got almost replica work. Keep it up! It is really very informative. clipping path

Unknown said...

Simply desire to say your article is as astonishing. The clearness in your post is just excellent and i could assume you are an expert on this subject. Fine with your permission let me to grab your feed to keep up to date with forthcoming post. Thanks a million and please continue the rewarding work. clipping path

Unknown said...

I don't understand why you say the method on the right is probably closer to being Lambertian than the one on the left. Isn't a Lambertian BRDF simply one that "scatters incident illumination equally in all directions"? (Physically Based Rendering, 2nd ed, Pharr & Humphreys, p. 446.) So isn't the one on the left (the hemisphere) actually just purely Lambertian, ignoring any side effects of drand48? Is it maybe because the sampling occurs inside the volume of a sphere rather than on the surface of a sphere?