pbrt_r3/integrators/
ao.rs1use 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 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 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 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}