1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use std::f32;
use rand::{StdRng, Rng};
use light_arena::Allocator;
use scene::Scene;
use linalg::{self, Ray};
use geometry::{Intersection, Emitter, Instance};
use film::Colorf;
use integrator::Integrator;
use bxdf::BxDFType;
use sampler::{Sampler, Sample};
#[derive(Clone, Copy, Debug)]
pub struct Path {
min_depth: usize,
max_depth: usize,
}
impl Path {
pub fn new(min_depth: u32, max_depth: u32) -> Path {
Path { min_depth: min_depth as usize, max_depth: max_depth as usize }
}
}
impl Integrator for Path {
fn illumination(&self, scene: &Scene, light_list: &[&Emitter], r: &Ray,
hit: &Intersection, sampler: &mut Sampler, rng: &mut StdRng,
alloc: &Allocator) -> Colorf {
let num_samples = self.max_depth as usize + 1;
let l_samples = alloc.alloc_slice::<(f32, f32)>(num_samples);
let l_samples_comp = alloc.alloc_slice::<f32>(num_samples);
let bsdf_samples = alloc.alloc_slice::<(f32, f32)>(num_samples);
let bsdf_samples_comp = alloc.alloc_slice::<f32>(num_samples);
let path_samples = alloc.alloc_slice::<(f32, f32)>(num_samples);
let path_samples_comp = alloc.alloc_slice::<f32>(num_samples);
sampler.get_samples_2d(l_samples, rng);
sampler.get_samples_2d(bsdf_samples, rng);
sampler.get_samples_2d(path_samples, rng);
sampler.get_samples_1d(l_samples_comp, rng);
sampler.get_samples_1d(bsdf_samples_comp, rng);
sampler.get_samples_1d(path_samples_comp, rng);
let mut illum = Colorf::black();
let mut path_throughput = Colorf::broadcast(1.0);
let mut specular_bounce = false;
let mut current_hit = *hit;
let mut ray = *r;
let mut bounce = 0;
loop {
if bounce == 0 || specular_bounce {
if let Instance::Emitter(ref e) = *current_hit.instance {
let w = -ray.d;
illum = illum + path_throughput * e.radiance(&w, &hit.dg.p, &hit.dg.ng, ray.time);
}
}
let bsdf = current_hit.material.bsdf(¤t_hit, alloc);
let w_o = -ray.d;
let light_sample = Sample::new(&l_samples[bounce], l_samples_comp[bounce]);
let bsdf_sample = Sample::new(&bsdf_samples[bounce], bsdf_samples_comp[bounce]);
let li = self.sample_one_light(scene, light_list, &w_o, ¤t_hit.dg.p, &bsdf,
&light_sample, &bsdf_sample, ray.time);
illum = illum + path_throughput * li;
let path_sample = Sample::new(&path_samples[bounce], path_samples_comp[bounce]);
let (f, w_i, pdf, sampled_type) = bsdf.sample(&w_o, BxDFType::all(), &path_sample);
if f.is_black() || pdf == 0.0 {
break;
}
specular_bounce = sampled_type.contains(&BxDFType::Specular);
path_throughput = path_throughput * f * f32::abs(linalg::dot(&w_i, &bsdf.n)) / pdf;
if bounce > self.min_depth {
let cont_prob = f32::max(0.5, path_throughput.luminance());
if rng.next_f32() > cont_prob {
break;
}
path_throughput = path_throughput / cont_prob;
}
if bounce == self.max_depth {
break;
}
ray = ray.child(&bsdf.p, &w_i.normalized());
ray.min_t = 0.001;
match scene.intersect(&mut ray) {
Some(h) => current_hit = h,
None => break,
}
bounce += 1;
}
illum
}
}