Implementing Color as a simple enum rather than as a trait.
There's really no reason for it to be a Trait, and this will simplify a lot of things down the road.
This commit is contained in:
parent
b598ce499c
commit
5add4cfdb1
133
src/color.rs
133
src/color.rs
|
@ -16,10 +16,6 @@ pub fn map_0_1_to_wavelength(n: f32) -> f32 {
|
||||||
n * WL_RANGE + WL_MIN
|
n * WL_RANGE + WL_MIN
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Color {
|
|
||||||
fn to_spectral_sample(&self, hero_wavelength: f32) -> SpectralSample;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn nth_wavelength(hero_wavelength: f32, n: usize) -> f32 {
|
fn nth_wavelength(hero_wavelength: f32, n: usize) -> f32 {
|
||||||
let wl = hero_wavelength + (WL_RANGE_Q * n as f32);
|
let wl = hero_wavelength + (WL_RANGE_Q * n as f32);
|
||||||
|
@ -43,6 +39,126 @@ fn wavelengths(hero_wavelength: f32) -> Float4 {
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub enum Color {
|
||||||
|
XYZ(f32, f32, f32),
|
||||||
|
Blackbody {
|
||||||
|
temperature: f32, // In kelvin
|
||||||
|
factor: f32, // Brightness multiplier
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Color {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn new_xyz(xyz: (f32, f32, f32)) -> Self {
|
||||||
|
Color::XYZ(xyz.0, xyz.1, xyz.2)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn new_blackbody(temp: f32, fac: f32) -> Self {
|
||||||
|
Color::Blackbody {
|
||||||
|
temperature: temp,
|
||||||
|
factor: fac,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_spectral_sample(self, hero_wavelength: f32) -> SpectralSample {
|
||||||
|
let wls = wavelengths(hero_wavelength);
|
||||||
|
match self {
|
||||||
|
Color::XYZ(x, y, z) => SpectralSample {
|
||||||
|
e: xyz_to_spectrum_4((x, y, z), wls),
|
||||||
|
hero_wavelength: hero_wavelength,
|
||||||
|
},
|
||||||
|
Color::Blackbody {
|
||||||
|
temperature,
|
||||||
|
factor,
|
||||||
|
} => {
|
||||||
|
SpectralSample::from_parts(
|
||||||
|
// TODO: make this SIMD
|
||||||
|
Float4::new(
|
||||||
|
plancks_law(temperature, wls.get_0()) * factor,
|
||||||
|
plancks_law(temperature, wls.get_1()) * factor,
|
||||||
|
plancks_law(temperature, wls.get_2()) * factor,
|
||||||
|
plancks_law(temperature, wls.get_3()) * factor,
|
||||||
|
),
|
||||||
|
hero_wavelength,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculates an approximate total spectral energy of the color.
|
||||||
|
///
|
||||||
|
/// Note: this really is very _approximate_.
|
||||||
|
pub fn approximate_energy(self) -> f32 {
|
||||||
|
// TODO: better approximation for Blackbody.
|
||||||
|
match self {
|
||||||
|
Color::XYZ(_, y, _) => y,
|
||||||
|
Color::Blackbody { factor, .. } => factor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Lerp for Color {
|
||||||
|
/// Note that this isn't a proper lerp in spectral space. However,
|
||||||
|
/// for our purposes that should be fine: all we care about is that
|
||||||
|
/// the interpolation is smooth and "reasonable".
|
||||||
|
///
|
||||||
|
/// If at some point it turns out this causes artifacts, then we
|
||||||
|
/// also have bigger problems: texture filtering in the shading
|
||||||
|
/// pipeline will have the same issues, which will be even harder
|
||||||
|
/// to address. However, I strongly suspect this will not be an issue.
|
||||||
|
/// (Famous last words!)
|
||||||
|
fn lerp(self, other: Self, alpha: f32) -> Self {
|
||||||
|
let inv_alpha = 1.0 - alpha;
|
||||||
|
match (self, other) {
|
||||||
|
(Color::XYZ(x1, y1, z1), Color::XYZ(x2, y2, z2)) => Color::XYZ(
|
||||||
|
(x1 * inv_alpha) + (x2 * alpha),
|
||||||
|
(y1 * inv_alpha) + (y2 * alpha),
|
||||||
|
(z1 * inv_alpha) + (z2 * alpha),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Color::Blackbody {
|
||||||
|
temperature: tmp1,
|
||||||
|
factor: fac1,
|
||||||
|
},
|
||||||
|
Color::Blackbody {
|
||||||
|
temperature: tmp2,
|
||||||
|
factor: fac2,
|
||||||
|
},
|
||||||
|
) => Color::Blackbody {
|
||||||
|
temperature: (tmp1 * inv_alpha) + (tmp2 * alpha),
|
||||||
|
factor: (fac1 * inv_alpha) + (fac2 * alpha),
|
||||||
|
},
|
||||||
|
_ => panic!("Cannot lerp colors with different representations."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn plancks_law(temperature: f32, wavelength: f32) -> f32 {
|
||||||
|
const C: f32 = 299_792_458.0; // Speed of light
|
||||||
|
const H: f32 = 6.62607015e-34; // Planck constant
|
||||||
|
const KB: f32 = 1.38064852e-23; // Boltzmann constant
|
||||||
|
|
||||||
|
// // As written at https://en.wikipedia.org/wiki/Planck's_law, here for
|
||||||
|
// // reference and clarity:
|
||||||
|
// let a = (2.0 * H * C * C) / (wavelength * wavelength * wavelength * wavelength * wavelength);
|
||||||
|
// let b = 1.0 / (((H * C) / (wavelength * KB * temperature)).exp() - 1.0);
|
||||||
|
// a * b
|
||||||
|
|
||||||
|
// Optimized version of the commented code above:
|
||||||
|
const TMP1: f32 = (2.0f64 * H as f64 * C as f64 * C as f64) as f32;
|
||||||
|
const TMP2: f32 = (H as f64 * C as f64 / KB as f64) as f32;
|
||||||
|
let wl5 = {
|
||||||
|
let wl2 = wavelength * wavelength;
|
||||||
|
wl2 * wl2 * wavelength
|
||||||
|
};
|
||||||
|
let tmp3 = wl5 * (fast_exp(TMP2 / (wavelength * temperature)) - 1.0);
|
||||||
|
TMP1 / tmp3
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct SpectralSample {
|
pub struct SpectralSample {
|
||||||
pub e: Float4,
|
pub e: Float4,
|
||||||
|
@ -197,15 +313,6 @@ impl XYZ {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Color for XYZ {
|
|
||||||
fn to_spectral_sample(&self, hero_wavelength: f32) -> SpectralSample {
|
|
||||||
SpectralSample {
|
|
||||||
e: xyz_to_spectrum_4((self.x, self.y, self.z), wavelengths(hero_wavelength)),
|
|
||||||
hero_wavelength: hero_wavelength,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Lerp for XYZ {
|
impl Lerp for XYZ {
|
||||||
fn lerp(self, other: XYZ, alpha: f32) -> XYZ {
|
fn lerp(self, other: XYZ, alpha: f32) -> XYZ {
|
||||||
(self * (1.0 - alpha)) + (other * alpha)
|
(self * (1.0 - alpha)) + (other * alpha)
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::f64::consts::PI as PI_64;
|
||||||
use mem_arena::MemArena;
|
use mem_arena::MemArena;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
color::{Color, SpectralSample, XYZ},
|
color::{Color, SpectralSample},
|
||||||
lerp::lerp_slice,
|
lerp::lerp_slice,
|
||||||
math::{coordinate_system_from_vector, Vector},
|
math::{coordinate_system_from_vector, Vector},
|
||||||
sampling::{uniform_sample_cone, uniform_sample_cone_pdf},
|
sampling::{uniform_sample_cone, uniform_sample_cone_pdf},
|
||||||
|
@ -17,7 +17,7 @@ use super::WorldLightSource;
|
||||||
pub struct DistantDiskLight<'a> {
|
pub struct DistantDiskLight<'a> {
|
||||||
radii: &'a [f32],
|
radii: &'a [f32],
|
||||||
directions: &'a [Vector],
|
directions: &'a [Vector],
|
||||||
colors: &'a [XYZ],
|
colors: &'a [Color],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DistantDiskLight<'a> {
|
impl<'a> DistantDiskLight<'a> {
|
||||||
|
@ -25,7 +25,7 @@ impl<'a> DistantDiskLight<'a> {
|
||||||
arena: &'a MemArena,
|
arena: &'a MemArena,
|
||||||
radii: &[f32],
|
radii: &[f32],
|
||||||
directions: &[Vector],
|
directions: &[Vector],
|
||||||
colors: &[XYZ],
|
colors: &[Color],
|
||||||
) -> DistantDiskLight<'a> {
|
) -> DistantDiskLight<'a> {
|
||||||
DistantDiskLight {
|
DistantDiskLight {
|
||||||
radii: arena.copy_slice(&radii),
|
radii: arena.copy_slice(&radii),
|
||||||
|
@ -78,7 +78,7 @@ impl<'a> WorldLightSource for DistantDiskLight<'a> {
|
||||||
let sample = uniform_sample_cone(u, v, cos_theta_max).normalized();
|
let sample = uniform_sample_cone(u, v, cos_theta_max).normalized();
|
||||||
|
|
||||||
// Calculate the final values and return everything.
|
// Calculate the final values and return everything.
|
||||||
let spectral_sample = (col * solid_angle_inv as f32).to_spectral_sample(wavelength);
|
let spectral_sample = col.to_spectral_sample(wavelength) * solid_angle_inv as f32;
|
||||||
let shadow_vec = (x * sample.x()) + (y * sample.y()) + (z * sample.z());
|
let shadow_vec = (x * sample.x()) + (y * sample.y()) + (z * sample.z());
|
||||||
let pdf = uniform_sample_cone_pdf(cos_theta_max);
|
let pdf = uniform_sample_cone_pdf(cos_theta_max);
|
||||||
(spectral_sample, shadow_vec, pdf as f32)
|
(spectral_sample, shadow_vec, pdf as f32)
|
||||||
|
@ -89,11 +89,9 @@ impl<'a> WorldLightSource for DistantDiskLight<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn approximate_energy(&self) -> f32 {
|
fn approximate_energy(&self) -> f32 {
|
||||||
let color: XYZ = self
|
self.colors
|
||||||
.colors
|
|
||||||
.iter()
|
.iter()
|
||||||
.fold(XYZ::new(0.0, 0.0, 0.0), |a, &b| a + b)
|
.fold(0.0, |a, &b| a + b.approximate_energy())
|
||||||
/ self.colors.len() as f32;
|
/ self.colors.len() as f32
|
||||||
color.y
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use mem_arena::MemArena;
|
||||||
use crate::{
|
use crate::{
|
||||||
bbox::BBox,
|
bbox::BBox,
|
||||||
boundable::Boundable,
|
boundable::Boundable,
|
||||||
color::{Color, SpectralSample, XYZ},
|
color::{Color, SpectralSample},
|
||||||
lerp::lerp_slice,
|
lerp::lerp_slice,
|
||||||
math::{cross, dot, Matrix4x4, Normal, Point, Vector},
|
math::{cross, dot, Matrix4x4, Normal, Point, Vector},
|
||||||
ray::{AccelRay, Ray},
|
ray::{AccelRay, Ray},
|
||||||
|
@ -23,7 +23,7 @@ const SIMPLE_SAMPLING_THRESHOLD: f32 = 0.01;
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct RectangleLight<'a> {
|
pub struct RectangleLight<'a> {
|
||||||
dimensions: &'a [(f32, f32)],
|
dimensions: &'a [(f32, f32)],
|
||||||
colors: &'a [XYZ],
|
colors: &'a [Color],
|
||||||
bounds_: &'a [BBox],
|
bounds_: &'a [BBox],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ impl<'a> RectangleLight<'a> {
|
||||||
pub fn new<'b>(
|
pub fn new<'b>(
|
||||||
arena: &'b MemArena,
|
arena: &'b MemArena,
|
||||||
dimensions: &[(f32, f32)],
|
dimensions: &[(f32, f32)],
|
||||||
colors: &[XYZ],
|
colors: &[Color],
|
||||||
) -> RectangleLight<'b> {
|
) -> RectangleLight<'b> {
|
||||||
let bbs: Vec<_> = dimensions
|
let bbs: Vec<_> = dimensions
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -188,7 +188,7 @@ impl<'a> SurfaceLight for RectangleLight<'a> {
|
||||||
.into_point();
|
.into_point();
|
||||||
let shadow_vec = sample_point - arr;
|
let shadow_vec = sample_point - arr;
|
||||||
let spectral_sample =
|
let spectral_sample =
|
||||||
(col * surface_area_inv as f32 * 0.5).to_spectral_sample(wavelength);
|
(col).to_spectral_sample(wavelength) * surface_area_inv as f32 * 0.5;
|
||||||
let pdf = (sample_point - arr).length2()
|
let pdf = (sample_point - arr).length2()
|
||||||
/ dot(shadow_vec.normalized(), normal.into_vector().normalized()).abs()
|
/ dot(shadow_vec.normalized(), normal.into_vector().normalized()).abs()
|
||||||
/ (surface_area_1 + surface_area_2);
|
/ (surface_area_1 + surface_area_2);
|
||||||
|
@ -232,7 +232,7 @@ impl<'a> SurfaceLight for RectangleLight<'a> {
|
||||||
// Calculate pdf and light energy
|
// Calculate pdf and light energy
|
||||||
let pdf = 1.0 / (area_1 + area_2); // PDF of the ray direction being sampled
|
let pdf = 1.0 / (area_1 + area_2); // PDF of the ray direction being sampled
|
||||||
let spectral_sample =
|
let spectral_sample =
|
||||||
(col * surface_area_inv as f32 * 0.5).to_spectral_sample(wavelength);
|
col.to_spectral_sample(wavelength) * surface_area_inv as f32 * 0.5;
|
||||||
|
|
||||||
(
|
(
|
||||||
spectral_sample,
|
spectral_sample,
|
||||||
|
@ -247,12 +247,10 @@ impl<'a> SurfaceLight for RectangleLight<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn approximate_energy(&self) -> f32 {
|
fn approximate_energy(&self) -> f32 {
|
||||||
let color: XYZ = self
|
self.colors
|
||||||
.colors
|
|
||||||
.iter()
|
.iter()
|
||||||
.fold(XYZ::new(0.0, 0.0, 0.0), |a, &b| a + b)
|
.fold(0.0, |a, &b| a + b.approximate_energy())
|
||||||
/ self.colors.len() as f32;
|
/ self.colors.len() as f32
|
||||||
color.y
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use mem_arena::MemArena;
|
||||||
use crate::{
|
use crate::{
|
||||||
bbox::BBox,
|
bbox::BBox,
|
||||||
boundable::Boundable,
|
boundable::Boundable,
|
||||||
color::{Color, SpectralSample, XYZ},
|
color::{Color, SpectralSample},
|
||||||
lerp::lerp_slice,
|
lerp::lerp_slice,
|
||||||
math::{coordinate_system_from_vector, dot, Matrix4x4, Normal, Point, Vector},
|
math::{coordinate_system_from_vector, dot, Matrix4x4, Normal, Point, Vector},
|
||||||
ray::{AccelRay, Ray},
|
ray::{AccelRay, Ray},
|
||||||
|
@ -26,12 +26,12 @@ const SAMPLE_POINT_FUDGE: f32 = 0.001;
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct SphereLight<'a> {
|
pub struct SphereLight<'a> {
|
||||||
radii: &'a [f32],
|
radii: &'a [f32],
|
||||||
colors: &'a [XYZ],
|
colors: &'a [Color],
|
||||||
bounds_: &'a [BBox],
|
bounds_: &'a [BBox],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SphereLight<'a> {
|
impl<'a> SphereLight<'a> {
|
||||||
pub fn new<'b>(arena: &'b MemArena, radii: &[f32], colors: &[XYZ]) -> SphereLight<'b> {
|
pub fn new<'b>(arena: &'b MemArena, radii: &[f32], colors: &[Color]) -> SphereLight<'b> {
|
||||||
let bbs: Vec<_> = radii
|
let bbs: Vec<_> = radii
|
||||||
.iter()
|
.iter()
|
||||||
.map(|r| BBox {
|
.map(|r| BBox {
|
||||||
|
@ -164,7 +164,7 @@ impl<'a> SurfaceLight for SphereLight<'a> {
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let pdf = uniform_sample_cone_pdf(cos_theta_max);
|
let pdf = uniform_sample_cone_pdf(cos_theta_max);
|
||||||
let spectral_sample = (col * surface_area_inv as f32).to_spectral_sample(wavelength);
|
let spectral_sample = col.to_spectral_sample(wavelength) * surface_area_inv as f32;
|
||||||
return (
|
return (
|
||||||
spectral_sample,
|
spectral_sample,
|
||||||
(sample_point, normal, sample_point_err),
|
(sample_point, normal, sample_point_err),
|
||||||
|
@ -182,7 +182,7 @@ impl<'a> SurfaceLight for SphereLight<'a> {
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let pdf = 1.0 / (4.0 * PI_64);
|
let pdf = 1.0 / (4.0 * PI_64);
|
||||||
let spectral_sample = (col * surface_area_inv as f32).to_spectral_sample(wavelength);
|
let spectral_sample = col.to_spectral_sample(wavelength) * surface_area_inv as f32;
|
||||||
return (
|
return (
|
||||||
spectral_sample,
|
spectral_sample,
|
||||||
(sample_point, normal, sample_point_err),
|
(sample_point, normal, sample_point_err),
|
||||||
|
@ -196,12 +196,10 @@ impl<'a> SurfaceLight for SphereLight<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn approximate_energy(&self) -> f32 {
|
fn approximate_energy(&self) -> f32 {
|
||||||
let color: XYZ = self
|
self.colors
|
||||||
.colors
|
|
||||||
.iter()
|
.iter()
|
||||||
.fold(XYZ::new(0.0, 0.0, 0.0), |a, &b| a + b)
|
.fold(0.0, |a, &b| a + b.approximate_energy())
|
||||||
/ self.colors.len() as f32;
|
/ self.colors.len() as f32
|
||||||
color.y
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ use mem_arena::MemArena;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
camera::Camera,
|
camera::Camera,
|
||||||
color::{rec709_e_to_xyz, XYZ},
|
color::{rec709_e_to_xyz, Color},
|
||||||
light::WorldLightSource,
|
light::WorldLightSource,
|
||||||
math::Matrix4x4,
|
math::Matrix4x4,
|
||||||
renderer::Renderer,
|
renderer::Renderer,
|
||||||
|
@ -504,7 +504,7 @@ fn parse_world<'a>(arena: &'a MemArena, tree: &'a DataTree) -> Result<World<'a>,
|
||||||
{
|
{
|
||||||
// TODO: proper color space management, not just assuming
|
// TODO: proper color space management, not just assuming
|
||||||
// rec.709.
|
// rec.709.
|
||||||
background_color = XYZ::from_tuple(rec709_e_to_xyz(color));
|
background_color = Color::new_xyz(rec709_e_to_xyz(color));
|
||||||
} else {
|
} else {
|
||||||
return Err(PsyParseError::IncorrectLeafData(
|
return Err(PsyParseError::IncorrectLeafData(
|
||||||
byte_offset,
|
byte_offset,
|
||||||
|
|
|
@ -7,7 +7,7 @@ use nom::{call, closure, tuple, tuple_parser, IResult};
|
||||||
use mem_arena::MemArena;
|
use mem_arena::MemArena;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
color::{rec709_e_to_xyz, XYZ},
|
color::{rec709_e_to_xyz, Color},
|
||||||
light::{DistantDiskLight, RectangleLight, SphereLight},
|
light::{DistantDiskLight, RectangleLight, SphereLight},
|
||||||
math::Vector,
|
math::Vector,
|
||||||
};
|
};
|
||||||
|
@ -68,7 +68,7 @@ pub fn parse_distant_disk_light<'a>(
|
||||||
// TODO: handle color space conversions properly.
|
// TODO: handle color space conversions properly.
|
||||||
// Probably will need a special color type with its
|
// Probably will need a special color type with its
|
||||||
// own parser...?
|
// own parser...?
|
||||||
colors.push(XYZ::from_tuple(rec709_e_to_xyz(color)));
|
colors.push(Color::new_xyz(rec709_e_to_xyz(color)));
|
||||||
} else {
|
} else {
|
||||||
// Found color, but its contents is not in the right format
|
// Found color, but its contents is not in the right format
|
||||||
return Err(PsyParseError::UnknownError(byte_offset));
|
return Err(PsyParseError::UnknownError(byte_offset));
|
||||||
|
@ -122,7 +122,7 @@ pub fn parse_sphere_light<'a>(
|
||||||
// TODO: handle color space conversions properly.
|
// TODO: handle color space conversions properly.
|
||||||
// Probably will need a special color type with its
|
// Probably will need a special color type with its
|
||||||
// own parser...?
|
// own parser...?
|
||||||
colors.push(XYZ::from_tuple(rec709_e_to_xyz(color)));
|
colors.push(Color::new_xyz(rec709_e_to_xyz(color)));
|
||||||
} else {
|
} else {
|
||||||
// Found color, but its contents is not in the right format
|
// Found color, but its contents is not in the right format
|
||||||
return Err(PsyParseError::UnknownError(byte_offset));
|
return Err(PsyParseError::UnknownError(byte_offset));
|
||||||
|
@ -178,7 +178,7 @@ pub fn parse_rectangle_light<'a>(
|
||||||
// TODO: handle color space conversions properly.
|
// TODO: handle color space conversions properly.
|
||||||
// Probably will need a special color type with its
|
// Probably will need a special color type with its
|
||||||
// own parser...?
|
// own parser...?
|
||||||
colors.push(XYZ::from_tuple(rec709_e_to_xyz(color)));
|
colors.push(Color::new_xyz(rec709_e_to_xyz(color)));
|
||||||
} else {
|
} else {
|
||||||
// Found color, but its contents is not in the right format
|
// Found color, but its contents is not in the right format
|
||||||
return Err(PsyParseError::UnknownError(byte_offset));
|
return Err(PsyParseError::UnknownError(byte_offset));
|
||||||
|
|
|
@ -7,7 +7,7 @@ use nom::{call, closure, tuple, tuple_parser, IResult};
|
||||||
use mem_arena::MemArena;
|
use mem_arena::MemArena;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
color::{rec709_e_to_xyz, XYZ},
|
color::{rec709_e_to_xyz, Color},
|
||||||
shading::{SimpleSurfaceShader, SurfaceShader},
|
shading::{SimpleSurfaceShader, SurfaceShader},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ pub fn parse_surface_shader<'a>(
|
||||||
// TODO: handle color space conversions properly.
|
// TODO: handle color space conversions properly.
|
||||||
// Probably will need a special color type with its
|
// Probably will need a special color type with its
|
||||||
// own parser...?
|
// own parser...?
|
||||||
XYZ::from_tuple(rec709_e_to_xyz(color))
|
Color::new_xyz(rec709_e_to_xyz(color))
|
||||||
} else {
|
} else {
|
||||||
// Found color, but its contents is not in the right format
|
// Found color, but its contents is not in the right format
|
||||||
return Err(PsyParseError::UnknownError(byte_offset));
|
return Err(PsyParseError::UnknownError(byte_offset));
|
||||||
|
@ -68,7 +68,7 @@ pub fn parse_surface_shader<'a>(
|
||||||
// TODO: handle color space conversions properly.
|
// TODO: handle color space conversions properly.
|
||||||
// Probably will need a special color type with its
|
// Probably will need a special color type with its
|
||||||
// own parser...?
|
// own parser...?
|
||||||
XYZ::from_tuple(rec709_e_to_xyz(color))
|
Color::new_xyz(rec709_e_to_xyz(color))
|
||||||
} else {
|
} else {
|
||||||
// Found color, but its contents is not in the right format
|
// Found color, but its contents is not in the right format
|
||||||
return Err(PsyParseError::UnknownError(byte_offset));
|
return Err(PsyParseError::UnknownError(byte_offset));
|
||||||
|
@ -93,7 +93,7 @@ pub fn parse_surface_shader<'a>(
|
||||||
// TODO: handle color space conversions properly.
|
// TODO: handle color space conversions properly.
|
||||||
// Probably will need a special color type with its
|
// Probably will need a special color type with its
|
||||||
// own parser...?
|
// own parser...?
|
||||||
XYZ::from_tuple(rec709_e_to_xyz(color))
|
Color::new_xyz(rec709_e_to_xyz(color))
|
||||||
} else {
|
} else {
|
||||||
// Found color, but its contents is not in the right format
|
// Found color, but its contents is not in the right format
|
||||||
return Err(PsyParseError::UnknownError(byte_offset));
|
return Err(PsyParseError::UnknownError(byte_offset));
|
||||||
|
@ -172,7 +172,7 @@ pub fn parse_surface_shader<'a>(
|
||||||
// TODO: handle color space conversions properly.
|
// TODO: handle color space conversions properly.
|
||||||
// Probably will need a special color type with its
|
// Probably will need a special color type with its
|
||||||
// own parser...?
|
// own parser...?
|
||||||
XYZ::from_tuple(rec709_e_to_xyz(color))
|
Color::new_xyz(rec709_e_to_xyz(color))
|
||||||
} else {
|
} else {
|
||||||
// Found color, but its contents is not in the right format
|
// Found color, but its contents is not in the right format
|
||||||
return Err(PsyParseError::UnknownError(byte_offset));
|
return Err(PsyParseError::UnknownError(byte_offset));
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{color::XYZ, light::WorldLightSource};
|
use crate::{color::Color, light::WorldLightSource};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct World<'a> {
|
pub struct World<'a> {
|
||||||
pub background_color: XYZ,
|
pub background_color: Color,
|
||||||
pub lights: &'a [&'a WorldLightSource],
|
pub lights: &'a [&'a WorldLightSource],
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,7 @@ pub mod surface_closure;
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use crate::{
|
use crate::{color::Color, surface::SurfaceIntersectionData};
|
||||||
color::{Color, XYZ},
|
|
||||||
surface::SurfaceIntersectionData,
|
|
||||||
};
|
|
||||||
|
|
||||||
use self::surface_closure::{
|
use self::surface_closure::{
|
||||||
EmitClosure, GGXClosure, GTRClosure, LambertClosure, SurfaceClosureUnion,
|
EmitClosure, GGXClosure, GTRClosure, LambertClosure, SurfaceClosureUnion,
|
||||||
|
@ -37,19 +34,19 @@ pub trait SurfaceShader: Debug + Sync {
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum SimpleSurfaceShader {
|
pub enum SimpleSurfaceShader {
|
||||||
Emit {
|
Emit {
|
||||||
color: XYZ,
|
color: Color,
|
||||||
},
|
},
|
||||||
Lambert {
|
Lambert {
|
||||||
color: XYZ,
|
color: Color,
|
||||||
},
|
},
|
||||||
GTR {
|
GTR {
|
||||||
color: XYZ,
|
color: Color,
|
||||||
roughness: f32,
|
roughness: f32,
|
||||||
tail_shape: f32,
|
tail_shape: f32,
|
||||||
fresnel: f32,
|
fresnel: f32,
|
||||||
},
|
},
|
||||||
GGX {
|
GGX {
|
||||||
color: XYZ,
|
color: Color,
|
||||||
roughness: f32,
|
roughness: f32,
|
||||||
fresnel: f32,
|
fresnel: f32,
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::iter;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
algorithm::partition,
|
algorithm::partition,
|
||||||
color::{rec709_to_xyz, XYZ},
|
color::{rec709_to_xyz, Color},
|
||||||
lerp::lerp_slice,
|
lerp::lerp_slice,
|
||||||
ray::{AccelRay, Ray},
|
ray::{AccelRay, Ray},
|
||||||
scene::{Assembly, InstanceType, Object},
|
scene::{Assembly, InstanceType, Object},
|
||||||
|
@ -182,7 +182,7 @@ impl<'a> TracerInner<'a> {
|
||||||
match *obj {
|
match *obj {
|
||||||
Object::Surface(surface) => {
|
Object::Surface(surface) => {
|
||||||
let unassigned_shader = SimpleSurfaceShader::Emit {
|
let unassigned_shader = SimpleSurfaceShader::Emit {
|
||||||
color: XYZ::from_tuple(rec709_to_xyz((1.0, 0.0, 1.0))),
|
color: Color::new_xyz(rec709_to_xyz((1.0, 0.0, 1.0))),
|
||||||
};
|
};
|
||||||
let shader = surface_shader.unwrap_or(&unassigned_shader);
|
let shader = surface_shader.unwrap_or(&unassigned_shader);
|
||||||
|
|
||||||
|
@ -198,7 +198,7 @@ impl<'a> TracerInner<'a> {
|
||||||
Object::SurfaceLight(surface) => {
|
Object::SurfaceLight(surface) => {
|
||||||
// Lights don't use shaders
|
// Lights don't use shaders
|
||||||
let bogus_shader = SimpleSurfaceShader::Emit {
|
let bogus_shader = SimpleSurfaceShader::Emit {
|
||||||
color: XYZ::from_tuple(rec709_to_xyz((1.0, 0.0, 1.0))),
|
color: Color::new_xyz(rec709_to_xyz((1.0, 0.0, 1.0))),
|
||||||
};
|
};
|
||||||
|
|
||||||
surface.intersect_rays(
|
surface.intersect_rays(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user