1use super::integrator::*;
2use crate::core::base::*;
3use crate::core::camera::*;
4use crate::core::film::*;
5use crate::core::geometry::*;
6use crate::core::interaction::*;
7use crate::core::memory::*;
8use crate::core::misc::*;
9use crate::core::reflection::*;
10use crate::core::sampler::*;
11use crate::core::scene::*;
12use crate::core::spectrum::*;
13use crate::core::stats::*;
14
15use std::ops::DerefMut;
16use std::path::Path;
17use std::sync::Arc;
18use std::sync::Mutex;
19use std::sync::RwLock;
20
21use log::*;
22use rayon::prelude::*;
23
24thread_local!(static N_CAMERA_RAYS: StatCounter = StatCounter::new("Integrator/Camera rays traced"));
25
26pub trait SamplerIntegrator: Integrator + Sync {
27 fn preprocess(&mut self, _scene: &Scene, _sampler: &mut dyn Sampler) {}
28 fn li(
29 &self,
30 ray: &RayDifferential,
31 scene: &Scene,
32 sampler: &mut dyn Sampler,
33 arena: &mut MemoryArena,
34 depth: i32,
35 ) -> Spectrum;
36
37 fn specular_reflect(
38 &self,
39 ray: &RayDifferential,
40 isect: &SurfaceInteraction,
41 scene: &Scene,
42 sampler: &mut dyn Sampler,
43 arena: &mut MemoryArena,
44 depth: i32,
45 ) -> Spectrum {
46 if let Some(bsdf) = isect.bsdf.as_ref() {
47 let bsdf = bsdf.as_ref();
48 let wo = isect.wo;
49 let u = sampler.get_2d();
50 let t = BSDF_REFLECTION | BSDF_SPECULAR;
51 if let Some((f, wi, pdf, _tt)) = bsdf.sample_f(&wo, &u, t) {
52 assert!(isect.n.length() > 0.0);
53 assert!(isect.shading.n.length() > 0.0);
54
55 let ns = isect.shading.n;
56 let wi_ns = Vector3f::abs_dot(&wi, &ns);
57 if pdf > 0.0 && !f.is_black() && wi_ns != 0.0 {
58 let mut rd = RayDifferential::from(isect.spawn_ray(&wi));
59 if ray.has_differentials {
60 rd.has_differentials = true;
61 rd.rx_origin = isect.p + isect.dpdx;
62 rd.ry_origin = isect.p + isect.dpdy;
63
64 let dndx =
65 isect.shading.dndu * isect.dudx + isect.shading.dndv * isect.dvdx;
66 let dndy =
67 isect.shading.dndu * isect.dudy + isect.shading.dndv * isect.dvdy;
68 let dwodx = -ray.rx_direction - wo;
69 let dwody = -ray.ry_direction - wo;
70
71 let d_dndx = Vector3f::dot(&dwodx, &ns) + Vector3f::dot(&wo, &dndx);
72 let d_dndy = Vector3f::dot(&dwody, &ns) + Vector3f::dot(&wo, &dndy);
73 let wo_ns = Vector3f::dot(&wo, &ns);
74 rd.rx_direction = wi - dwodx + 2.0 * (wo_ns * dndx + d_dndx * ns);
75 rd.ry_direction = wi - dwody + 2.0 * (wo_ns * dndy + d_dndy * ns);
76 }
77 return f * self.li(&rd, scene, sampler, arena, depth + 1) * (wi_ns / pdf);
78 }
79 }
80 }
81 return Spectrum::zero();
82 }
83
84 fn specular_transmit(
85 &self,
86 ray: &RayDifferential,
87 isect: &SurfaceInteraction,
88 scene: &Scene,
89 sampler: &mut dyn Sampler,
90 arena: &mut MemoryArena,
91 depth: i32,
92 ) -> Spectrum {
93 if let Some(bsdf) = isect.bsdf.as_ref() {
94 let bsdf = bsdf.as_ref();
95 let wo = isect.wo;
96 let u = sampler.get_2d();
97 let t = BSDF_TRANSMISSION | BSDF_SPECULAR;
98 if let Some((f, wi, pdf, _tt)) = bsdf.sample_f(&wo, &u, t) {
99 let mut ns = isect.shading.n;
100 let mut wi_ns = Vector3f::abs_dot(&wi, &ns);
101 let mut wo_ns = Vector3f::dot(&wo, &ns);
102 if pdf > 0.0 && !f.is_black() && wi_ns != 0.0 {
103 let mut rd = RayDifferential::from(isect.spawn_ray(&wi));
104 if ray.has_differentials {
105 rd.has_differentials = true;
106 rd.rx_origin = isect.p + isect.dpdx;
107 rd.ry_origin = isect.p + isect.dpdy;
108
109 let mut dndx =
110 isect.shading.dndu * isect.dudx + isect.shading.dndv * isect.dvdx;
111 let mut dndy =
112 isect.shading.dndu * isect.dudy + isect.shading.dndv * isect.dvdy;
113 let mut eta = 1.0 / bsdf.eta;
114 if Vector3f::dot(&wo, &ns) < 0.0 {
115 eta = 1.0 / eta;
116 ns = -ns;
117 dndx = -dndx;
118 dndy = -dndy;
119
120 wi_ns = Vector3f::abs_dot(&wi, &ns);
121 wo_ns = Vector3f::dot(&wo, &ns);
122 }
123
124 let dwodx = -ray.rx_direction - wo;
125 let dwody = -ray.ry_direction - wo;
126
127 let d_dndx = Vector3f::dot(&dwodx, &ns) + Vector3f::dot(&wo, &dndx);
128 let d_dndy = Vector3f::dot(&dwody, &ns) + Vector3f::dot(&wo, &dndy);
129
130 let mu = eta * wo_ns - wi_ns;
131 let dmudx = (eta - (eta * eta * wo_ns) / wi_ns) * d_dndx;
132 let dmudy = (eta - (eta * eta * wo_ns) / wi_ns) * d_dndy;
133
134 rd.rx_direction = wi - eta * dwodx + (mu * dndx + dmudx * ns);
135 rd.ry_direction = wi - eta * dwody + (mu * dndy + dmudy * ns);
136 }
137 return f * self.li(&rd, scene, sampler, arena, depth + 1) * (wi_ns / pdf);
138 }
139 }
140 }
141 return Spectrum::zero();
142 }
143
144 fn get_sampler(&self) -> Arc<RwLock<dyn Sampler>>;
147
148 fn get_pixel_bounds(&self) -> Bounds2i;
149}
150
151fn validate_radiance_result(l: Spectrum, pixel: &Point2i) -> Spectrum {
152 if !l.is_valid() {
153 error!(
154 "Not-a-number radiance value returned for pixel ({}, {}). Setting to black.",
155 pixel.x, pixel.y
156 );
157 return Spectrum::zero();
158 }
159 if l.y() < -1e-5 {
160 error!(
161 "Negative luminance value, {}, returned for pixel ({}, {}). Setting to black.",
162 l.y(),
163 pixel.x,
164 pixel.y
165 );
166 return Spectrum::zero();
167 }
168 if l.y().is_infinite() {
169 error!(
170 "Infinite luminance value returned for pixel ({}, {}). Setting to black.",
171 pixel.x, pixel.y
172 );
173 return Spectrum::zero();
174 }
175 return l;
176}
177
178struct SampleIntegratorCore {}
179
180impl SampleIntegratorCore {
181 pub fn get_film_tile(film: &Arc<Mutex<ProxyFilm>>, tile_bounds: &Bounds2i) -> FilmTile {
182 let film = film.lock().unwrap();
183 return film.get_film_tile(tile_bounds);
184 }
185
186 pub fn merge_film_tile(film: &Arc<Mutex<ProxyFilm>>, tile: &FilmTile) {
187 let mut film = film.lock().unwrap();
188 film.merge_film_tile(tile);
189 film.update_display(&tile.get_pixel_bounds());
190 }
191
192 pub fn get_filename(film: &Arc<Mutex<ProxyFilm>>) -> String {
193 let film = film.lock().unwrap();
194 let path = film.get_filename();
195 let path = Path::new(&path);
196 let filename = path.file_name().unwrap();
197 let filename = filename.to_str().unwrap();
198 return String::from(filename);
199 }
200
201 pub fn render_tile(
202 integrator: &dyn SamplerIntegrator,
203 scene: &Scene,
204 camera: &dyn Camera,
205 film: &Arc<Mutex<ProxyFilm>>,
206 tile_bounds: &Bounds2i,
207 sampler: &Arc<Mutex<ProxySampler>>,
208 reporter: &Arc<Mutex<ProgressReporter>>,
209 ) {
210 let mut arena = MemoryArena::new();
211 let x0 = tile_bounds.min.x;
212 let x1 = tile_bounds.max.x;
213 let y0 = tile_bounds.min.y;
214 let y1 = tile_bounds.max.y;
215
216 let mut sampler = sampler.lock().unwrap();
217
218 let ray_scale = (1.0 / sampler.get_samples_per_pixel() as Float).sqrt();
219
220 let mut film_tile = Self::get_film_tile(film, tile_bounds);
221 for yy in y0..y1 {
222 for xx in x0..x1 {
223 let pixel = Point2i::new(xx, yy);
224 sampler.start_pixel(&pixel);
225 loop {
226 let camera_sample = sampler.get_camera_sample(&pixel);
228
229 if let Some((ray_weight, mut ray)) =
231 camera.generate_ray_differential(&camera_sample)
232 {
233 ray.scale_differentials(ray_scale);
234
235 N_CAMERA_RAYS.with(|c| c.inc());
236
237 let l = integrator.li(&ray, scene, sampler.deref_mut(), &mut arena, 0);
239 let l = validate_radiance_result(l, &pixel);
240 film_tile.add_sample(&camera_sample.p_film, &l, ray_weight);
241 } else {
242 film_tile.add_sample(&camera_sample.p_film, &Spectrum::zero(), 0.0);
243 }
244 arena.reset();
245
246 if !sampler.start_next_sample() {
247 break;
248 }
249 }
250 }
251 }
252 Self::merge_film_tile(film, &film_tile);
253 {
254 let mut reporter = reporter.lock().unwrap();
255 reporter.update(1);
256 }
257 }
258
259 pub fn render(
260 integrator: &dyn SamplerIntegrator,
261 scene: &Scene,
262 camera: &dyn Camera,
263 film: &Arc<RwLock<Film>>,
264 sampler: &Arc<RwLock<dyn Sampler>>,
265 ) {
266 let mut tile_indices = Vec::new();
267 {
268 let mut film = film.as_ref().write().unwrap();
269 let sample_bounds = film.get_sample_bounds();
270 let sample_extent = sample_bounds.diagonal();
271 const TILE_SIZE: i32 = 16;
272 let n_tiles = Point2i::from((
273 (sample_extent.x + TILE_SIZE - 1) / TILE_SIZE,
274 (sample_extent.y + TILE_SIZE - 1) / TILE_SIZE,
275 ));
276 tile_indices.reserve((n_tiles.x * n_tiles.y) as usize);
277 for y in 0..n_tiles.y {
278 for x in 0..n_tiles.x {
279 let x0 = sample_bounds.min.x + x * TILE_SIZE;
280 let x1 = i32::min(x0 + TILE_SIZE, sample_bounds.max.x);
281 let y0 = sample_bounds.min.y + y * TILE_SIZE;
282 let y1 = i32::min(y0 + TILE_SIZE, sample_bounds.max.y);
283 let tile_bounds = Bounds2i::from(((x0, y0), (x1, y1)));
284
285 let seed = (y * n_tiles.x + x) as u32;
286 let s = sampler.read().unwrap().clone_with_seed(seed);
287 let proxy = Arc::new(Mutex::new(ProxySampler::new(&s)));
288 tile_indices.push((tile_bounds, proxy));
289 }
290 }
291
292 film.render_start();
293 }
294
295 {
296 let proxy_film = Arc::new(Mutex::new(ProxyFilm::new(film)));
297 let filename = Self::get_filename(&proxy_film);
298
299 let total = tile_indices.len();
300 let reporter = Arc::new(Mutex::new(ProgressReporter::new(total, &filename)));
301
302 {
303 tile_indices.par_iter().for_each(|(tile_bounds, sampler)| {
304 Self::render_tile(
305 integrator,
306 scene,
307 camera,
308 &proxy_film,
309 tile_bounds,
310 sampler,
311 &reporter,
312 );
313 });
314 }
315
316 {
317 let mut reporter = reporter.lock().unwrap();
318 reporter.done();
319 }
320 }
321
322 {
323 let mut film = film.as_ref().write().unwrap();
324 film.render_end();
325 film.write_image();
326 }
327 }
328}
329
330pub struct BaseSamplerIntegrator {
331 pub camera: Arc<dyn Camera>,
332 pub sampler: Arc<RwLock<dyn Sampler>>,
333 pub pixel_bounds: Bounds2i,
334}
335
336impl BaseSamplerIntegrator {
337 pub fn new(
338 camera: &Arc<dyn Camera>,
339 sampler: &Arc<RwLock<dyn Sampler>>,
340 pixel_bounds: &Bounds2i,
341 ) -> Self {
342 BaseSamplerIntegrator {
343 camera: Arc::clone(camera),
344 sampler: Arc::clone(sampler),
345 pixel_bounds: pixel_bounds.clone(),
346 }
347 }
348
349 pub fn render(integrator: &mut dyn SamplerIntegrator, scene: &Scene) {
350 let acamera = integrator.get_camera();
351 let camera = acamera.as_ref();
352 let sampler = integrator.get_sampler();
353 {
354 let mut sampler = sampler.write().unwrap();
355 integrator.preprocess(scene, sampler.deref_mut());
356 }
357
358 let film = camera.get_film();
359 SampleIntegratorCore::render(integrator, scene, camera, &film, &sampler);
360 }
361}