pbrt_r3/integrators/
whitted.rs

1use 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                //return Spectrum::one();
62                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                                    //let dot = Float::max(Vector3f::dot(&wi, &n), 0.0);
73                                    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}