color(direction_out) = INTEGRAL brdf(direction_in, direction_out) cosine
the domain of integration is all direction_in coming from the sphere of all directions. Often the brdf is zero for directions from inside the surface so it's the hemisphere.
Basic Monte Carlo integration says that if you choose a random direction_in with pdf pdf(direction_in), the unbiased estimate is:
color(direction_out) = brdf(direction_in, direction_out) cosine / pdf(direction_in)
As long as you can generate random direction_in, and can compute pdf(direction_in) then you have a working ray tracer. It works best when you are likely to cast random rays toward bright areas like lights. If you sample a polygonal light, you normally just sample q uniformly on the area. The direction is just q-p. The key observation to get from the pdf in area space p_area(q) = 1/A (where A is the area of the light) is that by definition the probability of q being in a small area dA is
probability = p_area(q) dA
Similarly the directional pdf of a direction toward dA is:
probability = pdf(q-p) dw
Those probabilities must be the same:
p_area(q) dA = pdf(q-p) dw
By algebra:
pdf(q-p) = p_area(q) dA/dw = (1/A) (dA/dw)
But what is (dA/dw)?
Let's do some basic geometry. As is so often the case, the right figure makes that tons easier:
You pick a point q on the light with pdf 1/A in area space, but what is the pdf in directional space? Drawn in limnu whitboarding program. |
If dA faces p dead-on (so its normal faces p), then it's foreshotening:
dw = dA/distance_squared
But if dA is tilted then we get a cosine shift:
dw = dA*cosine / distance_squared
So recall we are after
pdf(q-p) = (1/A) (dA/dw)
So we can plug and chug to get:
pdf(q-p) =length_sqaured(q-p) / (A*cosine)
We just apply this formula directly in our code. For my xz rectangle class this is:
Great explanation!
ReplyDeleteI found this explanation more clear than the one presented in the book.
ReplyDeleteIt's probably a good idea to rename p_q(q) to p_area(q) in the book for clarity.