pbrt_r3/integrators/
ao.rs

1use crate::core::prelude::*;
2
3use std::sync::Arc;
4use std::sync::RwLock;
5
6use log::*;
7
8pub struct AOIntegrator {
9    base: BaseSamplerIntegrator,
10    cos_sample: bool,
11    n_samples: u32,
12}
13
14impl AOIntegrator {
15    pub fn new(
16        cos_sample: bool,
17        ns: u32,
18        camera: &Arc<dyn Camera>,
19        sampler: &Arc<RwLock<dyn Sampler>>,
20        pixel_bounds: &Bounds2i,
21    ) -> Self {
22        let n_samples = sampler.read().unwrap().round_count(ns);
23        if ns != n_samples {
24            warn!(
25                "Rounding AO samples to {} (from {} specified).",
26                n_samples, ns
27            );
28        }
29        sampler.write().unwrap().request_2d_array(n_samples);
30        AOIntegrator {
31            base: BaseSamplerIntegrator::new(camera, sampler, pixel_bounds),
32            cos_sample,
33            n_samples,
34        }
35    }
36}
37
38impl Integrator for AOIntegrator {
39    fn render(&mut self, scene: &Scene) {
40        BaseSamplerIntegrator::render(self, scene);
41    }
42
43    fn get_camera(&self) -> Arc<dyn Camera> {
44        return self.base.camera.clone();
45    }
46}
47
48impl SamplerIntegrator for AOIntegrator {
49    fn li(
50        &self,
51        r: &RayDifferential,
52        scene: &Scene,
53        sampler: &mut dyn Sampler,
54        arena: &mut MemoryArena,
55        _depth: i32,
56    ) -> Spectrum {
57        let _p = ProfilePhase::new(Prof::SamplerIntegratorLi);
58
59        let mut l = Spectrum::zero();
60        let mut ray = r.clone();
61
62        let cos_sample = self.cos_sample;
63        let n_samples = self.n_samples as u32;
64        // Intersect _ray_ with scene and store intersection in _isect_
65        loop {
66            if let Some(mut isect) = scene.intersect(&ray.ray) {
67                isect.compute_scattering_functions(&ray, arena, TransportMode::Radiance, true);
68                if isect.bsdf.is_none() {
69                    ray = isect.spawn_ray(&ray.ray.d).into();
70                    continue;
71                }
72                // Compute coordinate frame based on true geometry, not shading
73                // geometry.
74                let n = face_forward(&isect.n, &-ray.ray.d);
75                let s = isect.dpdu.normalize();
76                let t = Vector3f::cross(&isect.n, &s);
77
78                let u = sampler.get_2d_array(n_samples).unwrap();
79                for i in 0..u.len() {
80                    let (wi, pdf) = if cos_sample {
81                        let wi = cosine_sample_hemisphere(&u[i]);
82                        let pdf = cosine_hemisphere_pdf(wi.z.abs());
83                        (wi, pdf)
84                    } else {
85                        let wi = uniform_sample_hemisphere(&u[i]);
86                        let pdf = uniform_hemisphere_pdf();
87                        (wi, pdf)
88                    };
89
90                    // Transform wi from local frame to world space.
91                    let wi = Vector3f::new(
92                        wi.x * s.x + wi.y * t.x + wi.z * n.x,
93                        wi.x * s.y + wi.y * t.y + wi.z * n.y,
94                        wi.x * s.z + wi.y * t.z + wi.z * n.z,
95                    );
96                    if !scene.intersect_p(&isect.spawn_ray(&wi)) {
97                        l += Spectrum::from(wi.dot(&n) / (pdf * n_samples as Float));
98                    }
99                }
100            }
101            break;
102        }
103        return l;
104    }
105
106    fn get_sampler(&self) -> Arc<RwLock<dyn Sampler>> {
107        return Arc::clone(&self.base.sampler);
108    }
109
110    fn get_pixel_bounds(&self) -> Bounds2i {
111        return self.base.pixel_bounds;
112    }
113}
114
115unsafe impl Sync for AOIntegrator {}
116
117pub fn create_ao_integrator(
118    params: &ParamSet,
119    sampler: &Arc<RwLock<dyn Sampler>>,
120    camera: &Arc<dyn Camera>,
121) -> Result<Arc<RwLock<dyn Integrator>>, PbrtError> {
122    let pixel_bounds = camera.get_film().read().unwrap().get_sample_bounds();
123    let cos_sample = params.find_one_bool("cossample", true);
124    let mut n_samples = params.find_one_int("nsamples", 64);
125    {
126        let options = PbrtOptions::get();
127        if options.quick_render {
128            n_samples = 1;
129        }
130    }
131    Ok(Arc::new(RwLock::new(AOIntegrator::new(
132        cos_sample,
133        n_samples as u32,
134        camera,
135        sampler,
136        &pixel_bounds,
137    ))))
138}