pbrt/shared/src/spectra/mod.rs

96 lines
2.6 KiB
Rust

pub mod cie;
pub mod color;
pub mod colorspace;
pub mod data;
pub mod rgb;
pub mod sampled;
pub mod simple;
use crate::core::pbrt::Float;
use crate::utils::file::read_float_file;
use enum_dispatch::enum_dispatch;
pub use color::{RGB, XYZ};
pub use colorspace::RGBColorSpace;
pub use data::*;
pub use rgb::*;
pub use sampled::{CIE_Y_INTEGRAL, LAMBDA_MAX, LAMBDA_MIN};
pub use sampled::{N_SPECTRUM_SAMPLES, SampledSpectrum, SampledWavelengths};
pub use simple::*;
//
#[enum_dispatch]
pub trait SpectrumProvider: Copy {
fn evaluate(&self, lambda: Float) -> Float;
fn max_value(&self) -> Float;
}
#[cfg(not(target_arch = "spirv"))]
impl SpectrumProvider for std::sync::Arc<DenselySampledSpectrum> {
fn evaluate(&self, lambda: Float) -> Float {
(**self).evaluate(lambda)
}
fn max_value(&self) -> Float {
(**self).max_value()
}
}
#[cfg(target_arch = "spirv")] // or target_os = "cuda"
impl SpectrumProvider for u32 {
fn evaluate(&self, lambda: Float) -> Float {
// Here you would call a global function that accesses
// a static buffer of spectra data
crate::gpu::lookup_global_spectrum(*self, lambda)
}
fn max_value(&self) -> Float {
crate::gpu::lookup_global_spectrum_max(*self)
}
}
#[enum_dispatch(SpectrumTrait)]
#[derive(Debug, Clone)]
pub enum Spectrum {
Constant(ConstantSpectrum),
DenselySampled(DenselySampledSpectrum),
PiecewiseLinear(PiecewiseLinearSpectrum),
Blackbody(BlackbodySpectrum),
RGBAlbedo(RGBAlbedoSpectrum),
RGBIlluminant(RGBIlluminantSpectrum),
RGBUnbounded(RGBUnboundedSpectrum),
}
impl Spectrum {
pub fn std_illuminant_d65() -> Self {
todo!()
}
pub fn to_xyz(&self) -> XYZ {
let x = self.inner_product(data::cie_x());
let y = self.inner_product(data::cie_y());
let z = self.inner_product(data::cie_z());
XYZ::new(x, y, z) / CIE_Y_INTEGRAL
}
fn to_rgb(&self, cs: &RGBColorSpace) -> RGB {
let xyz = self.to_xyz();
cs.to_rgb(xyz)
}
pub fn sample(&self, wavelengths: &SampledWavelengths) -> SampledSpectrum {
SampledSpectrum::from_fn(|i| self.evaluate(wavelengths[i]))
}
pub fn inner_product(&self, other: &Spectrum) -> Float {
let mut integral = 0.0;
// Iterate integer wavelengths.
for lambda in LAMBDA_MIN..=LAMBDA_MAX {
let l = lambda as Float;
integral += self.evaluate(l) * other.evaluate(l);
}
integral
}
pub fn is_constant(&self) -> bool {
matches!(self, Spectrum::Constant(_))
}
}