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 cornell_smoke_and_fog;
|
||||
mod image_texture;
|
||||
mod instances;
|
||||
mod perlin_noise_ball;
|
||||
|
@ -20,6 +21,7 @@ mod simple_light;
|
|||
mod two_spheres;
|
||||
|
||||
pub use checkered_motion_blur::CheckeredMotionBlur;
|
||||
pub use cornell_smoke_and_fog::CornellSmokeAndFog;
|
||||
pub use image_texture::ImageTextureDemo;
|
||||
pub use instances::Instances;
|
||||
pub use perlin_noise_ball::PerlinNoiseBall;
|
||||
|
|
|
@ -3,6 +3,7 @@ pub mod hitable_list;
|
|||
mod rotate;
|
||||
pub mod shapes;
|
||||
mod translate;
|
||||
pub mod volume;
|
||||
|
||||
pub use bvh::*;
|
||||
pub use translate::*;
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::marker::PhantomData;
|
|||
use crate::{
|
||||
hitable::{HitRecord, Hitable},
|
||||
types::{Ray, Vec3},
|
||||
Aabb, Dimension, X, Y, Z,
|
||||
Aabb, Dimension,
|
||||
};
|
||||
|
||||
pub struct Rotate<D1, D2, D3, T: Hitable> {
|
||||
|
@ -28,7 +28,7 @@ where
|
|||
let cos_theta = radians.cos();
|
||||
|
||||
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) {
|
||||
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)
|
||||
.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;
|
||||
|
||||
loop {
|
||||
|
@ -107,6 +108,10 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> {
|
|||
active_demo = &demos::Instances {};
|
||||
should_update = true;
|
||||
}
|
||||
Some(Keycode::Num7) => {
|
||||
active_demo = &demos::CornellSmokeAndFog {};
|
||||
should_update = true;
|
||||
}
|
||||
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 diffuse_light;
|
||||
mod isotropic;
|
||||
mod lambertian;
|
||||
mod metal;
|
||||
|
||||
pub use dielectric::Dielectric;
|
||||
pub use diffuse_light::DiffuseLight;
|
||||
pub use isotropic::Isotropic;
|
||||
pub use lambertian::Lambertian;
|
||||
pub use metal::Metal;
|
||||
use rand::{prelude::SmallRng, Rng};
|
||||
|
|
Loading…
Reference in New Issue
Block a user