gloss_utils/
tonemap.rs

1use std::ops::MulAssign;
2
3// use na::SimdPartialOrd;
4use nalgebra as na;
5// use std::ops::Add;
6
7pub struct AcesFitted {
8    rgb_to_rrt: na::Matrix3<f32>,
9    odt_to_rgb: na::Matrix3<f32>,
10}
11impl AcesFitted {
12    #[allow(clippy::new_without_default)]
13    pub fn new() -> Self {
14        // sRGB => XYZ => D65_2_D60 => AP1 => RRT_SAT
15        let rgb_to_rrt = na::Matrix3::<f32>::from_columns(&[
16            na::Vector3::new(0.59719, 0.35458, 0.04823),
17            na::Vector3::new(0.07600, 0.90834, 0.01566),
18            na::Vector3::new(0.02840, 0.13383, 0.83777),
19        ]);
20        let odt_to_rgb = na::Matrix3::<f32>::from_columns(&[
21            na::Vector3::new(1.60475, -0.53108, -0.07367),
22            na::Vector3::new(-0.10208, 1.10813, -0.00605),
23            na::Vector3::new(-0.00327, -0.07276, 1.07602),
24        ]);
25        Self { rgb_to_rrt, odt_to_rgb }
26    }
27    pub fn tonemap(&self, color: &na::Vector3<f32>) -> na::Vector3<f32> {
28        let mut fitted_color = color.transpose();
29        fitted_color.mul_assign(&self.rgb_to_rrt);
30
31        // Apply RRT and ODT
32        fitted_color = Self::rrt_and_odt_fit(&fitted_color);
33
34        fitted_color.mul_assign(&self.odt_to_rgb);
35
36        // Clamp to [0, 1]
37        fitted_color.x = fitted_color.x.clamp(0.0, 1.0);
38        fitted_color.y = fitted_color.y.clamp(0.0, 1.0);
39        fitted_color.z = fitted_color.z.clamp(0.0, 1.0);
40
41        fitted_color.transpose()
42    }
43    fn rrt_and_odt_fit(
44        v: &na::Matrix<f32, na::Const<1>, na::Const<3>, na::ArrayStorage<f32, 1, 3>>,
45    ) -> na::Matrix<f32, na::Const<1>, na::Const<3>, na::ArrayStorage<f32, 1, 3>> {
46        let v1 = v.add_scalar(0.024_578_6);
47        let v2 = v.component_mul(&v1);
48        let a = v2.add_scalar(-0.000_090_537);
49
50        let v1 = 0.983_729 * v;
51        let v2 = v1.add_scalar(0.432_951);
52        let v3 = v.component_mul(&v2);
53        let b = v3.add_scalar(0.238_081);
54        a.component_div(&b)
55    }
56}