Completed isotropic materials and constant medium/volumes
This commit is contained in:
parent
73e7085818
commit
f9b682a12c
119
src/demos/cornell_smoke_and_fog.rs
Normal file
119
src/demos/cornell_smoke_and_fog.rs
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use rand::{prelude::SmallRng, SeedableRng};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
demos::{Demo, ParallelHit},
|
||||||
|
hitable::{
|
||||||
|
shapes::{Cuboid, RectBuilder},
|
||||||
|
volume::ConstantMedium,
|
||||||
|
Hitable,
|
||||||
|
},
|
||||||
|
materials::{DiffuseLight, Isotropic, Lambertian, MaterialBuilder},
|
||||||
|
texture::Solid,
|
||||||
|
types::Vec3,
|
||||||
|
BvhNode, Camera,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct CornellSmokeAndFog {}
|
||||||
|
|
||||||
|
impl Demo for CornellSmokeAndFog {
|
||||||
|
type DemoT = BvhNode<Arc<dyn ParallelHit>>;
|
||||||
|
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"cornell_smoke_and_fog"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn world(&self) -> Self::DemoT {
|
||||||
|
let mut world: Vec<Arc<dyn ParallelHit>> = Vec::with_capacity(8);
|
||||||
|
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let mut rng = SmallRng::from_rng(&mut rng).unwrap();
|
||||||
|
|
||||||
|
let red = Lambertian::new(Solid::new(Vec3::new(0.65, 0.05, 0.05)));
|
||||||
|
let white = Lambertian::new(Solid::new(Vec3::splat(0.73)));
|
||||||
|
let green = Lambertian::new(Solid::new(Vec3::new(0.12, 0.45, 0.15)));
|
||||||
|
let light = DiffuseLight::new(Solid::new(Vec3::splat(7.0)));
|
||||||
|
|
||||||
|
world.push(Arc::new(
|
||||||
|
RectBuilder
|
||||||
|
.y(0.0..=555.0)
|
||||||
|
.z(0.0..=555.0)
|
||||||
|
.x(555.0)
|
||||||
|
.material(green),
|
||||||
|
));
|
||||||
|
world.push(Arc::new(
|
||||||
|
RectBuilder
|
||||||
|
.y(0.0..=555.0)
|
||||||
|
.z(0.0..=555.0)
|
||||||
|
.x(0.0)
|
||||||
|
.material(red),
|
||||||
|
));
|
||||||
|
|
||||||
|
world.push(Arc::new(
|
||||||
|
RectBuilder
|
||||||
|
.x(113.0..=443.0)
|
||||||
|
.z(127.0..=432.0)
|
||||||
|
.y(554.0)
|
||||||
|
.material(light),
|
||||||
|
));
|
||||||
|
world.push(Arc::new(
|
||||||
|
RectBuilder
|
||||||
|
.x(0.0..=555.0)
|
||||||
|
.z(0.0..=555.0)
|
||||||
|
.y(0.0)
|
||||||
|
.material(white),
|
||||||
|
));
|
||||||
|
|
||||||
|
world.push(Arc::new(
|
||||||
|
RectBuilder
|
||||||
|
.x(0.0..=555.0)
|
||||||
|
.z(0.0..=555.0)
|
||||||
|
.y(555.0)
|
||||||
|
.material(white),
|
||||||
|
));
|
||||||
|
world.push(Arc::new(
|
||||||
|
RectBuilder
|
||||||
|
.x(0.0..=555.0)
|
||||||
|
.y(0.0..=555.0)
|
||||||
|
.z(555.0)
|
||||||
|
.material(white),
|
||||||
|
));
|
||||||
|
|
||||||
|
// Add the two boxes
|
||||||
|
world.push(Arc::new(ConstantMedium::new(
|
||||||
|
Cuboid::new(Vec3::splat(0.0), Vec3::new(165.0, 330.0, 165.0), white)
|
||||||
|
.rotate_y(15.0)
|
||||||
|
.translate(Vec3::new(265.0, 0.0, 295.0)),
|
||||||
|
Isotropic::new(Solid::new(Vec3::splat(0.0))),
|
||||||
|
0.01,
|
||||||
|
)));
|
||||||
|
world.push(Arc::new(ConstantMedium::new(
|
||||||
|
Cuboid::new(Vec3::splat(0.0), Vec3::splat(165.0), white)
|
||||||
|
.rotate_y(-18.0)
|
||||||
|
.translate(Vec3::new(130.0, 0.0, 65.0)),
|
||||||
|
Isotropic::new(Solid::new(Vec3::splat(1.0))),
|
||||||
|
0.01,
|
||||||
|
)));
|
||||||
|
|
||||||
|
BvhNode::new(&mut rng, &mut world, 0.0, 1.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn camera(&self, aspect_ratio: f64) -> Camera {
|
||||||
|
let lookfrom = Vec3::new(278.0, 278.0, -800.0);
|
||||||
|
let lookat = Vec3::new(278.0, 278.0, 0.0);
|
||||||
|
let aperture = 0.1;
|
||||||
|
let focus_distance = 40.0;
|
||||||
|
Camera::new(
|
||||||
|
lookfrom,
|
||||||
|
lookat,
|
||||||
|
Vec3::new(0.0, 1.0, 0.0),
|
||||||
|
40.0,
|
||||||
|
aspect_ratio,
|
||||||
|
aperture,
|
||||||
|
focus_distance,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
mod checkered_motion_blur;
|
mod checkered_motion_blur;
|
||||||
|
mod cornell_smoke_and_fog;
|
||||||
mod image_texture;
|
mod image_texture;
|
||||||
mod instances;
|
mod instances;
|
||||||
mod perlin_noise_ball;
|
mod perlin_noise_ball;
|
||||||
|
@ -20,6 +21,7 @@ mod simple_light;
|
||||||
mod two_spheres;
|
mod two_spheres;
|
||||||
|
|
||||||
pub use checkered_motion_blur::CheckeredMotionBlur;
|
pub use checkered_motion_blur::CheckeredMotionBlur;
|
||||||
|
pub use cornell_smoke_and_fog::CornellSmokeAndFog;
|
||||||
pub use image_texture::ImageTextureDemo;
|
pub use image_texture::ImageTextureDemo;
|
||||||
pub use instances::Instances;
|
pub use instances::Instances;
|
||||||
pub use perlin_noise_ball::PerlinNoiseBall;
|
pub use perlin_noise_ball::PerlinNoiseBall;
|
||||||
|
|
|
@ -3,6 +3,7 @@ pub mod hitable_list;
|
||||||
mod rotate;
|
mod rotate;
|
||||||
pub mod shapes;
|
pub mod shapes;
|
||||||
mod translate;
|
mod translate;
|
||||||
|
pub mod volume;
|
||||||
|
|
||||||
pub use bvh::*;
|
pub use bvh::*;
|
||||||
pub use translate::*;
|
pub use translate::*;
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::marker::PhantomData;
|
||||||
use crate::{
|
use crate::{
|
||||||
hitable::{HitRecord, Hitable},
|
hitable::{HitRecord, Hitable},
|
||||||
types::{Ray, Vec3},
|
types::{Ray, Vec3},
|
||||||
Aabb, Dimension, X, Y, Z,
|
Aabb, Dimension,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Rotate<D1, D2, D3, T: Hitable> {
|
pub struct Rotate<D1, D2, D3, T: Hitable> {
|
||||||
|
@ -28,7 +28,7 @@ where
|
||||||
let cos_theta = radians.cos();
|
let cos_theta = radians.cos();
|
||||||
|
|
||||||
let mut min = Vec3::splat(f64::MAX);
|
let mut min = Vec3::splat(f64::MAX);
|
||||||
let mut max = Vec3::splat(-f64::MAX);
|
let mut max = Vec3::splat(f64::MIN);
|
||||||
|
|
||||||
let bbox = if let Some(bbox) = object.bounding_box(0.0, 1.0) {
|
let bbox = if let Some(bbox) = object.bounding_box(0.0, 1.0) {
|
||||||
for i in 0..2 {
|
for i in 0..2 {
|
||||||
|
|
63
src/hitable/volume/constant_medium.rs
Normal file
63
src/hitable/volume/constant_medium.rs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
use crate::{
|
||||||
|
hitable::{HitRecord, Hitable},
|
||||||
|
types::{Ray, Vec3},
|
||||||
|
Aabb, Material,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct ConstantMedium<A: Hitable, B: Material> {
|
||||||
|
neg_inv_density: f64,
|
||||||
|
boundary: A,
|
||||||
|
phase_function: B,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Hitable, B: Material> ConstantMedium<A, B> {
|
||||||
|
pub fn new(boundary: A, phase_function: B, d: f64) -> Self {
|
||||||
|
Self {
|
||||||
|
boundary,
|
||||||
|
phase_function,
|
||||||
|
neg_inv_density: -1.0 / d,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Hitable, B: Material> Hitable for ConstantMedium<A, B> {
|
||||||
|
fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
|
||||||
|
let mut hit1 = self.boundary.hit(ray, f64::MIN, f64::MAX)?;
|
||||||
|
let mut hit2 = self.boundary.hit(ray, hit1.t + 0.0001, f64::MAX)?;
|
||||||
|
|
||||||
|
hit1.t = hit1.t.max(t_min);
|
||||||
|
hit2.t = hit2.t.min(t_max);
|
||||||
|
|
||||||
|
if hit1.t >= hit2.t {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
hit1.t = hit1.t.max(0.0);
|
||||||
|
|
||||||
|
let ray_length = ray.direction.length();
|
||||||
|
let distance_inside_boundary = (hit2.t - hit1.t) * ray_length;
|
||||||
|
let hit_distance = self.neg_inv_density * rand::random::<f64>().ln();
|
||||||
|
|
||||||
|
if hit_distance > distance_inside_boundary {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let t = hit1.t + hit_distance / ray_length;
|
||||||
|
|
||||||
|
Some(HitRecord {
|
||||||
|
t,
|
||||||
|
p: ray.point_at_parameter(t),
|
||||||
|
material: &self.phase_function,
|
||||||
|
u: 0.0,
|
||||||
|
v: 0.0,
|
||||||
|
|
||||||
|
// Arbitrary
|
||||||
|
front_face: true,
|
||||||
|
normal: Vec3::new(1.0, 0.0, 0.0),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bounding_box(&self, t0: f64, t1: f64) -> Option<Aabb> {
|
||||||
|
self.boundary.bounding_box(t0, t1)
|
||||||
|
}
|
||||||
|
}
|
3
src/hitable/volume/mod.rs
Normal file
3
src/hitable/volume/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
mod constant_medium;
|
||||||
|
|
||||||
|
pub use constant_medium::ConstantMedium;
|
|
@ -66,7 +66,8 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> {
|
||||||
.create_texture_static(PixelFormatEnum::BGR888, width as u32, height as u32)
|
.create_texture_static(PixelFormatEnum::BGR888, width as u32, height as u32)
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
let mut active_demo: &dyn Demo<DemoT = BvhNode<Arc<dyn ParallelHit>>> = &demos::Instances {};
|
let mut active_demo: &dyn Demo<DemoT = BvhNode<Arc<dyn ParallelHit>>> =
|
||||||
|
&demos::CornellSmokeAndFog {};
|
||||||
let mut should_update = true;
|
let mut should_update = true;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -107,6 +108,10 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> {
|
||||||
active_demo = &demos::Instances {};
|
active_demo = &demos::Instances {};
|
||||||
should_update = true;
|
should_update = true;
|
||||||
}
|
}
|
||||||
|
Some(Keycode::Num7) => {
|
||||||
|
active_demo = &demos::CornellSmokeAndFog {};
|
||||||
|
should_update = true;
|
||||||
|
}
|
||||||
None => unreachable!(),
|
None => unreachable!(),
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
|
|
31
src/materials/isotropic.rs
Normal file
31
src/materials/isotropic.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
use rand::prelude::SmallRng;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
hitable::HitRecord,
|
||||||
|
materials::random_point_in_unit_sphere,
|
||||||
|
types::{Ray, Vec3},
|
||||||
|
Material, Texture,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Isotropic<T> {
|
||||||
|
texture: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Texture> Isotropic<T> {
|
||||||
|
pub fn new(texture: T) -> Self {
|
||||||
|
Self { texture }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Texture + Send + Sync> Material for Isotropic<T> {
|
||||||
|
fn scatter(&self, ray: &Ray, hit_rec: &HitRecord, rng: &mut SmallRng) -> (Vec3, Option<Ray>) {
|
||||||
|
(
|
||||||
|
self.texture.value(hit_rec.u, hit_rec.v, hit_rec.p),
|
||||||
|
Some(Ray::new(
|
||||||
|
hit_rec.p,
|
||||||
|
random_point_in_unit_sphere(rng),
|
||||||
|
ray.time(),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,12 @@
|
||||||
mod dielectric;
|
mod dielectric;
|
||||||
mod diffuse_light;
|
mod diffuse_light;
|
||||||
|
mod isotropic;
|
||||||
mod lambertian;
|
mod lambertian;
|
||||||
mod metal;
|
mod metal;
|
||||||
|
|
||||||
pub use dielectric::Dielectric;
|
pub use dielectric::Dielectric;
|
||||||
pub use diffuse_light::DiffuseLight;
|
pub use diffuse_light::DiffuseLight;
|
||||||
|
pub use isotropic::Isotropic;
|
||||||
pub use lambertian::Lambertian;
|
pub use lambertian::Lambertian;
|
||||||
pub use metal::Metal;
|
pub use metal::Metal;
|
||||||
use rand::{prelude::SmallRng, Rng};
|
use rand::{prelude::SmallRng, Rng};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user