Subversion Repositories gelsvn

Rev

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);

        //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 = 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.