From 89a5c9a8a0cdf627cda0e31da454f83ca21315ce Mon Sep 17 00:00:00 2001 From: lamp Date: Sun, 21 Jan 2024 16:40:16 +0000 Subject: implement beer's law for colourful dielectrics --- src/hittable/constant_medium.rs | 2 +- src/main.rs | 6 +++--- src/material/dielectric.rs | 25 ++++++++++++++++++++++++- src/material/mod.rs | 1 + src/scenes.rs | 16 ++++++++-------- 5 files changed, 37 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/hittable/constant_medium.rs b/src/hittable/constant_medium.rs index b047c23..36ac2ff 100644 --- a/src/hittable/constant_medium.rs +++ b/src/hittable/constant_medium.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use crate::{hittable::{HitRecord, Hittable, AABB}, material::{Isotropic, Material}, ray::Ray, texture::Texture, vec3::Vec3}; +use crate::{hittable::{HitRecord, Hittable, AABB}, material::{Isotropic, Material}, ray::Ray, texture::Texture, vec3::{Vec3, Point3}}; pub struct ConstantMedium { boundary: Arc, diff --git a/src/main.rs b/src/main.rs index c99ca58..0fe2df9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,7 @@ use camera::Camera; use hittable::Hittable; use display::{Display, Image, Pixelflut}; use ray::Ray; -use vec3::{Vec3, Color}; +use vec3::{Vec3, Color, Point3}; use scenes::get_scene; struct PixelUpdate { @@ -33,7 +33,7 @@ fn ray_color(ray: &Ray, background: &Color, world: &dyn Hittable, depth: u32) -> } match world.hit(ray, 0.001, f64::INFINITY) { None => background.clone(), - Some(rec) => { + Some(mut rec) => { let mut scattered = Ray::new(); let mut attenuation = Color::new(); if let Some(material) = &rec.material { @@ -70,7 +70,7 @@ fn main() { //const ASPECT_RATIO: f64 = 1.0; const IMAGE_WIDTH: u32 = 600; const IMAGE_HEIGHT: u32 = (IMAGE_WIDTH as f64 / ASPECT_RATIO) as u32; - const SAMPLES_PER_PIXEL: u32 = 500; + const SAMPLES_PER_PIXEL: u32 = 30; const MAX_DEPTH: u32 = 50; const THREAD_COUNT: u32 = 8; const TIME_START: f64 = 0.0; diff --git a/src/material/dielectric.rs b/src/material/dielectric.rs index bcacb78..1a49f73 100644 --- a/src/material/dielectric.rs +++ b/src/material/dielectric.rs @@ -1,10 +1,18 @@ +use std::ops::Neg; + use super::Material; use crate::{hittable::HitRecord, vec3::Vec3}; use crate::vec3::Color; use crate::ray::Ray; +pub struct DielectricAttenuation { + pub albedo: Color, + pub constant: f64, +} + pub struct Dielectric { pub index_of_refraction: f64, + pub attenuation: Option, } impl Dielectric { @@ -18,7 +26,22 @@ impl Dielectric { impl Material for Dielectric { fn scatter(&self, ray_in: &Ray, hit_record: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool { - *attenuation = Color { x: 1.0, y: 1.0, z: 1.0 }; + if let Some(props) = &self.attenuation { + let outward_normal = if hit_record.front_face { + hit_record.normal.clone() + } else { + -&hit_record.normal + }; + if outward_normal.dot(&ray_in.direction) > 0.0 { + let distance = (&ray_in.origin - &hit_record.p).length(); + let falloff_ratio = (props.constant * distance).neg().exp(); + *attenuation = &props.albedo * falloff_ratio; + } else { + *attenuation = props.albedo.clone(); + } + } else { + *attenuation = Color { x: 1.0, y: 1.0, z: 1.0 }; + } let refraction_ratio = if hit_record.front_face { 1.0 / self.index_of_refraction } else { self.index_of_refraction }; let unit_direction = ray_in.direction.unit_vector(); let cos_theta = hit_record.normal.dot(&-&unit_direction).min(1.0); diff --git a/src/material/mod.rs b/src/material/mod.rs index bf1eb24..c292ea1 100644 --- a/src/material/mod.rs +++ b/src/material/mod.rs @@ -4,6 +4,7 @@ mod metal; pub use metal::Metal; mod dielectric; pub use dielectric::Dielectric; +pub use dielectric::DielectricAttenuation; mod diffuse_light; pub use diffuse_light::DiffuseLight; mod isotropic; diff --git a/src/scenes.rs b/src/scenes.rs index 7cdce86..54f6eb3 100644 --- a/src/scenes.rs +++ b/src/scenes.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use crate::hittable::{ConstantMedium, Hittable}; use crate::hittable::HittableBox; use crate::hittable::HittableList; -use crate::material::{Dielectric, DiffuseLight, Lambertian, Material, Metal}; +use crate::material::{Dielectric, DielectricAttenuation, DiffuseLight, Lambertian, Material, Metal}; use crate::hittable::instance::RotateY; use crate::hittable::instance::RotateX; use crate::hittable::instance::RotateZ; @@ -59,14 +59,14 @@ fn random_scene() -> (Arc, Point3, Point3, f64, f64, Color) { sphere_material = Arc::new(Metal { albedo, fuzz }); world.add(Arc::new(Sphere { center, radius: 0.2, material: sphere_material })); } else { - sphere_material = Arc::new(Dielectric { index_of_refraction: 1.5 }); + sphere_material = Arc::new(Dielectric { index_of_refraction: 1.5, attenuation: Some(DielectricAttenuation { albedo: Color { x: 0.5, y: 0.5, z: 0.8 }, constant: 0.8 } ) }); world.add(Arc::new(Sphere { center, radius: 0.2, material: sphere_material })); } } } } - let material1 = Arc::new(Dielectric { index_of_refraction: 1.5 }); + let material1 = Arc::new(Dielectric { index_of_refraction: 1.5, attenuation: Some(DielectricAttenuation { albedo: Color { x: 0.5, y: 0.5, z: 0.8 }, constant: 0.8 } ) }); world.add(Arc::new(Sphere { center: Point3 { x: 0.0, y: 1.0, z: 0.0 }, radius: 1.0, material: material1 })); let material2 = Arc::new(Lambertian { albedo: Arc::new(SolidColor::from_color(Color { x: 0.4, y: 0.2, z: 0.1 })) }); @@ -199,13 +199,13 @@ fn final_scene() -> (Arc, Point3, Point3, f64, f64, Color) { let moving_sphere_material = Arc::new(Lambertian::from_color(Color { x: 0.7, y: 0.3, z: 0.1 })); objects.add(Arc::new(Moving { hittable: Arc::new(Sphere { center: Point3::new(), radius: 50.0, material: moving_sphere_material }), offset_start: center_1, offset_end: center_2, time_start: 0.0, time_end: 1.0, })); - objects.add(Arc::new(Sphere { center: Point3 { x: 260.0, y: 150.0, z: 45.0 }, radius: 50.0, material: Arc::new(Dielectric { index_of_refraction: 1.5 }) })); + objects.add(Arc::new(Sphere { center: Point3 { x: 260.0, y: 150.0, z: 45.0 }, radius: 50.0, material: Arc::new(Dielectric { index_of_refraction: 1.5, attenuation: None }) })); objects.add(Arc::new(Sphere { center: Point3 { x: 0.0, y: 150.0, z: 145.0 }, radius: 50.0, material: Arc::new(Metal { albedo: Color { x: 0.8, y: 0.8, z: 0.9 }, fuzz: 1.0 }) })); - let boundary = Arc::new(Sphere { center: Point3 { x: 360.0, y: 150.0, z: 145.0 }, radius: 70.0, material: Arc::new(Dielectric { index_of_refraction: 1.5 }) }); + let boundary = Arc::new(Sphere { center: Point3 { x: 360.0, y: 150.0, z: 145.0 }, radius: 70.0, material: Arc::new(Dielectric { index_of_refraction: 1.5, attenuation: None }) }); objects.add(boundary.clone()); objects.add(Arc::new(ConstantMedium::new(boundary.clone(), 0.2, Arc::new(SolidColor::from_color(Color { x: 0.2, y: 0.4, z: 0.9 }))))); - let boundary = Arc::new(Sphere { center: Point3 { x: 0.0, y: 0.0, z: 0.0 }, radius: 5000.0, material: Arc::new(Dielectric { index_of_refraction: 1.5 }) }); + let boundary = Arc::new(Sphere { center: Point3 { x: 0.0, y: 0.0, z: 0.0 }, radius: 5000.0, material: Arc::new(Dielectric { index_of_refraction: 1.5, attenuation: None }) }); objects.add(Arc::new(ConstantMedium::new(boundary.clone(), 0.0001, Arc::new(SolidColor::from_color(Color { x: 1.0, y: 1.0, z: 1.0 }))))); let emat = Arc::new(Lambertian { albedo: Arc::new(ImageTexture::from_bmp_data(&include_bytes!("../res/earthmap.bmp").to_vec())) }); @@ -242,8 +242,8 @@ fn triangle_scene() -> (Arc, Point3, Point3, f64, f64, Color) { //let pertext = Arc::new(Lambertian { albedo: Arc::new(NoiseTexture::new(4.0)) }); //let pertext = Arc::new(Lambertian { albedo: Arc::new(SolidColor::from_color(Color {x: 0.0, y: 0.0, z: 0.0}) ) }); //objects.add(Arc::new(Triangle { material: Arc::new(Metal { albedo: Color { x: 0.7, y: 0.6, z: 0.5 }, fuzz: 0.0 }), v0 : Vec3::new(), v1: Vec3 { x: 0.0, y: 0.0, z: 1.0 }, v2: Vec3 { x: 0.0, y: 1.0, z: 0.5 } })); - //let monkey = Arc::new(Model::from_obj(include_str!("../res/monkey.obj"), Arc::new(Dielectric { index_of_refraction: 1.5 }))); - let monkey = Arc::new(Model::from_obj(include_str!("../res/monkey.obj"), Arc::new(Metal { albedo: Color { x: 0.7, y: 0.6, z: 0.5 }, fuzz: 0.5 }))); + let monkey = Arc::new(Model::from_obj(include_str!("../res/monkey.obj"), Arc::new(Dielectric { index_of_refraction: 1.5, attenuation: Some(DielectricAttenuation { albedo: Color { x: 0.5, y: 0.5, z: 0.8 }, constant: 0.8 } ) }))); + // let monkey = Arc::new(Model::from_obj(include_str!("../res/monkey.obj"), Arc::new(Metal { albedo: Color { x: 0.7, y: 0.6, z: 0.5 }, fuzz: 0.5 }))); let monkey = Arc::new(RotateX::new(monkey, 45.0)); let monkey = Arc::new(RotateZ::new(monkey, 45.0)); objects.add(monkey); -- cgit v1.2.3