2
$\begingroup$

I'm having a lot of trouble implementing Importance Sampling path tracer.

If I understand it correctly, what I need to evaluate for a path tracer is this:
$\int_\Omega L_{in}(L) * fr(L, V) * \cos(\Theta_L) d\omega_L$

Which for an Importance sampling PT is estimated by sampling $n$ times $L_i$ according to some pdf $p(L)$, i.e.:
$\frac{1}{M} * \sum_1^n L_{in}(L) * \frac{fr(L, V) * \cos(\Theta_L)}{p(L_i)}$

Which in it's simplest form, for a single sample of a recursive reverse Path Tracer using an environment map, translates to roughly this pseudocode:

trace(scene, ray, throughput, depth) =
    if(depth > ...)
         return 0
    else
        intersection, normal, material = intersect(ray, scene)
        if(intersection)
            new_ray = material.sample_direction(normal, ray)
            new_throughput = material.brdf(normal, ray, new_ray)
                           * cos(normal, new_ray)
                           / material.pdf(normal, ray, new_ray)
            return trace(scene, new_ray, new_throughut, depth + 1)
        else
            return throughput * environment(ray)

Usually the $brdf * cos(theta)$ and the $pdf$ would be similar. In my case for Lambertian importance sampling, they are equal.

What I think this means is that if, instead of importance sampling the material, I sample a random direction in the "$normal$-oriented" hemisphere, and use constant $\frac{1}{2 * PI}$ for the pdf, the radiance (for a sufficient number of samples) should be equal (up to some trivial variance):

trace(scene, ray, throughput, depth) =
    if(depth > ...)
         return 0
    else
        intersection, normal, material = intersect(ray, scene)
        if(intersection)
            new_ray = sample_uniform_hemisphere(normal, ray)
            new_throughput = material.brdf(normal, ray, new_ray)
                           * cos(normal, new_ray)
                           / (1/(2 * PI))        
            return trace(scene, new_ray, new_throughut, depth + 1)
        else
            return throughput * environment(ray)

Instead, even for trivial Lambertian materials, IF i switch the sampling pdfs in a checkerboard pattern, it shows a large difference in luminance:
enter image description here
Switching sampling PDFs in a checkerboard pattern shows a difference in luminance

For more complex materials the problem is MUCH worse.

The actual Lambert implementation is (note the albedo is separated out):

glm::vec3 lambert::sample(glm::vec3 n, glm::vec3 v) const
{
    glm::vec2 xi{drand48(), drand48()};
    float th = acosf(sqrtf(xi.x));
    float ph = 2 * M_PIf32 * xi.y;
    glm::vec3 dir{sinf(th) * cosf(ph), sinf(th) * sinf(ph), cosf(th)};
    return local_to_normal(dir, n);
}

float lambert::bxdf(glm::vec3 n, glm::vec3 v, glm::vec3 l) const
{
    return M_1_PIf32;
}

float lambert::pdf(glm::vec3 n, glm::vec3 v, glm::vec3 l) const
{
    return glm::dot(n, l) * M_1_PIf32;
}

The actual trace routine is:

auto trace(ray r, scene const &s)
{
       float throughput = 1.0f;
       for(int num_bounces = 0; num_bounces < 6; ++num_bounces) {
           auto &&[i, hit] = intersect_scene(r, s);
           if(!i) {
                   return throughput * sample_environment(r.dir, s.environment);
           }
           auto out_direction = hit.mat->sample(hit.x_norm, -r.dir);
           throughput *= hit.mat->albedo * hit.mat->bxdf(hit.normal, -r.dir, out_direction)  * glm::dot(hit.normal, out_direction)/ hit.mat->pdf(hit.normal, -r.dir, out_direction);
           r.src = hit.pos + hit.normal * 1e-4f;
           r.dir = out_direction;    
       }
       return 0.f;
}

For the uniform hemispherical sampling I use this:

    auto const r = sqrtf(1.f - u1 * u1);
    auto const phi = 2 * M_PIf32 * u2;
    return {r * cosf(phi), r * sinf(phi), u1};

And then change the basis to the intersection normal again.

Please, if anyone has any idea could you please help?

I can provide more of the project if it's necessary.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.