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}