Skip to content

Commit

Permalink
fog!
Browse files Browse the repository at this point in the history
  • Loading branch information
ChristopherBiscardi committed Sep 2, 2023
1 parent 1c3ea7a commit 882db14
Show file tree
Hide file tree
Showing 5 changed files with 248 additions and 2 deletions.
127 changes: 127 additions & 0 deletions examples/cornell-box-fog-smoke.rs
@@ -0,0 +1,127 @@
use glam::DVec3;
use raytracer::{
camera::Camera,
material::Material,
shapes::{
constant_medium::ConstantMedium, quad::Quad,
quad_box::QuadBox, Shapes,
},
textures::Texture,
};
use std::{io, path::Path};

fn main() -> io::Result<()> {
let mut world = vec![];

// Materials
let red = Material::Lambertian {
albedo: DVec3::new(0.65, 0.05, 0.05).into(),
};
let white = Material::Lambertian {
albedo: DVec3::new(0.73, 0.73, 0.73).into(),
};
let green = Material::Lambertian {
albedo: DVec3::new(0.12, 0.45, 0.15).into(),
};
let light = Material::DiffuseLight(
DVec3::new(7., 7., 7.).into(),
);

world.push(Shapes::Quad(Quad::new(
DVec3::new(555., 0., 0.),
DVec3::new(0., 555., 0.),
DVec3::new(0., 0., 555.),
green,
)));
world.push(Shapes::Quad(Quad::new(
DVec3::new(0., 0., 0.),
DVec3::new(0., 555., 0.),
DVec3::new(0., 0., 555.),
red,
)));
world.push(Shapes::Quad(Quad::new(
DVec3::new(113., 554., 127.),
DVec3::new(330., 0., 0.),
DVec3::new(0., 0., 305.),
light,
)));
world.push(Shapes::Quad(Quad::new(
DVec3::new(0., 555., 0.),
DVec3::new(555., 0., 0.),
DVec3::new(0., 0., 555.),
white.clone(),
)));
world.push(Shapes::Quad(Quad::new(
DVec3::new(0., 0., 0.),
DVec3::new(555., 0., 0.),
DVec3::new(0., 0., 555.),
white.clone(),
)));
world.push(Shapes::Quad(Quad::new(
DVec3::new(0., 0., 555.),
DVec3::new(555., 0., 0.),
DVec3::new(0., 555., 0.),
white.clone(),
)));

let box1 = Shapes::Translate {
offset: DVec3::new(265., 0., 295.),
object: Box::new(Shapes::new_rotate_y(
15.,
Shapes::QuadBox(QuadBox::new(
DVec3::new(0., 0., 0.),
DVec3::new(165., 330., 165.),
white.clone(),
)),
)),
};
let box2 = Shapes::Translate {
offset: DVec3::new(130., 0., 65.),
object: Box::new(Shapes::new_rotate_y(
-18.,
Shapes::QuadBox(QuadBox::new(
DVec3::new(0., 0., 0.),
DVec3::new(165., 165., 165.),
white,
)),
)),
};

world.push(Shapes::ConstantMedium(
ConstantMedium::new(
box1,
0.01,
DVec3::new(0., 0., 0.).into(),
),
));
world.push(Shapes::ConstantMedium(
ConstantMedium::new(
box2,
0.01,
DVec3::new(1., 1., 1.).into(),
),
));

let camera = Camera::init()
.image_width(800)
.aspect_ratio(1.)
.look_from(DVec3::new(278., 278., -800.))
.look_at(DVec3::new(278., 278., 0.))
.vup(DVec3::Y)
.focus_dist(10.0)
.defocus_angle(0.0)
.samples_per_pixel(500)
.max_depth(50)
.vfov(40.)
.background(DVec3::ZERO)
.build();

let filename = Path::new(file!())
.file_name()
.and_then(|s| s.to_str())
.unwrap()
.trim_end_matches(".rs");
camera.render_to_disk(filename, world)?;

Ok(())
}
2 changes: 1 addition & 1 deletion src/hittable.rs
Expand Up @@ -14,7 +14,7 @@ pub trait Hittable {
pub struct HitRecord {
pub point: DVec3,
pub normal: DVec3,
t: f64,
pub t: f64,
pub front_face: bool,
pub material: Material,
pub u: f64,
Expand Down
19 changes: 18 additions & 1 deletion src/material.rs
Expand Up @@ -18,6 +18,7 @@ pub enum Material {
Metal { albedo: DVec3, fuzz: f64 },
Dielectric { index_of_refraction: f64 },
DiffuseLight(Texture),
Isotropic { albedo: Texture },
}
pub struct Scattered {
pub attenuation: DVec3,
Expand Down Expand Up @@ -133,7 +134,23 @@ impl Material {
},
})
}
Material::DiffuseLight(texture) => None,
Material::DiffuseLight(_) => None,
Material::Isotropic { albedo } => {
let scattered = Ray {
origin: hit_record.point,
direction: random_unit_vector(),
time: r_in.time,
};
let attenuation = albedo.color(
hit_record.u,
hit_record.v,
hit_record.point,
);
Some(Scattered {
attenuation,
scattered,
})
}
}
}
pub fn emitted(
Expand Down
5 changes: 5 additions & 0 deletions src/shapes.rs
Expand Up @@ -2,6 +2,7 @@ use glam::DVec3;

use crate::{hittable::Hittable, ray::Ray};

pub mod constant_medium;
pub mod quad;
pub mod quad_box;
pub mod sphere;
Expand All @@ -24,6 +25,7 @@ pub enum Shapes {
cos_theta: f64,
object: Box<Shapes>,
},
ConstantMedium(constant_medium::ConstantMedium),
// RoundedBox(rounded_box::RoundedBox),
// Box(a_box::Box),
// Cylinder(cylinder::Cylinder),
Expand Down Expand Up @@ -128,6 +130,9 @@ impl Hittable for Shapes {

Some(hit_record)
}
Shapes::ConstantMedium(object) => {
object.hit(ray, interval)
}
}
}
}
97 changes: 97 additions & 0 deletions src/shapes/constant_medium.rs
@@ -0,0 +1,97 @@
use crate::{
hittable::{HitRecord, Hittable},
material::Material,
ray::Ray,
textures::Texture,
};
use glam::DVec3;
use rand::prelude::*;
use std::{f64::consts::PI, ops::Range};

use super::Shapes;

pub struct ConstantMedium {
boundary: Box<Shapes>,
neg_inv_density: f64,
phase_function: Material,
}

impl ConstantMedium {
pub fn new(
boundary: Shapes,
density: f64,
texture: Texture,
) -> Self {
Self {
boundary: Box::new(boundary),
neg_inv_density: -density.recip(),
phase_function: Material::Isotropic {
albedo: texture,
},
}
}
}

impl Hittable for ConstantMedium {
fn hit(
&self,
ray: &Ray,
interval: Range<f64>,
) -> Option<HitRecord> {
let mut rng = rand::thread_rng();

let Some(mut rec1) = self
.boundary
.hit(ray, f64::NEG_INFINITY..f64::INFINITY)
else {
return None;
};
let Some(mut rec2) = self
.boundary
.hit(ray, (rec1.t + 0.0001)..f64::INFINITY)
else {
return None;
};

if rec1.t < interval.start {
rec1.t = interval.start;
}
if rec2.t > interval.end {
rec2.t = interval.end;
}

if rec1.t >= rec2.t {
return None;
}

if rec1.t < 0. {
rec1.t = 0.;
}

let ray_length = ray.direction.length();
let distance_inside_boundary =
(rec2.t - rec1.t) * ray_length;
let hit_distance =
self.neg_inv_density * rng.gen::<f64>().log10();

if hit_distance > distance_inside_boundary {
return None;
}

let t = rec1.t + hit_distance / ray_length;
let point = ray.at(t);

let rec = HitRecord {
point,
normal: DVec3::new(1., 0., 0.), // arbitrary
t,
front_face: true, // also arbitrary
material: self.phase_function.clone(),
// Arbitrary u/v?
u: 0.,
v: 0.,
};

Some(rec)
}
}

0 comments on commit 882db14

Please sign in to comment.