Subversion Repositories gelsvn

Rev

Rev 346 | Go to most recent revision | Blame | Last modification | View Log | RSS feed

#include "path_tracer.hpp"

using namespace CGLA;

path_tracer::path_tracer(int w, int h, bool explicit_direct, int subsamples)
: tracer(w, h)
{
    explicit_direct_ = explicit_direct;
    subsamples_ = subsamples;
}

CGLA::Vec3f path_tracer::trace(const ray& r, bool include_emitted)
{
    //intersect ray with
    hit_info hi;
    bool hit = scene_->intersect(r, hi);

    if (!hit)
        return Vec3f(0.f, 0.5f, 0.f);

    //Vec3f x, y, z = hi.shading_normal;
    //orthogonal(z, x, y);
    //return (Vec3f(hi.texcoords(0),hi.texcoords(1),0) + Vec3f(0.f)) / 1.f;

    //only include emitted light if requested
    CGLA::Vec3f Le(0.f);
    if (include_emitted)
        Le = hi.emitted;

    //compute reflectance for each bsdf component
    float rho_diffuse = intensity(hi.diffuse);
    float rho_glossy = intensity(hi.glossy);
    float rho_reflection = intensity(hi.reflection);
    float rho_refraction = intensity(hi.refraction);
    float rho_total = rho_diffuse+rho_glossy+rho_reflection+rho_refraction;
    assert(rho_total < 1.f);

    if (rho_total == 0.f)
        return Le;

    //compute direct lighting on hit point
    CGLA::Vec3f Ld(0.f);
    Vec3f wo = -r.direction;
    if (explicit_direct_ && rho_diffuse+rho_glossy>0.f)
    {
        size_t nlums = scene_->luminaires();
        for (size_t i=0; i<nlums; ++i)
        {
            const luminaire* lum = scene_->get_luminaire(i);
            int samples = lum->samples();

            Vec3f L(0.f);
            for (int j=0; j<samples; ++j)
            {
                Vec3f Li, wi;
                if (lum->sample(r, hi, Li, wi))
                {
                    float cost = std::max(dot(hi.shading_normal, wi),0.f);
                    L += Li * cost * bsdf_evaluate(hi, wi, wo);
                }

                Ld += L / float(samples);
            }
        }
    }

    //use russian roulette to terminate path
    float prussian = 1.f;
    float rr = mt_random();

    if (r.depth > 3)
    {
        prussian = rho_total;

        if (rr >= prussian)
            return Ld + Le;
    }

    //figure out which bXdf to sample
    float pdiffuse = rho_diffuse/rho_total;
    float pglossy = rho_glossy/rho_total;
    float preflection = rho_reflection/rho_total;
    float prefraction = rho_refraction/rho_total;

    Vec3f wi;
    float pwi;
    Vec3f fs;
    bool sample_emitted = !explicit_direct_;
    if (rr <= pdiffuse)
    {
        //sample diffuse
        float pwi = sample_lambertian(hi, wo, wi);
        fs = lambertian_brdf(hi, wi, wo) / (pwi * pdiffuse * prussian);
    }
    else if (rr <= pdiffuse+pglossy)
    {
        //sample glossy part
        float pwi = sample_phong(hi, wo, wi);

        if (dot(hi.shading_normal, wi) <= 0.f)
            return Le + Ld;

        fs = phong_brdf(hi, wi, wo) / (pwi * pglossy * prussian);
    }
    else if (rr <= pdiffuse+pglossy+preflection)
    {
        //sample perfect specular reflection
        wi = reflect(hi.shading_normal, wo);
        pwi = 1.f;
        float cost = dot(hi.shading_normal, wo);
        fs = hi.reflection / (pwi * preflection * cost);
        sample_emitted = true;
    }
    else if (rr <= pdiffuse+pglossy+preflection+prefraction)
    {
        //sample perfect specular refraction
        bool not_tir = refract(hi.shading_normal, wo, 1.f/hi.ior, wi);
        assert(not_tir);
        pwi = 1.f;
        float cost = std::abs(dot(hi.shading_normal, wi));
        fs = hi.refraction / (pwi * prefraction * cost);
        sample_emitted = true;
    }
    else
        assert(false);

    //create aux ray
    ray s;
    s.origin = hi.position + epsilon * wi;
    s.direction = wi;
    s.depth = r.depth + 1;
    s.distance = std::numeric_limits<float>::infinity();
    float cost = std::abs(dot(hi.shading_normal, wi));
    Vec3f Li = cost * fs * trace(s, sample_emitted);

    //returm sum of emitted + direct + indirect
    return Le + Ld + Li;
}

Vec3f path_tracer::compute_pixel(int w, int h)
{
    assert(scene_);

    //supersample
    Vec3f L(0.f);
    for (int j=0; j<subsamples_; ++j)
    {
        float y  = h + (j + 0.5f) / subsamples_;

        for (int i=0; i<subsamples_; ++i)
        {
            float x  = w + (i + 0.5f) / subsamples_;

            //ask camera for initial ray..
            Vec2f uv(x/width_, y/height_);
            ray r = scene_->get_camera()->generate(uv);

            //trace ray
            L += trace(r, true);
        }
    }

    return L / float(subsamples_ * subsamples_);
}

//02566 framework, Anders Wang Kristensen, awk@imm.dtu.dk, 2007

Generated by GNU Enscript 1.6.6.