pbrt_r3/integrators/
whitted.rs1use crate::core::prelude::*;
2
3use std::sync::Arc;
4use std::sync::RwLock;
5
6pub struct WhittedIntegrator {
7 pub base: BaseSamplerIntegrator,
8 pub max_depth: i32,
9}
10
11impl WhittedIntegrator {
12 pub fn new(
13 max_depth: i32,
14 camera: &Arc<dyn Camera>,
15 sampler: &Arc<RwLock<dyn Sampler>>,
16 pixel_bounds: &Bounds2i,
17 ) -> Self {
18 WhittedIntegrator {
19 base: BaseSamplerIntegrator::new(camera, sampler, pixel_bounds),
20 max_depth,
21 }
22 }
23}
24
25impl Integrator for WhittedIntegrator {
26 fn render(&mut self, scene: &Scene) {
27 BaseSamplerIntegrator::render(self, scene);
28 }
29
30 fn get_camera(&self) -> Arc<dyn Camera> {
31 return Arc::clone(&self.base.camera);
32 }
33}
34
35unsafe impl Sync for WhittedIntegrator {}
36
37impl SamplerIntegrator for WhittedIntegrator {
38 fn li(
39 &self,
40 ray: &RayDifferential,
41 scene: &Scene,
42 sampler: &mut dyn Sampler,
43 arena: &mut MemoryArena,
44 depth: i32,
45 ) -> Spectrum {
46 let _p = ProfilePhase::new(Prof::SamplerIntegratorLi);
47
48 if let Some(mut isect) = scene.intersect(&ray.ray) {
49 assert!(isect.n.length() > 0.0);
50 assert!(isect.shading.n.length() > 0.0);
51
52 let n = isect.shading.n;
53 let wo = isect.wo;
54
55 isect.compute_scattering_functions(ray, arena, TransportMode::Radiance, false);
56
57 let tisect = Interaction::from(isect);
58 let isect = tisect.as_surface_interaction().unwrap();
59
60 if let Some(bsdf) = isect.bsdf.as_ref() {
61 let mut l = scene
63 .lights
64 .iter()
65 .map(|light| -> Spectrum {
66 let lt = light.as_ref();
67 let u = sampler.get_2d();
68 if let Some((li, wi, pdf, visibility)) = lt.sample_li(&tisect, &u) {
69 if !(pdf <= 0.0 || li.is_black()) {
70 let f = bsdf.f(&wo, &wi, BSDF_ALL);
71 if !f.is_black() && visibility.unoccluded(scene) {
72 return f * li * (Vector3f::abs_dot(&wi, &n) / pdf);
74 }
75 }
76 }
77 return Spectrum::zero();
78 })
79 .fold(Spectrum::zero(), |a, b| {
80 return a + b;
81 });
82 if depth + 1 < self.max_depth {
83 l += self.specular_reflect(ray, isect, scene, sampler, arena, depth);
84 l += self.specular_transmit(ray, isect, scene, sampler, arena, depth);
85 }
86 return l;
87 }
88 return Spectrum::zero();
89 } else {
90 let l = scene
91 .lights
92 .iter()
93 .map(|light| -> Spectrum {
94 return light.as_ref().le(ray);
95 })
96 .fold(Spectrum::zero(), |a, b| {
97 return a + b;
98 });
99 return l;
100 }
101 }
102
103 fn get_sampler(&self) -> Arc<RwLock<dyn Sampler>> {
104 return Arc::clone(&self.base.sampler);
105 }
106
107 fn get_pixel_bounds(&self) -> Bounds2i {
108 return self.base.pixel_bounds;
109 }
110}
111
112pub fn create_whitted_integrator(
113 params: &ParamSet,
114 sampler: &Arc<RwLock<dyn Sampler>>,
115 camera: &Arc<dyn Camera>,
116) -> Result<Arc<RwLock<dyn Integrator>>, PbrtError> {
117 let max_depth = params.find_one_int("maxdepth", 5);
118 let film = camera.as_ref().get_film();
119 let mut pixel_bounds = film.read().unwrap().get_sample_bounds();
120 if let Some(pb) = params.get_ints_ref("pixelbounds") {
121 if pb.len() >= 4 {
122 pixel_bounds = Bounds2i::from(((pb[0], pb[2]), (pb[1], pb[3])));
123 }
124 }
125 return Ok(Arc::new(RwLock::new(WhittedIntegrator::new(
126 max_depth,
127 camera,
128 sampler,
129 &pixel_bounds,
130 ))));
131}