pbrt_r3/integrators/
aov.rs

1use crate::core::prelude::*;
2
3use std::sync::Arc;
4use std::sync::RwLock;
5
6#[derive(Debug, Clone, Copy)]
7pub enum AOVTarget {
8    Distance,
9    Depth,
10    N,
11    NS,
12    UV,
13    RDXC,
14    RDYC,
15    DRODX,
16    DRDDX,
17    DPDX,
18    DPDY,
19    DPDU,
20    DPDV,
21    DUVDX,
22    DUVDY,
23    DPDUS,
24    DPDVS,
25}
26
27fn get_aov_target(name: &str) -> Result<AOVTarget, PbrtError> {
28    match name {
29        "distance" => Ok(AOVTarget::Distance),
30        "depth" => Ok(AOVTarget::Depth),
31        "n" => Ok(AOVTarget::N),
32        "ng" => Ok(AOVTarget::N),
33        "ns" => Ok(AOVTarget::NS),
34        "uv" => Ok(AOVTarget::UV),
35        "rdxc" => Ok(AOVTarget::RDXC),
36        "rdyc" => Ok(AOVTarget::RDYC),
37        "drodx" => Ok(AOVTarget::DRODX),
38        "drddx" => Ok(AOVTarget::DRDDX),
39        "dpdx" => Ok(AOVTarget::DPDX),
40        "dpdy" => Ok(AOVTarget::DPDY),
41        "dpdu" => Ok(AOVTarget::DPDU),
42        "dpdv" => Ok(AOVTarget::DPDV),
43        "dstdx" => Ok(AOVTarget::DUVDX),
44        "dstdy" => Ok(AOVTarget::DUVDY),
45        "duvdx" => Ok(AOVTarget::DUVDX),
46        "dpdus" => Ok(AOVTarget::DPDUS),
47        "dpdvs" => Ok(AOVTarget::DPDVS),
48        "shading.n" => Ok(AOVTarget::NS),
49        "shading.dpdu" => Ok(AOVTarget::DPDUS),
50        "shading.dpdv" => Ok(AOVTarget::DPDVS),
51        _ => {
52            let msg = format!("AOV target \"{}\" unknown.", name);
53            return Err(PbrtError::error(&msg));
54        }
55    }
56}
57
58fn v2c(v: &Vector3f) -> Spectrum {
59    let v = 0.5 * *v + Vector3f::from(0.5);
60    let rgb = [v.x, v.y, v.z];
61    return spectrum_from_rgb(&rgb);
62}
63
64fn spectrum_from_rgb(rgb: &[Float; 3]) -> Spectrum {
65    return Spectrum::from(rgb).clamp(0.0, 1.0);
66}
67
68pub struct AOVIntegrator {
69    base: BaseSamplerIntegrator,
70    target: AOVTarget,
71    scale: Float,
72}
73
74impl AOVIntegrator {
75    pub fn new(
76        camera: &Arc<dyn Camera>,
77        sampler: &Arc<RwLock<dyn Sampler>>,
78        pixel_bounds: &Bounds2i,
79        target: AOVTarget,
80        scale: Float,
81    ) -> Self {
82        AOVIntegrator {
83            base: BaseSamplerIntegrator::new(camera, sampler, pixel_bounds),
84            target,
85            scale,
86        }
87    }
88}
89
90impl Integrator for AOVIntegrator {
91    fn render(&mut self, scene: &Scene) {
92        BaseSamplerIntegrator::render(self, scene);
93    }
94
95    fn get_camera(&self) -> Arc<dyn Camera> {
96        return self.base.camera.clone();
97    }
98}
99
100impl SamplerIntegrator for AOVIntegrator {
101    fn li(
102        &self,
103        r: &RayDifferential,
104        scene: &Scene,
105        _sampler: &mut dyn Sampler,
106        arena: &mut MemoryArena,
107        _depth: i32,
108    ) -> Spectrum {
109        let _p = ProfilePhase::new(Prof::SamplerIntegratorLi);
110
111        let scale = self.scale;
112        if let Some(mut si) = scene.intersect(&r.ray) {
113            si.compute_scattering_functions(r, arena, TransportMode::Radiance, true);
114            match self.target {
115                AOVTarget::Distance => {
116                    let dist = r.ray.t_max.get() / r.ray.d.length();
117                    return spectrum_from_rgb(&[dist, dist, dist]) * scale;
118                }
119                AOVTarget::Depth => {
120                    let dist = si.p - r.ray.o;
121                    let dist = dist.length();
122                    return spectrum_from_rgb(&[dist, dist, dist]) * scale;
123                }
124                AOVTarget::N => {
125                    return v2c(&si.n) * scale;
126                }
127                AOVTarget::NS => {
128                    return v2c(&si.shading.n) * scale;
129                }
130                AOVTarget::UV => {
131                    let v = si.uv;
132                    return spectrum_from_rgb(&[v[0], v[1], 0.0]) * scale;
133                }
134                AOVTarget::RDXC => {
135                    let v = r.rx_origin;
136                    return v2c(&v) * scale;
137                }
138                AOVTarget::DRODX => {
139                    let v = r.rx_origin;
140                    return v2c(&v) * scale;
141                }
142                AOVTarget::DRDDX => {
143                    let v = r.rx_direction;
144                    return v2c(&v) * scale;
145                }
146                AOVTarget::DPDX => {
147                    let v = si.dpdx;
148                    return v2c(&v) * scale;
149                }
150                AOVTarget::DPDY => {
151                    let v = si.dpdy;
152                    return v2c(&v) * scale;
153                }
154                AOVTarget::DPDU => {
155                    let v = si.dpdu;
156                    return v2c(&v) * scale;
157                }
158                AOVTarget::DPDV => {
159                    let v = si.dpdv;
160                    return v2c(&v) * scale;
161                }
162                AOVTarget::DUVDX => {
163                    let v = Vector3::new(Float::abs(si.dudx), Float::abs(si.dvdx), 0.0);
164                    return v2c(&v) * scale;
165                }
166                AOVTarget::DUVDY => {
167                    let v = Vector3::new(Float::abs(si.dudy), Float::abs(si.dvdy), 0.0);
168                    return v2c(&v) * scale;
169                }
170                AOVTarget::DPDUS => {
171                    let v = si.shading.dpdu;
172                    return v2c(&v) * scale;
173                }
174                AOVTarget::DPDVS => {
175                    let v = si.shading.dpdv;
176                    return v2c(&v) * scale;
177                }
178                _ => {}
179            }
180        }
181        return Spectrum::zero();
182    }
183
184    fn get_sampler(&self) -> Arc<RwLock<dyn Sampler>> {
185        return Arc::clone(&self.base.sampler);
186    }
187
188    fn get_pixel_bounds(&self) -> Bounds2i {
189        return self.base.pixel_bounds;
190    }
191}
192
193unsafe impl Sync for AOVIntegrator {}
194
195pub fn create_aov_integrator(
196    params: &ParamSet,
197    sampler: &Arc<RwLock<dyn Sampler>>,
198    camera: &Arc<dyn Camera>,
199) -> Result<Arc<RwLock<dyn Integrator>>, PbrtError> {
200    let target = params.find_one_string("target", "uv");
201    let scale = params.find_one_float("scale", 1.0);
202
203    let pixel_bounds = camera.get_film().read().unwrap().get_sample_bounds();
204
205    let target = get_aov_target(&target)?;
206
207    return Ok(Arc::new(RwLock::new(AOVIntegrator::new(
208        camera,
209        sampler,
210        &pixel_bounds,
211        target,
212        scale,
213    ))));
214}