libredr/light_source/
functional.rs

1use nalgebra as na;
2use ndarray::{Axis, Array4};
3use anyhow::{Result, ensure};
4
5/// Construct envmap with a given function
6/// # Arguments
7/// * `resolution`: a single integer
8/// * `f`: function converting the normalized envmap direction (f32 vector of 3) to intensity (f32 vector of 3)
9/// # Return
10/// * 3 * 6 * `resolution` * `resolution`
11pub fn functional_envmap<F>(resolution: usize, mut f: F) -> Result<Array4<f32>>
12    where F: FnMut(na::Vector3<f32>) -> na::Vector3<f32> {
13  let mut envmap = Array4::zeros((3, 6, resolution, resolution));
14  for (face_id, mut envmap) in envmap.axis_iter_mut(Axis(1)).enumerate() {
15    for (i_row, mut envmap) in envmap.axis_iter_mut(Axis(1)).enumerate() {
16      for (i_col, mut envmap) in envmap.axis_iter_mut(Axis(1)).enumerate() {
17        let i_row = ((resolution - 1 - i_row) as f32 + 0.5) / resolution as f32 * 2. - 1.;
18        let i_col = (i_col as f32 + 0.5) / resolution as f32 * 2. - 1.;
19        let mut axis_xyz = na::Vector3::zeros();
20        axis_xyz[face_id / 2] = if face_id % 2 == 0 { 1. } else { -1. };
21        match face_id / 2 {
22          0 => (axis_xyz[2], axis_xyz[1]) = (i_row, i_col),
23          1 => (axis_xyz[2], axis_xyz[0]) = (i_row, i_col),
24          2 => (axis_xyz[1], axis_xyz[0]) = (i_row, i_col),
25          _ => unreachable!(),
26        }
27        let intensity = f(axis_xyz.normalize());
28        for (intensity, envmap) in intensity.into_iter().zip(envmap.iter_mut()) {
29          ensure!(*intensity >= 0.,
30                  "light_source::functional_envmap: negative `intensity` at {face_id} {i_row} {i_col}");
31          ensure!(intensity.is_finite(),
32                  "light_source::functional_envmap: infinite nor NaN `intensity` at {face_id} {i_row} {i_col}");
33          *envmap = *intensity;
34        }
35      }
36    }
37  }
38  Ok(envmap)
39}