pbrt/src/spectra/dense.rs

117 lines
3.5 KiB
Rust

use shared::Float;
use shared::core::spectrum::{Spectrum, SpectrumTrait};
use shared::spectra::cie::{CIE_S_LAMBDA, CIE_S0, CIE_S1, CIE_S2, N_CIES};
use shared::spectra::{
BlackbodySpectrum, DenselySampledSpectrum, LAMBDA_MAX, LAMBDA_MIN, PiecewiseLinearSpectrum,
};
use shared::utils::math::square;
use std::hash::{Hash, Hasher};
#[derive(Clone, Debug, PartialEq)]
pub struct DenselySampledSpectrumBuffer {
pub lambda_min: i32,
pub lambda_max: i32,
pub values: Vec<Float>,
}
impl Eq for DenselySampledSpectrumBuffer {}
impl Hash for DenselySampledSpectrumBuffer {
fn hash<H: Hasher>(&self, state: &mut H) {
self.lambda_min.hash(state);
self.lambda_max.hash(state);
for &val in &self.values {
val.to_bits().hash(state);
}
}
}
impl DenselySampledSpectrumBuffer {
pub fn new(lambda_min: i32, lambda_max: i32, values: Vec<Float>) -> Self {
Self {
lambda_min,
lambda_max,
values,
}
}
pub fn new_zero(lambda_min: i32, lambda_max: i32) -> Self {
let n_values = (lambda_max - lambda_min + 1).max(0) as usize;
let values = vec![0.0; n_values];
Self::new(lambda_min, lambda_max, values)
}
pub fn from_spectrum(spec: &Spectrum) -> Self {
let lambda_min = LAMBDA_MIN;
let lambda_max = LAMBDA_MAX;
let mut values = Vec::with_capacity((lambda_max - lambda_min + 1) as usize);
for lambda in lambda_min..=lambda_max {
values.push(spec.evaluate(lambda as Float));
}
Self::new(lambda_min, lambda_max, values)
}
pub fn from_function<F>(f: F, lambda_min: i32, lambda_max: i32) -> Self
where
F: Fn(Float) -> Float,
{
let mut values = Vec::with_capacity((lambda_max - lambda_min + 1) as usize);
for lambda in lambda_min..=lambda_max {
values.push(f(lambda as Float));
}
Self::new(lambda_min, lambda_max, values)
}
pub fn generate_cie_d(temperature: Float) -> Self {
let cct = temperature * 1.4388 / 1.4380;
if cct < 4000.0 {
return Self::from_function(
|lambda| BlackbodySpectrum::new(cct).evaluate(lambda),
LAMBDA_MIN,
LAMBDA_MAX,
);
}
let x = if cct < 7000. {
-4.607 * 1e9 / cct.powi(3) + 2.9678 * 1e6 / square(cct) + 0.09911 * 1e3 / cct + 0.244063
} else {
-2.0064 * 1e9 / cct.powi(3) + 1.9018 * 1e6 / square(cct) + 0.24748 * 1e3 / cct + 0.23704
};
let y = -3. * x + 2.87 * x - 0.275;
let m = 0.0241 + 0.2562 * x - 0.7341 * y;
let m1 = (-1.3515 - 1.7703 * x + 5.9114 * y) / m;
let m2 = (0.0300 - 31.4424 * x + 30.0717 * y) / m;
let coarse_values: Vec<Float> = (0..N_CIES)
.map(|i| (CIE_S0[i] + CIE_S1[i] * m1 + CIE_S2[i] * m2) * 0.01)
.collect();
let temp_pls = PiecewiseLinearSpectrum {
lambdas: CIE_S_LAMBDA.as_ptr().into(),
values: coarse_values.as_ptr().into(),
count: N_CIES as u32,
};
Self::from_function(|lambda| temp_pls.evaluate(lambda), LAMBDA_MIN, LAMBDA_MAX)
}
pub fn device(&self) -> DenselySampledSpectrum {
DenselySampledSpectrum {
lambda_min: self.lambda_min,
lambda_max: self.lambda_max,
values: self.values.as_ptr().into(),
}
}
pub fn scale(&mut self, s: Float) {
for v in &mut self.values {
*v *= s;
}
}
}