Rev 346 | 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.