From 2269bd102dbfcedea20504692977a15a6040393f Mon Sep 17 00:00:00 2001 From: hal8174 Date: Thu, 28 Aug 2025 00:22:58 +0200 Subject: [PATCH] Add dielectric pbrt material --- ray-tracing-core/src/math/material.rs | 15 ++++++++ ray-tracing-core/src/math/mod.rs | 1 + .../src/bin/fresnel.rs | 3 +- ray-tracing-material/src/microfacet.rs | 16 +-------- ray-tracing-pbrt-scene/src/material.rs | 35 +++++++++++++------ 5 files changed, 43 insertions(+), 27 deletions(-) create mode 100644 ray-tracing-core/src/math/material.rs diff --git a/ray-tracing-core/src/math/material.rs b/ray-tracing-core/src/math/material.rs new file mode 100644 index 0000000..7300c7a --- /dev/null +++ b/ray-tracing-core/src/math/material.rs @@ -0,0 +1,15 @@ +use crate::prelude::*; + +pub fn fresnel_real(cos_theta_in: Float, nu1: Float, nu2: Float) -> Float { + let nu_rel = nu1 / nu2; + let cos_theta_tr = Float::sqrt(1.0 - nu_rel * nu_rel * (1.0 - cos_theta_in * cos_theta_in)); + + let rs = ((nu1 * cos_theta_in - nu2 * cos_theta_tr) + / (nu1 * cos_theta_in + nu2 * cos_theta_tr)) + .powi(2); + let rp = ((nu1 * cos_theta_tr - nu2 * cos_theta_in) + / (nu1 * cos_theta_tr + nu2 * cos_theta_in)) + .powi(2); + + 0.5 * (rs + rp) +} diff --git a/ray-tracing-core/src/math/mod.rs b/ray-tracing-core/src/math/mod.rs index be5acb3..8fa1126 100644 --- a/ray-tracing-core/src/math/mod.rs +++ b/ray-tracing-core/src/math/mod.rs @@ -1,6 +1,7 @@ pub mod dir3; pub mod frame; pub mod mat3; +pub mod material; pub mod pos3; pub mod sampling; diff --git a/ray-tracing-material-visualizer/src/bin/fresnel.rs b/ray-tracing-material-visualizer/src/bin/fresnel.rs index 90ae34c..2c32c52 100644 --- a/ray-tracing-material-visualizer/src/bin/fresnel.rs +++ b/ray-tracing-material-visualizer/src/bin/fresnel.rs @@ -1,6 +1,5 @@ use plotters::prelude::*; -use ray_tracing_core::prelude::*; -use ray_tracing_material::microfacet::fresnel_real; +use ray_tracing_core::{math::material::fresnel_real, prelude::*}; fn main() -> Result<(), Box> { let root = BitMapBackend::new("fresnel.png", (640, 480)).into_drawing_area(); diff --git a/ray-tracing-material/src/microfacet.rs b/ray-tracing-material/src/microfacet.rs index 9f37681..afed1b0 100644 --- a/ray-tracing-material/src/microfacet.rs +++ b/ray-tracing-material/src/microfacet.rs @@ -1,5 +1,5 @@ use rand_distr::{Distribution, Normal}; -use ray_tracing_core::{material::Material, prelude::*}; +use ray_tracing_core::{material::Material, math::material::fresnel_real, prelude::*}; use std::fmt::Debug; #[derive(Debug)] @@ -14,20 +14,6 @@ impl Microfacet { } } -pub fn fresnel_real(cos_theta_in: Float, nu1: Float, nu2: Float) -> Float { - let nu_rel = nu1 / nu2; - let cos_theta_tr = Float::sqrt(1.0 - nu_rel * nu_rel * (1.0 - cos_theta_in * cos_theta_in)); - - let rs = ((nu1 * cos_theta_in - nu2 * cos_theta_tr) - / (nu1 * cos_theta_in + nu2 * cos_theta_tr)) - .powi(2); - let rp = ((nu1 * cos_theta_tr - nu2 * cos_theta_in) - / (nu1 * cos_theta_tr + nu2 * cos_theta_in)) - .powi(2); - - 0.5 * (rs + rp) -} - impl Material for Microfacet { fn eval(&self, w_in: Dir3, w_out: Dir3, _rng: &mut R) -> ray_tracing_core::prelude::Color { if w_out.y() > 0.0 && w_in.y() > 0.0 { diff --git a/ray-tracing-pbrt-scene/src/material.rs b/ray-tracing-pbrt-scene/src/material.rs index 4c837da..f9902fc 100644 --- a/ray-tracing-pbrt-scene/src/material.rs +++ b/ray-tracing-pbrt-scene/src/material.rs @@ -1,4 +1,6 @@ -use ray_tracing_core::{color::Color, material::SampleResult, prelude::*}; +use ray_tracing_core::{ + color::Color, material::SampleResult, math::material::fresnel_real, prelude::*, +}; use crate::{ either::Either, @@ -103,20 +105,33 @@ impl PbrtMaterial for PbrtDielectricMaterial { let _ = rng; let _ = v; let _ = u; - let _ = match self.eta { + let eta = match self.eta { Either::A(Either::A(eta)) => eta, _ => todo!(), }; - // let c = w_in.y(); - // let w_out = -w_in * eta - // + (eta * c - Float::sqrt(1.0 - eta * eta * (1.0 - c * c))) * Dir3::new(0.0, -1.0, 1.0); + let (n1, n2) = if w_in.y() >= 0.0 { + (1.0, eta) + } else { + (eta, 1.0) + }; - SampleResult::new( - Dir3::new(0.0, 2.0 * w_in.y(), 0.0) - w_in, - Color::white(), - true, - ) + let r = fresnel_real(w_in.y().abs(), n1, n2); + + if r >= rng.r#gen() { + SampleResult::new( + Dir3::new(0.0, 2.0 * w_in.y(), 0.0) - w_in, + Color::white(), + true, + ) + } else { + let r = n1 / n2; + let w_out = -w_in * r + + (r * w_in.y().abs() - Float::sqrt(1.0 - r * r * (1.0 - w_in.y() * w_in.y()))) + * Dir3::new(0.0, if w_in.y() > 0.0 { 1.0 } else { -1.0 }, 0.0); + + SampleResult::new(w_out, Color::white(), true) + } } fn pdf(&self, u: Float, v: Float, w_in: Dir3, w_out: Dir3) -> Float {