pbrt/shared/src/spectra/rgb.rs

162 lines
3.7 KiB
Rust

use super::{
DenselySampledSpectrum, RGBColorSpace, SampledSpectrum, SampledWavelengths, LAMBDA_MAX,
LAMBDA_MIN, N_SPECTRUM_SAMPLES,
};
use crate::core::color::{RGBSigmoidPolynomial, RGB, XYZ};
use crate::core::spectrum::SpectrumTrait;
use crate::utils::Ptr;
use crate::Float;
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct RGBAlbedoSpectrum {
pub rsp: RGBSigmoidPolynomial,
}
impl RGBAlbedoSpectrum {
pub fn new(cs: &RGBColorSpace, rgb: RGB) -> Self {
Self {
rsp: cs.to_rgb_coeffs(rgb),
}
}
}
impl SpectrumTrait for RGBAlbedoSpectrum {
fn evaluate(&self, lambda: Float) -> Float {
self.rsp.evaluate(lambda)
}
fn max_value(&self) -> Float {
self.rsp.max_value()
}
}
#[repr(C)]
#[derive(Debug, Default, Clone, Copy)]
pub struct UnboundedRGBSpectrum {
pub scale: Float,
pub rsp: RGBSigmoidPolynomial,
}
impl UnboundedRGBSpectrum {
pub fn new(cs: RGBColorSpace, rgb: RGB) -> Self {
let m = rgb.r.max(rgb.g).max(rgb.b);
let scale = 2.0 * m;
let scaled_rgb = if scale != 0.0 {
rgb / scale
} else {
RGB::new(0.0, 0.0, 0.0)
};
Self {
scale,
rsp: cs.to_rgb_coeffs(scaled_rgb),
}
}
}
impl SpectrumTrait for UnboundedRGBSpectrum {
fn evaluate(&self, lambda: Float) -> Float {
self.scale * self.rsp.evaluate(lambda)
}
fn max_value(&self) -> Float {
self.scale * self.rsp.max_value()
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct RGBIlluminantSpectrum {
pub scale: Float,
pub rsp: RGBSigmoidPolynomial,
pub illuminant: Ptr<DenselySampledSpectrum>,
}
impl RGBIlluminantSpectrum {
pub fn new(cs: &RGBColorSpace, rgb: RGB) -> Self {
let illuminant = cs.illuminant;
let m = rgb.max_component_value();
let scale = 2. * m;
let rsp = cs.to_rgb_coeffs(if scale != 0. {
rgb / scale
} else {
RGB::new(0., 0., 0.)
});
Self {
scale,
rsp,
illuminant,
}
}
}
impl SpectrumTrait for RGBIlluminantSpectrum {
fn evaluate(&self, lambda: Float) -> Float {
if self.illuminant.is_null() {
return 0.;
}
self.scale * self.rsp.evaluate(lambda) * self.illuminant.evaluate(lambda)
}
fn sample(&self, lambda: &SampledWavelengths) -> SampledSpectrum {
if self.illuminant.is_null() {
return SampledSpectrum::new(0.);
}
SampledSpectrum::from_fn(|i| self.scale * self.rsp.evaluate(lambda[i]))
}
fn max_value(&self) -> Float {
if self.illuminant.is_null() {
return 0.;
}
self.scale * self.rsp.max_value() * self.illuminant.max_value()
}
}
#[derive(Debug, Clone, Copy)]
pub struct RGBSpectrum {
pub c: [Float; 3],
}
#[derive(Debug, Clone, Copy)]
pub struct RGBUnboundedSpectrum {
pub scale: Float,
pub rsp: RGBSigmoidPolynomial,
}
impl Default for RGBUnboundedSpectrum {
fn default() -> Self {
Self {
scale: 0.0,
rsp: RGBSigmoidPolynomial::default(),
}
}
}
impl RGBUnboundedSpectrum {
pub fn new(cs: &RGBColorSpace, rgb: RGB) -> Self {
let m = rgb.max_component_value();
let scale = 2.0 * m;
let rgb_norm = if scale > 0.0 {
rgb / scale
} else {
RGB::new(0.0, 0.0, 0.0)
};
let rsp = cs.to_rgb_coeffs(rgb_norm);
Self { scale, rsp }
}
}
impl SpectrumTrait for RGBUnboundedSpectrum {
fn evaluate(&self, lambda: Float) -> Float {
self.scale * self.rsp.evaluate(lambda)
}
fn max_value(&self) -> Float {
self.scale * self.rsp.max_value()
}
}