aboutsummaryrefslogtreecommitdiff
path: root/src/material
diff options
context:
space:
mode:
authorJulian T <julian@jtle.dk>2021-08-01 22:55:07 +0200
committerJulian T <julian@jtle.dk>2021-08-01 22:55:07 +0200
commit86ad7845219e8db06fe47b62794180e1b40f90a5 (patch)
tree2fe1de5c4a854522536a397b7913d7c299b35c67 /src/material
parentae460c3f34838e3baf0ffafe4ccbcf1fbfe03095 (diff)
Implement dielectric material from RTIAW
Diffstat (limited to 'src/material')
-rw-r--r--src/material/dielectric.rs59
-rw-r--r--src/material/mod.rs4
2 files changed, 61 insertions, 2 deletions
diff --git a/src/material/dielectric.rs b/src/material/dielectric.rs
new file mode 100644
index 0000000..41f47c2
--- /dev/null
+++ b/src/material/dielectric.rs
@@ -0,0 +1,59 @@
+use super::Material;
+use crate::core::{min, Vector3f, Spectrum, Ray};
+use crate::world::Intersection;
+use crate::sample::Sampler;
+use crate::Float;
+
+pub struct Dielectric {
+ ratio: Float,
+}
+
+fn reflect(v: Vector3f, n: Vector3f) -> Vector3f {
+ v - n * (2.0 * v.dot(&n))
+}
+
+// Implementation from RTIOW
+fn refract(v: Vector3f, n: Vector3f, r_ratio: Float, cos_theta: Float) -> Vector3f {
+ let r_perp = (v + n * cos_theta) * r_ratio;
+ let r_parallel = n * (-(1.0 - r_perp.len_squared()).abs().sqrt());
+
+ r_perp + r_parallel
+}
+
+// Schlick Approximation, explained in RTIOW
+fn fresnel(cos: Float, ratio: Float) -> Float {
+ let mut r0 = (1.0-ratio) / (1.0+ratio);
+ r0 = r0 * r0;
+
+ r0 + (1.0-r0)*(1.0-cos).powi(5)
+}
+
+impl Dielectric {
+ pub fn new(ratio: Float) -> Self {
+ Self { ratio }
+ }
+}
+
+impl Material for Dielectric {
+ // Implementation from RTIOW
+ fn scatter(&self, ray: &Ray, i: &Intersection, sampler: &mut dyn Sampler) -> Option<(Spectrum, Ray)> {
+ let ratio = if i.front {1.0/self.ratio} else {self.ratio};
+
+ let ray_dir = ray.direction.norm();
+ let cos_theta = min((-ray_dir).dot(&i.n), 1.0);
+ let sin_theta = (1.0 - cos_theta*cos_theta).sqrt();
+
+ // Test if it is possible for the ray the retract or if it must reflect.
+ let cannot_refract = (ratio * sin_theta) > 1.0;
+ let direction = if cannot_refract || (fresnel(cos_theta, ratio) > sampler.get_sample()) {
+ reflect(ray_dir, i.n)
+ } else {
+ refract(ray_dir, i.n, ratio, cos_theta)
+ };
+
+ Some((
+ Spectrum::WHITE,
+ Ray::new(i.p, direction),
+ ))
+ }
+}
diff --git a/src/material/mod.rs b/src/material/mod.rs
index 3e92bf6..d3c3154 100644
--- a/src/material/mod.rs
+++ b/src/material/mod.rs
@@ -3,14 +3,14 @@ use crate::world::Intersection;
use crate::sample::Sampler;
mod lambertian;
-mod reflectant;
mod diffuse_light;
mod sky_light;
+mod dielectric;
pub use lambertian::Lambertian;
-pub use reflectant::Reflectant;
pub use diffuse_light::DiffuseLight;
pub use sky_light::SkyLight;
+pub use dielectric::Dielectric;
pub trait Material: Sync + Send {
fn scatter(&self, _: &Ray, _: &Intersection, _: &mut dyn Sampler) -> Option<(Spectrum, Ray)> {