Environment map importance sampling (beginner) 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 &lt; h; j++) {
    for (size_t i = 0; i &lt; 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 &gt; 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?
From all other implementations I have seen, you generally sample twice, once in the Y dimension to select a row and then once in the X dimension to selct the pixel from this row.
I am not sure if this is necissary, maybe you're one dimensional sampling is fine.
I think you also need to multiply your pdf so that it is relative to solid angle (so it's total sums to 4pi).
You should be able to do this by dividing by (2 * Pi * Pi * sinTheta).
PBRT is probably the best textbook to help you. You can find it online here:
http://www.pbr-book.org/
The source code is also available. Here is the code for the environment light:
https://github.com/mmp/pbrt-v3/blob/aaa552a4b9cbf9dccb71450f47b268e0ed6370e2/src/lights/infinite.cpp
and the code for the Distribution2D sampler:
https://github.com/mmp/pbrt-v3/blob/aaa552a4b9cbf9dccb71450f47b268e0ed6370e2/src/core/sampling.h