pbrt_r3/integrators/
directlighting.rs

1use crate::core::prelude::*;
2
3use std::sync::Arc;
4use std::sync::RwLock;
5
6#[derive(Copy, Clone, Debug, PartialEq)]
7pub enum DirectLightingLightStrategy {
8    UniformSampleAll,
9    UniformSampleOne,
10}
11
12type LightStrategy = DirectLightingLightStrategy;
13
14pub struct DirectLightingIntegrator {
15    base: BaseSamplerIntegrator,
16    strategy: LightStrategy,
17    max_depth: i32,
18    n_light_samples: Vec<u32>,
19}
20
21impl DirectLightingIntegrator {
22    pub fn new(
23        strategy: LightStrategy,
24        max_depth: i32,
25        camera: &Arc<dyn Camera>,
26        sampler: &Arc<RwLock<dyn Sampler>>,
27        pixel_bounds: &Bounds2i,
28    ) -> Self {
29        DirectLightingIntegrator {
30            base: BaseSamplerIntegrator::new(camera, sampler, pixel_bounds),
31            strategy,
32            max_depth,
33            n_light_samples: Vec::new(),
34        }
35    }
36}
37
38impl Integrator for DirectLightingIntegrator {
39    fn render(&mut self, scene: &Scene) {
40        BaseSamplerIntegrator::render(self, scene);
41    }
42
43    fn get_camera(&self) -> Arc<dyn Camera> {
44        return Arc::clone(&self.base.camera);
45    }
46}
47
48unsafe impl Sync for DirectLightingIntegrator {}
49
50impl SamplerIntegrator for DirectLightingIntegrator {
51    fn preprocess(&mut self, scene: &Scene, sampler: &mut dyn Sampler) {
52        if self.strategy == LightStrategy::UniformSampleAll {
53            for light in scene.lights.iter() {
54                let count = sampler.round_count(light.as_ref().get_sample_count());
55                self.n_light_samples.push(count);
56            }
57            for _ in 0..self.max_depth {
58                for j in 0..scene.lights.len() {
59                    let n = self.n_light_samples[j];
60                    sampler.request_2d_array(n);
61                    sampler.request_2d_array(n);
62                }
63            }
64        }
65    }
66    fn li(
67        &self,
68        ray: &RayDifferential,
69        scene: &Scene,
70        sampler: &mut dyn Sampler,
71        arena: &mut MemoryArena,
72        depth: i32,
73    ) -> Spectrum {
74        let _p = ProfilePhase::new(Prof::SamplerIntegratorLi);
75
76        if let Some(mut isect) = scene.intersect(&ray.ray) {
77            let wo = isect.wo;
78
79            isect.compute_scattering_functions(ray, arena, TransportMode::Radiance, false);
80
81            let tisect = Interaction::from(isect);
82            let isect = tisect.as_surface_interaction().unwrap();
83
84            if isect.bsdf.is_some() {
85                let mut l = isect.le(&wo);
86                if !scene.lights.is_empty() {
87                    match self.strategy {
88                        LightStrategy::UniformSampleAll => {
89                            l += uniform_sample_all_lights(
90                                &tisect,
91                                scene,
92                                arena,
93                                sampler,
94                                &self.n_light_samples,
95                                false,
96                            );
97                        }
98                        LightStrategy::UniformSampleOne => {
99                            l += uniform_sample_one_light(
100                                &tisect, scene, arena, sampler, false, None,
101                            );
102                        }
103                    }
104                }
105                if depth + 1 < self.max_depth {
106                    l += self.specular_reflect(ray, isect, scene, sampler, arena, depth);
107                    l += self.specular_transmit(ray, isect, scene, sampler, arena, depth);
108                }
109                return l;
110            } else {
111                let rd = RayDifferential::from(isect.spawn_ray(&ray.ray.d));
112                return self.li(&rd, scene, sampler, arena, depth);
113            }
114        } else {
115            let l = scene
116                .lights
117                .iter()
118                .map(|light| -> Spectrum {
119                    return light.as_ref().le(ray);
120                })
121                .fold(Spectrum::zero(), |a, b| {
122                    return a + b;
123                });
124            return l;
125        }
126    }
127
128    fn get_sampler(&self) -> Arc<RwLock<dyn Sampler>> {
129        return Arc::clone(&self.base.sampler);
130    }
131
132    fn get_pixel_bounds(&self) -> Bounds2i {
133        return self.base.pixel_bounds;
134    }
135}
136
137pub fn create_direct_lighting_integrator(
138    params: &ParamSet,
139    sampler: &Arc<RwLock<dyn Sampler>>,
140    camera: &Arc<dyn Camera>,
141) -> Result<Arc<RwLock<dyn Integrator>>, PbrtError> {
142    let max_depth = params.find_one_int("maxdepth", 5);
143    let st = params.find_one_string("strategy", "all");
144    let sterategy = if st == "one" {
145        LightStrategy::UniformSampleOne
146    } else {
147        LightStrategy::UniformSampleAll
148    };
149    let film = camera.as_ref().get_film();
150    let pixel_bounds = film.read().unwrap().get_sample_bounds();
151
152    return Ok(Arc::new(RwLock::new(DirectLightingIntegrator::new(
153        sterategy,
154        max_depth,
155        camera,
156        sampler,
157        &pixel_bounds,
158    ))));
159}