pbrt_r3/core/integrator/
sampler.rs

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_camera(&self) -> Arc<dyn Camera>;
145
146    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                    // Initialize _CameraSample_ for current sample
227                    let camera_sample = sampler.get_camera_sample(&pixel);
228
229                    // Generate camera ray for current sample
230                    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                        // Evaluate radiance along camera ray
238                        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}