Break material module up into multiple files
This commit is contained in:
parent
90bb7d84af
commit
cb67362ad4
109
src/materials.rs
109
src/materials.rs
|
|
@ -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)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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()))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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)]
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue