Added volumes
This commit is contained in:
parent
30b972ce5c
commit
8501bb3a7a
89
src/constant_medium.rs
Normal file
89
src/constant_medium.rs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use crate::{Aabb, Color, Material, Ray, Vec3};
|
||||||
|
use crate::hittable::{HitRecord, Hittable};
|
||||||
|
use crate::isotropic::Isotropic;
|
||||||
|
use crate::material::Scatterable;
|
||||||
|
use crate::texture::Texture;
|
||||||
|
|
||||||
|
/*
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct HitRecord<'material> {
|
||||||
|
pub point: Point3,
|
||||||
|
pub normal: Vec3,
|
||||||
|
pub t: f64,
|
||||||
|
pub u: f64,
|
||||||
|
pub v: f64,
|
||||||
|
pub front_face: bool,
|
||||||
|
pub material: &'material Arc<Material>
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub struct ConstantMedium<H: Hittable> {
|
||||||
|
boundary: H,
|
||||||
|
phase_function: Arc<Material>,
|
||||||
|
neg_inv_density: f64
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H: Hittable,> ConstantMedium<H> {
|
||||||
|
pub fn new(boundary: H, phase_function: Arc<Material>, density: f64) -> Self {
|
||||||
|
Self {
|
||||||
|
boundary,
|
||||||
|
phase_function,
|
||||||
|
neg_inv_density: -1.0 / density
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn textured(boundary: H, texture: Arc<dyn Texture>, density: f64) -> Self {
|
||||||
|
Self {
|
||||||
|
boundary,
|
||||||
|
phase_function: Arc::new(Material::Isotropic(Isotropic::from(texture))),
|
||||||
|
neg_inv_density: -1.0 / density
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn colored(boundary: H, color: Color, density: f64) -> Self {
|
||||||
|
Self {
|
||||||
|
boundary,
|
||||||
|
phase_function: Arc::new(Material::Isotropic(Isotropic::from(color))),
|
||||||
|
neg_inv_density: -1.0 / density
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H: Hittable>Hittable for ConstantMedium<H>{
|
||||||
|
fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
|
||||||
|
let rec1 = self.boundary.hit(ray, f64::NEG_INFINITY, f64::INFINITY);
|
||||||
|
if rec1.is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut rec1 = rec1.unwrap();
|
||||||
|
|
||||||
|
let rec2 = self.boundary.hit(ray, rec1.t+0.0001, f64::INFINITY);
|
||||||
|
if rec2.is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut rec2 = rec2.unwrap();
|
||||||
|
if rec1.t < t_min { rec1.t = t_min; }
|
||||||
|
if rec2.t > t_max { rec2.t = t_max; }
|
||||||
|
if rec1.t > rec2.t { return None; }
|
||||||
|
if rec1.t < t_min { rec1.t = 0.0; }
|
||||||
|
|
||||||
|
let ray_length = ray.direction().length();
|
||||||
|
let distance_inside_boundary = (rec2.t - rec1.t) * ray_length;
|
||||||
|
let hit_distance = self.neg_inv_density * rand::random::<f64>().ln();
|
||||||
|
|
||||||
|
if hit_distance > distance_inside_boundary { return None; }
|
||||||
|
let t = rec1.t + hit_distance / ray_length;
|
||||||
|
Some(HitRecord {
|
||||||
|
point: ray.at(t),
|
||||||
|
normal: Vec3::new(1.0, 0.0, 0.0), // arbitrary
|
||||||
|
t,
|
||||||
|
u: 0.0,
|
||||||
|
v: 0.0,
|
||||||
|
front_face: true, // also arbitrary
|
||||||
|
material: &self.phase_function
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bounding_box(&self, time0: f64, time1: f64) -> Option<Aabb> {
|
||||||
|
self.boundary.bounding_box(time0, time1)
|
||||||
|
}
|
||||||
|
}
|
33
src/isotropic.rs
Normal file
33
src/isotropic.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use crate::hittable::HitRecord;
|
||||||
|
use crate::{Color, Ray, Vec3};
|
||||||
|
use crate::texture::{SolidColor, Texture};
|
||||||
|
|
||||||
|
pub struct Isotropic {
|
||||||
|
pub albedo: Arc<dyn Texture>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Isotropic {
|
||||||
|
pub fn scatter(&self, ray: &Ray, hit_record: &HitRecord) -> Option<(Option<Ray>, Color)> {
|
||||||
|
Some((
|
||||||
|
Some(
|
||||||
|
Ray::new(
|
||||||
|
hit_record.point,
|
||||||
|
Vec3::random_in_unit_sphere(),
|
||||||
|
ray.time())),
|
||||||
|
self.albedo.value(hit_record.u, hit_record.v, &hit_record.point)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Color> for Isotropic {
|
||||||
|
fn from(albedo: Color) -> Self {
|
||||||
|
let texture = SolidColor::from(albedo);
|
||||||
|
Isotropic { albedo: Arc::new(texture) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<Arc<dyn Texture>> for Isotropic {
|
||||||
|
fn from(albedo: Arc<dyn Texture>) -> Self {
|
||||||
|
Isotropic { albedo }
|
||||||
|
}
|
||||||
|
}
|
136
src/main.rs
136
src/main.rs
@ -11,6 +11,7 @@ use rand::distributions::{Distribution, Uniform};
|
|||||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
use crate::material::{Dielectric, DiffuseLight, Lambertian, Material, Metal};
|
use crate::material::{Dielectric, DiffuseLight, Lambertian, Material, Metal};
|
||||||
use crate::aabb::Aabb;
|
use crate::aabb::Aabb;
|
||||||
|
use crate::constant_medium::ConstantMedium;
|
||||||
use crate::cuboid::Cuboid;
|
use crate::cuboid::Cuboid;
|
||||||
use crate::image_texture::ImageTexture;
|
use crate::image_texture::ImageTexture;
|
||||||
use crate::noise::NoiseTexture;
|
use crate::noise::NoiseTexture;
|
||||||
@ -36,11 +37,13 @@ mod rect;
|
|||||||
mod cuboid;
|
mod cuboid;
|
||||||
mod translate;
|
mod translate;
|
||||||
mod rotate_y;
|
mod rotate_y;
|
||||||
|
mod constant_medium;
|
||||||
|
mod isotropic;
|
||||||
|
|
||||||
// Image
|
// Image
|
||||||
const DEFAULT_ASPECT_RATIO: f64 = 3.0 / 2.0;
|
const DEFAULT_ASPECT_RATIO: f64 = 3.0 / 2.0;
|
||||||
const IMAGE_WIDTH: usize = 400;
|
const IMAGE_WIDTH: usize = 600;
|
||||||
const SAMPLES_PER_PIXEL: i32 = 100;
|
const SAMPLES_PER_PIXEL: i32 = 200;
|
||||||
const MAX_DEPTH: i32 = 50;
|
const MAX_DEPTH: i32 = 50;
|
||||||
|
|
||||||
struct Scene {
|
struct Scene {
|
||||||
@ -167,6 +170,132 @@ fn cornell_box() -> Scene {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cornell_box_smoke() -> Scene {
|
||||||
|
let mut world:HittableList = Vec::new();
|
||||||
|
let red = Material::Lambertian(
|
||||||
|
Lambertian::from(Color::new(0.65, 0.05, 0.05)));
|
||||||
|
let white = Arc::new(Material::Lambertian(
|
||||||
|
Lambertian::from(Color::new(0.73, 0.73, 0.73))));
|
||||||
|
let green = Material::Lambertian(
|
||||||
|
Lambertian::from(Color::new(0.12, 0.45, 0.15)));
|
||||||
|
let light = Material::DiffuseLight(
|
||||||
|
DiffuseLight::from(Color::new(7.0, 7.0, 7.0)));
|
||||||
|
|
||||||
|
// Walls
|
||||||
|
world.push(Arc::new(Rect2D::new(
|
||||||
|
Plane::YZ,
|
||||||
|
0.0,
|
||||||
|
555.0,
|
||||||
|
0.0,
|
||||||
|
555.0,
|
||||||
|
555.0,
|
||||||
|
Arc::new(green)
|
||||||
|
)));
|
||||||
|
world.push(Arc::new(Rect2D::new(
|
||||||
|
Plane::YZ,
|
||||||
|
0.0,
|
||||||
|
555.0,
|
||||||
|
0.0,
|
||||||
|
555.0,
|
||||||
|
0.0,
|
||||||
|
Arc::new(red)
|
||||||
|
)));
|
||||||
|
world.push(Arc::new(Rect2D::new(
|
||||||
|
Plane::XZ,
|
||||||
|
113.0,
|
||||||
|
443.0,
|
||||||
|
127.0,
|
||||||
|
432.0,
|
||||||
|
554.0,
|
||||||
|
Arc::new(light)
|
||||||
|
)));
|
||||||
|
world.push(Arc::new(Rect2D::new(
|
||||||
|
Plane::XZ,
|
||||||
|
0.0,
|
||||||
|
555.0,
|
||||||
|
0.0,
|
||||||
|
555.0,
|
||||||
|
0.0,
|
||||||
|
white.clone()
|
||||||
|
)));
|
||||||
|
world.push(Arc::new(Rect2D::new(
|
||||||
|
Plane::XZ,
|
||||||
|
0.0,
|
||||||
|
555.0,
|
||||||
|
0.0,
|
||||||
|
555.0,
|
||||||
|
555.0,
|
||||||
|
white.clone()
|
||||||
|
)));
|
||||||
|
world.push(Arc::new(Rect2D::new(
|
||||||
|
Plane::XY,
|
||||||
|
0.0,
|
||||||
|
555.0,
|
||||||
|
0.0,
|
||||||
|
555.0,
|
||||||
|
555.0,
|
||||||
|
white.clone()
|
||||||
|
)));
|
||||||
|
|
||||||
|
// Boxes
|
||||||
|
|
||||||
|
let rotated1 = RotateY::new(
|
||||||
|
Cuboid::new(
|
||||||
|
Point3::new(0.0, 0.0, 0.0),
|
||||||
|
Point3::new(165.0, 330.0, 165.0),
|
||||||
|
white.clone()
|
||||||
|
),
|
||||||
|
15.0
|
||||||
|
);
|
||||||
|
let box1 = Translate::new(
|
||||||
|
rotated1,
|
||||||
|
Vec3::new(265.0, 0.0, 295.0)
|
||||||
|
);
|
||||||
|
let medium1 = ConstantMedium::colored(
|
||||||
|
box1,
|
||||||
|
Color::new(0.0, 0.0, 0.0),
|
||||||
|
0.01);
|
||||||
|
world.push(Arc::new(medium1));
|
||||||
|
let rotated2 = RotateY::new(
|
||||||
|
Cuboid::new(
|
||||||
|
Point3::new(0.0, 0.0, 0.0),
|
||||||
|
Point3::new(165.0, 165.0, 165.0),
|
||||||
|
white.clone()
|
||||||
|
),
|
||||||
|
-18.0
|
||||||
|
);
|
||||||
|
let box2 = Translate::new(
|
||||||
|
rotated2,
|
||||||
|
Vec3::new(130.0,0.0,65.0)
|
||||||
|
);
|
||||||
|
let medium2 = ConstantMedium::colored(
|
||||||
|
box2,
|
||||||
|
Color::new(1.0, 1.0, 1.0),
|
||||||
|
0.01);
|
||||||
|
world.push(Arc::new(medium2));
|
||||||
|
|
||||||
|
let look_from = Point3::new(278.0, 278.0, -800.0);
|
||||||
|
let look_at = Point3::new(278.0, 278.0, 0.0);
|
||||||
|
let focus_dist = 2.0;
|
||||||
|
|
||||||
|
let cam = Camera::new(
|
||||||
|
look_from,
|
||||||
|
look_at,
|
||||||
|
Vec3::new(0.0, 1.0, 0.0),
|
||||||
|
1.0,
|
||||||
|
40.0,
|
||||||
|
0.0,
|
||||||
|
focus_dist,
|
||||||
|
0.0,
|
||||||
|
1.0);
|
||||||
|
|
||||||
|
Scene {
|
||||||
|
world,
|
||||||
|
cam,
|
||||||
|
background: Color::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn simple_light() -> Scene {
|
fn simple_light() -> Scene {
|
||||||
let mut world:HittableList = Vec::new();
|
let mut world:HittableList = Vec::new();
|
||||||
|
|
||||||
@ -476,7 +605,7 @@ fn random_scene() -> Scene {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// World
|
// World
|
||||||
let scene: u8 = 5;
|
let scene: u8 = 6;
|
||||||
let scene_setup = match scene {
|
let scene_setup = match scene {
|
||||||
0 => two_spheres(),
|
0 => two_spheres(),
|
||||||
1 => two_perlin_spheres(),
|
1 => two_perlin_spheres(),
|
||||||
@ -484,6 +613,7 @@ fn main() {
|
|||||||
3 => sun(),
|
3 => sun(),
|
||||||
4 => simple_light(),
|
4 => simple_light(),
|
||||||
5 => cornell_box(),
|
5 => cornell_box(),
|
||||||
|
6 => cornell_box_smoke(),
|
||||||
_ => random_scene(),
|
_ => random_scene(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ use std::sync::Arc;
|
|||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use crate::hittable::HitRecord;
|
use crate::hittable::HitRecord;
|
||||||
use crate::{Color, Point3, Ray, Vec3};
|
use crate::{Color, Point3, Ray, Vec3};
|
||||||
|
use crate::isotropic::Isotropic;
|
||||||
use crate::texture::{SolidColor, Texture};
|
use crate::texture::{SolidColor, Texture};
|
||||||
|
|
||||||
pub trait Scatterable {
|
pub trait Scatterable {
|
||||||
@ -13,7 +14,8 @@ pub enum Material {
|
|||||||
Lambertian(Lambertian),
|
Lambertian(Lambertian),
|
||||||
Metal(Metal),
|
Metal(Metal),
|
||||||
Dielectric(Dielectric),
|
Dielectric(Dielectric),
|
||||||
DiffuseLight(DiffuseLight)
|
DiffuseLight(DiffuseLight),
|
||||||
|
Isotropic(Isotropic)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Material {
|
impl Default for Material {
|
||||||
@ -28,7 +30,8 @@ impl Scatterable for Material {
|
|||||||
Material::Lambertian(l) => l.scatter(ray, hit_record),
|
Material::Lambertian(l) => l.scatter(ray, hit_record),
|
||||||
Material::Metal(m) => m.scatter(ray, hit_record),
|
Material::Metal(m) => m.scatter(ray, hit_record),
|
||||||
Material::Dielectric(d) => d.scatter(ray, hit_record),
|
Material::Dielectric(d) => d.scatter(ray, hit_record),
|
||||||
Material::DiffuseLight(l) => l.scatter(ray, hit_record)
|
Material::DiffuseLight(l) => l.scatter(ray, hit_record),
|
||||||
|
Material::Isotropic(i) => i.scatter(ray, hit_record)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn emitted(&self, u: f64, v: f64, point: &Point3) -> Color {
|
fn emitted(&self, u: f64, v: f64, point: &Point3) -> Color {
|
||||||
|
Loading…
Reference in New Issue
Block a user