Break material module up into multiple files

This commit is contained in:
Matthew Gordon 2020-06-11 22:28:53 -04:00
parent 90bb7d84af
commit cb67362ad4
5 changed files with 141 additions and 109 deletions

View File

@ -1,109 +0,0 @@
use nalgebra::{clamp, convert, Vector3};
use super::colour::{ColourRgbF, NamedColour};
use crate::Real;
use std::fmt::Debug;
type Bsdf<T> = Box<dyn Fn(Vector3<T>, Vector3<T>, ColourRgbF<T>) -> ColourRgbF<T>>;
pub trait Material<T: Real>: Debug + Sync + Send {
fn bsdf(&self) -> Bsdf<T>;
fn sample(&self, _w_o: &Vector3<T>) -> Vec<Vector3<T>> {
vec![]
}
}
#[derive(Debug)]
pub struct LambertianMaterial<T: Real> {
pub colour: ColourRgbF<T>,
pub diffuse_strength: T,
}
impl<T: Real> LambertianMaterial<T> {
pub fn new_dummy() -> LambertianMaterial<T> {
LambertianMaterial {
colour: ColourRgbF::new(T::one(), T::one(), T::one()),
diffuse_strength: T::one(),
}
}
}
impl<T: Real> Material<T> for LambertianMaterial<T> {
fn bsdf(&self) -> Bsdf<T> {
let colour = self.colour * self.diffuse_strength;
Box::new(
move |_w_o: Vector3<T>, _w_i: Vector3<T>, colour_in: ColourRgbF<T>| colour * colour_in,
)
}
}
#[derive(Debug)]
pub struct PhongMaterial<T: Real> {
pub colour: ColourRgbF<T>,
pub diffuse_strength: T,
pub specular_strength: T,
pub smoothness: T,
}
impl<T: Real> Material<T> for PhongMaterial<T> {
fn bsdf(&self) -> Bsdf<T> {
let smoothness = self.smoothness;
let specular_strength = self.specular_strength;
let colour = self.colour * self.diffuse_strength;
Box::new(
move |w_o: Vector3<T>, w_i: Vector3<T>, colour_in: ColourRgbF<T>| {
if w_i.z < T::zero() || w_o.z < T::zero() {
ColourRgbF::from_vector3(&Vector3::zeros())
} else {
let reflection_vector = Vector3::new(-w_i.x, -w_i.y, w_i.z);
colour * colour_in
+ ColourRgbF::from_named(NamedColour::White)
* w_o.dot(&reflection_vector).abs().powf(smoothness)
* (specular_strength / w_i.dot(&Vector3::z_axis()))
}
},
)
}
}
#[derive(Debug)]
pub struct ReflectiveMaterial<T: Real> {
pub colour: ColourRgbF<T>,
pub diffuse_strength: T,
pub reflection_strength: T,
}
impl<T: Real> Material<T> for ReflectiveMaterial<T> {
fn bsdf(&self) -> Bsdf<T> {
let diffuse_colour_factor = self.colour * self.diffuse_strength;
let reflection_strength = self.reflection_strength;
Box::new(
move |w_o: Vector3<T>, w_i: Vector3<T>, colour_in: ColourRgbF<T>| {
if w_i.z < T::zero() || w_o.z < T::zero() {
ColourRgbF::new(T::zero(), T::one(), T::one())
} else {
let reflection_vector = Vector3::new(-w_o.x, -w_o.y, w_o.z);
let reflection_colour = colour_in * reflection_strength;
let diffuse_colour = diffuse_colour_factor * colour_in;
let sigma: T = convert(0.05);
let two: T = convert(2.0);
// These are normalized vectors, but sometimes rounding errors cause the
// dot product to be slightly above 1 or below 0. The call to clamp
// ensures the values stay within the domain of acos,
let theta = clamp(w_i.dot(&reflection_vector), T::zero(), T::one())
.abs()
.acos();
let reflection_factor = (-(theta.powf(two)) / (two * sigma * sigma)).exp();
reflection_colour * reflection_factor
+ diffuse_colour * (T::one() - reflection_factor)
}
},
)
}
fn sample(&self, w_o: &Vector3<T>) -> Vec<Vector3<T>> {
vec![Vector3::new(-w_o.x, -w_o.y, w_o.z)]
}
}

View File

@ -0,0 +1,32 @@
use nalgebra::Vector3;
use crate::colour::ColourRgbF;
use crate::Real;
use super::{Bsdf, Material};
use std::fmt::Debug;
#[derive(Debug)]
pub struct LambertianMaterial<T: Real> {
pub colour: ColourRgbF<T>,
pub diffuse_strength: T,
}
impl<T: Real> LambertianMaterial<T> {
pub fn new_dummy() -> LambertianMaterial<T> {
LambertianMaterial {
colour: ColourRgbF::new(T::one(), T::one(), T::one()),
diffuse_strength: T::one(),
}
}
}
impl<T: Real> Material<T> for LambertianMaterial<T> {
fn bsdf(&self) -> Bsdf<T> {
let colour = self.colour * self.diffuse_strength;
Box::new(
move |_w_o: Vector3<T>, _w_i: Vector3<T>, colour_in: ColourRgbF<T>| colour * colour_in,
)
}
}

25
src/materials/mod.rs Normal file
View File

@ -0,0 +1,25 @@
use nalgebra::Vector3;
use super::colour::ColourRgbF;
use crate::Real;
use std::fmt::Debug;
type Bsdf<T> = Box<dyn Fn(Vector3<T>, Vector3<T>, ColourRgbF<T>) -> ColourRgbF<T>>;
pub mod lambertian_material;
pub use lambertian_material::LambertianMaterial;
pub mod phong_material;
pub use phong_material::PhongMaterial;
pub mod reflective_material;
pub use reflective_material::ReflectiveMaterial;
pub trait Material<T: Real>: Debug + Sync + Send {
fn bsdf(&self) -> Bsdf<T>;
fn sample(&self, _w_o: &Vector3<T>) -> Vec<Vector3<T>> {
vec![]
}
}

View File

@ -0,0 +1,37 @@
use nalgebra::Vector3;
use crate::colour::{ColourRgbF, NamedColour};
use crate::Real;
use std::fmt::Debug;
use super::{Bsdf, Material};
#[derive(Debug)]
pub struct PhongMaterial<T: Real> {
pub colour: ColourRgbF<T>,
pub diffuse_strength: T,
pub specular_strength: T,
pub smoothness: T,
}
impl<T: Real> Material<T> for PhongMaterial<T> {
fn bsdf(&self) -> Bsdf<T> {
let smoothness = self.smoothness;
let specular_strength = self.specular_strength;
let colour = self.colour * self.diffuse_strength;
Box::new(
move |w_o: Vector3<T>, w_i: Vector3<T>, colour_in: ColourRgbF<T>| {
if w_i.z < T::zero() || w_o.z < T::zero() {
ColourRgbF::from_vector3(&Vector3::zeros())
} else {
let reflection_vector = Vector3::new(-w_i.x, -w_i.y, w_i.z);
colour * colour_in
+ ColourRgbF::from_named(NamedColour::White)
* w_o.dot(&reflection_vector).abs().powf(smoothness)
* (specular_strength / w_i.dot(&Vector3::z_axis()))
}
},
)
}
}

View File

@ -0,0 +1,47 @@
use nalgebra::{clamp, convert, Vector3};
use crate::colour::ColourRgbF;
use crate::Real;
use std::fmt::Debug;
use super::{Bsdf, Material};
#[derive(Debug)]
pub struct ReflectiveMaterial<T: Real> {
pub colour: ColourRgbF<T>,
pub diffuse_strength: T,
pub reflection_strength: T,
}
impl<T: Real> Material<T> for ReflectiveMaterial<T> {
fn bsdf(&self) -> Bsdf<T> {
let diffuse_colour_factor = self.colour * self.diffuse_strength;
let reflection_strength = self.reflection_strength;
Box::new(
move |w_o: Vector3<T>, w_i: Vector3<T>, colour_in: ColourRgbF<T>| {
if w_i.z < T::zero() || w_o.z < T::zero() {
ColourRgbF::new(T::zero(), T::one(), T::one())
} else {
let reflection_vector = Vector3::new(-w_o.x, -w_o.y, w_o.z);
let reflection_colour = colour_in * reflection_strength;
let diffuse_colour = diffuse_colour_factor * colour_in;
let sigma: T = convert(0.05);
let two: T = convert(2.0);
// These are normalized vectors, but sometimes rounding errors cause the
// dot product to be slightly above 1 or below 0. The call to clamp
// ensures the values stay within the domain of acos,
let theta = clamp(w_i.dot(&reflection_vector), T::zero(), T::one())
.abs()
.acos();
let reflection_factor = (-(theta.powf(two)) / (two * sigma * sigma)).exp();
reflection_colour * reflection_factor
+ diffuse_colour * (T::one() - reflection_factor)
}
},
)
}
fn sample(&self, w_o: &Vector3<T>) -> Vec<Vector3<T>> {
vec![Vector3::new(-w_o.x, -w_o.y, w_o.z)]
}
}