beginner here.
I am implementing importance sampling for environment maps in Scotty3D, a CMU CS project (but I am not a student).
The task can be found here
I have a problem with the sample's pdf, it is unusually small and that results in the object being rendered white even if its albedo is not white.
Here is how I construct the CDF:
// Calculate Lsintheta across the image. Accumulate to normalize the pdf to 1 later.
for (size_t j = 0; j < h; j++) {
for (size_t i = 0; i < w; i++) {
// 0.5f at the pixel center. Else we never sample top and bottom rows
float Lsintheta = image.at(i, j).luma() * sin(PI_F*(j + 0.5f)/h);
total += Lsintheta;
cdf.push_back(total); // Joint Cdf. P(theta, phi)
}
}
So total
would have all the pixels' luminosities. cdf
would actually be the cumulative luminosity.
Next is the sampling and calculating the actual pdf.
float Xi = RNG::unit(); // [0, 1]
auto lower = std::lower_bound(cdf.begin(), cdf.end(), Xi*total); // cdf is not normalized yet. Scale the RV
auto index = std::distance(cdf.begin(), lower);
out_pdf = *lower;
if (index > 0) out_pdf -= cdf[index - 1]; // pdf[index] = cdf[index] - cdf[index - 1]
out_pdf /= total;
Xi
is a uniformly sampled real number from 0 to 1. Then it is multiplied by the total
luminosity in the image to get the sampled accumulated luminosity. Use std::lower_bound
to get the nearest accumulated luminosity greater than or equal to it. Find the index of this nearest accumulated luminosity using std::distance
. Then minus with the previous accumulated luminosity to get the actual luminosity in this pixel. Divide by total
to get the pdf
.
This doesn't work, but if I just do out_pdf = lower/total
it can at least show the right color.
What am I doing/understanding wrong?
out_pdf = lower/total
looks simply wrong AFAICT, as that is a CDF not a PDF. Peter made the point about having it sum up to 4π instead of 1, which would mean the pdf values were too small by about a factor of 12. Could that account for the errors? $\endgroup$