RayTracing / raytracing.github.io

Main Web Site (Online Books)
https://raytracing.github.io/
Creative Commons Zero v1.0 Universal
8.72k stars 856 forks source link

Book 3.6.2 Invalid Monte Carlo Integration (?) #1598

Closed tGautot closed 1 month ago

tGautot commented 1 month ago

Hello!

Let me preface this with an enormous ¨Thank You" to everyone who has worked on putting this amazing series together, I have been eating it over the last two weeks and it has been a blast.

I recently started book 3 and I am a bit confused about the work done in section 6.2, since this could absolutely be a lack of understanding on my side I'll try to lay out my understanding so as to not loose time in case this is not a problem of the material but only of me.

In the previous section we set up the ground work to understand how to approximate integrals using Monte Carlo Integration. In our case we want to find a value for the following integral:

$$ Color_o(\mathbf{x}, \omegao, \lambda) = \int{\omega_i} A(\mathbf{x}, \omega_i, \omega_o, \lambda)pScatter(\mathbf{x}, \omega_i, \omega_o, \lambda)Color_i(\mathbf{x}, \omega_i, \omega_o, \lambda) $$

Or, more simply, relating to what we have at that point in the code:

$$ Color_o(\omegao) = \int{\omega_i} A(\omega_i, \omega_o)pScatter(\omega_i, \omega_o)Color_i(\omega_i, \omega_o) $$

Linking these symbols with what we have in the code, $\omega_o$ is the direction of the ray we send to the world (i.e, the ray sent from any call of ray_color) and $\omega_i$ is the direction of the scattered ray (which will then become $\omega_o$ in the next ray_colorcall since the function is recursive) So based on the Monte Carlo formula, we are evaluating the following expression:

$$ Color_o(\omega_o) \approx \frac{1}{N} \sum_1^N \frac{A(\omega_i, \omega_o)pScatter(\omega_i, \omega_o)Color(\omega_i, \omega_o) }{p(\omega_i)} $$

Where $\omega_i$ has be chosen randomly according to the PDF $p$. However when looking at the code provided for this section (Listing 20):

image

We see that $\omega_i$ (scattered) is obtained via the material's scatter function which, at this point is the default lambertian scatter function (surface normal + random unit vector), and not at all obtained via a sampling of the uniform PDF (i.e. getting a random vector in the hemisphere). This looks (to me) very contradictory with the theory, is there something I am missing, or is this an oversight?

An additional element could be the uncharacteristically bright image produced by this code, here is the base picture (from section 6.1): image Versus the image obtained with the code above: image

Note that I have done some tests on my side, I have tested:

  1. Sampling a cosine pdf (i.e. with the original lambertian scatter implementation), dividing by this the same pdf (with the formula derived for scattering_pdf in section 6.1)
  2. Sampling a uniform pdf (i.e random vector in hemisphere), dividing by 2*PI
  3. Sampling a cosine pdf, dividing by 2*PI

You can see the results of these 3 tests below, there aren't too many rays so its quite noisy, but you can see that 1 and 2 are very similar (with 2 being, expectedly, a bit noisier), but 3 is once again very bright.

1. cornell_cosine_lambertian 2. cornell_uniform_lambertian 3. cornell_misfit_original_scatter_lambertian

If anyone could shed some light (you are free to re-use that pun) on this situation and explain what is happening, you would put an end to two and a half days of hair-grabbing.

tGautot commented 1 month ago

I don't know how I missed it but this is a duplicate of #1302 just with the math more clearly written, I'll close this and add my comments there