aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/camera.rs23
-rw-r--r--src/display/image.rs6
-rw-r--r--src/display/pixelflut.rs29
-rw-r--r--src/hittable/bvh_node.rs89
-rw-r--r--src/hittable/constant_medium.rs20
-rw-r--r--src/hittable/hittable_box.rs75
-rw-r--r--src/hittable/instance/moving.rs29
-rw-r--r--src/hittable/instance/rotate_x.rs56
-rw-r--r--src/hittable/instance/rotate_y.rs54
-rw-r--r--src/hittable/instance/rotate_z.rs54
-rw-r--r--src/hittable/instance/translate.rs12
-rw-r--r--src/hittable/mod.rs4
-rw-r--r--src/hittable/model.rs118
-rw-r--r--src/hittable/sphere.rs22
-rw-r--r--src/hittable/triangle.rs15
-rw-r--r--src/hittable/xy_rect.rs31
-rw-r--r--src/hittable/xz_rect.rs31
-rw-r--r--src/hittable/yz_rect.rs31
-rw-r--r--src/main.rs106
-rw-r--r--src/material/dielectric.rs33
-rw-r--r--src/material/diffuse_light.rs6
-rw-r--r--src/material/isotropic.rs33
-rw-r--r--src/material/lambertian.rs24
-rw-r--r--src/material/metal.rs18
-rw-r--r--src/material/mod.rs18
-rw-r--r--src/ray.rs14
-rw-r--r--src/scenes.rs986
-rw-r--r--src/texture/checker_texture.rs2
-rw-r--r--src/texture/image_texture.rs8
-rw-r--r--src/texture/noise_texture.rs9
-rw-r--r--src/texture/perlin.rs19
-rw-r--r--src/texture/solid_color.rs4
-rw-r--r--src/vec3.rs8
33 files changed, 1604 insertions, 383 deletions
diff --git a/src/camera.rs b/src/camera.rs
index 55bf387..52c2011 100644
--- a/src/camera.rs
+++ b/src/camera.rs
@@ -1,6 +1,6 @@
use crate::ray::Ray;
-use crate::vec3::{Point3, Vec3};
use crate::util::degrees_to_radians;
+use crate::vec3::{Point3, Vec3};
pub struct Camera {
origin: Point3,
@@ -16,7 +16,17 @@ pub struct Camera {
}
impl Camera {
- pub fn new(lookfrom: Point3, lookat: Point3, vup: Vec3, vfov: f64, aspect_ratio: f64, aperture: f64, focus_dist: f64, time_start: f64, time_end: f64) -> Camera {
+ pub fn new(
+ lookfrom: Point3,
+ lookat: Point3,
+ vup: Vec3,
+ vfov: f64,
+ aspect_ratio: f64,
+ aperture: f64,
+ focus_dist: f64,
+ time_start: f64,
+ time_end: f64,
+ ) -> Camera {
let theta = degrees_to_radians(vfov);
let h = (theta / 2.0).tan();
let viewport_height = 2.0 * h;
@@ -30,10 +40,7 @@ impl Camera {
let horizontal = focus_dist * viewport_width * &u;
let vertical = focus_dist * viewport_height * &v;
Camera {
- lower_left_corner: &origin
- - &horizontal / 2.0
- - &vertical / 2.0
- - focus_dist * &w,
+ lower_left_corner: &origin - &horizontal / 2.0 - &vertical / 2.0 - focus_dist * &w,
origin,
horizontal,
vertical,
@@ -51,7 +58,9 @@ impl Camera {
let offset = &self.u * rd.x + &self.v * rd.y;
Ray {
origin: &self.origin + &offset,
- direction: &self.lower_left_corner + s * &self.horizontal + t * &self.vertical - &self.origin - &offset,
+ direction: &self.lower_left_corner + s * &self.horizontal + t * &self.vertical
+ - &self.origin
+ - &offset,
time: self.time_start + (self.time_end - self.time_start) * rand::random::<f64>(),
}
}
diff --git a/src/display/image.rs b/src/display/image.rs
index 77d8c83..4b25cb2 100644
--- a/src/display/image.rs
+++ b/src/display/image.rs
@@ -1,7 +1,7 @@
use std::io::Write;
-use crate::vec3::Color;
use crate::display::{Display, Pixel};
+use crate::vec3::Color;
pub struct Image {
width: usize,
@@ -39,7 +39,9 @@ impl Display for Image {
}
fn maybe_write(&self, output: &mut impl Write) {
- output.write_fmt(format_args!("P3\n{} {}\n255\n", self.width, self.height)).unwrap();
+ output
+ .write_fmt(format_args!("P3\n{} {}\n255\n", self.width, self.height))
+ .unwrap();
for y in (0..self.height).rev() {
for x in 0..self.width {
let pixel = self.data.get((y * self.width) + x).unwrap();
diff --git a/src/display/pixelflut.rs b/src/display/pixelflut.rs
index 3a62f8d..9b71c8e 100644
--- a/src/display/pixelflut.rs
+++ b/src/display/pixelflut.rs
@@ -1,8 +1,8 @@
use std::io::Write;
-use std::net::{TcpStream};
+use std::net::TcpStream;
+use crate::display::{Display, Pixel};
use crate::vec3::Color;
-use crate::display::{Display, Pixel};
pub struct Pixelflut {
socket: TcpStream,
@@ -54,15 +54,22 @@ impl Display for Pixelflut {
for x in 0..self.width {
let pixel = self.data.get((y * self.width) + x).unwrap();
let scale = 1.0 / pixel.sample_count as f64;
- let mut r = (pixel.color.x * scale).sqrt();
- let mut g = (pixel.color.y * scale).sqrt();
- let mut b = (pixel.color.z * scale).sqrt();
- self.socket.write(format!("PX {} {} {:02x}{:02x}{:02x}\n",
- self.x + x,
- self.y + self.height - y,
- (256.0 * r.clamp(0.0, 0.999)) as u32,
- (256.0 * g.clamp(0.0, 0.999)) as u32,
- (256.0 * b.clamp(0.0, 0.999)) as u32).as_bytes());
+ let r = (pixel.color.x * scale).sqrt();
+ let g = (pixel.color.y * scale).sqrt();
+ let b = (pixel.color.z * scale).sqrt();
+ self.socket
+ .write(
+ format!(
+ "PX {} {} {:02x}{:02x}{:02x}\n",
+ self.x + x,
+ self.y + self.height - y,
+ (256.0 * r.clamp(0.0, 0.999)) as u32,
+ (256.0 * g.clamp(0.0, 0.999)) as u32,
+ (256.0 * b.clamp(0.0, 0.999)) as u32
+ )
+ .as_bytes(),
+ )
+ .unwrap();
}
}
}
diff --git a/src/hittable/bvh_node.rs b/src/hittable/bvh_node.rs
index d215bc3..405ab5b 100644
--- a/src/hittable/bvh_node.rs
+++ b/src/hittable/bvh_node.rs
@@ -2,7 +2,7 @@ use std::{cmp, sync::Arc};
use rand::seq::SliceRandom;
-use crate::hittable::{HitRecord, Hittable, AABB, hittable_list::HittableList};
+use crate::hittable::{hittable_list::HittableList, HitRecord, Hittable, AABB};
use crate::ray::Ray;
pub struct BVHNode {
@@ -20,34 +20,72 @@ enum Axis {
impl BVHNode {
pub fn new(hittable_list: &HittableList, time_start: f64, time_end: f64) -> BVHNode {
- Self::from_objects(&hittable_list.objects, 0, hittable_list.objects.len(), time_start, time_end)
+ Self::from_objects(
+ &hittable_list.objects,
+ 0,
+ hittable_list.objects.len(),
+ time_start,
+ time_end,
+ )
}
- fn from_objects(src_objects: &Vec<Arc<dyn Hittable>>, start: usize, end: usize, time_start: f64, time_end: f64) -> BVHNode {
+ fn from_objects(
+ src_objects: &Vec<Arc<dyn Hittable>>,
+ start: usize,
+ end: usize,
+ time_start: f64,
+ time_end: f64,
+ ) -> BVHNode {
let mut objects = src_objects.clone();
let comparator = [
- |a: &Arc<dyn Hittable>, b: &Arc<dyn Hittable>| Self::box_compare(a.clone(), b.clone(), Axis::X),
- |a: &Arc<dyn Hittable>, b: &Arc<dyn Hittable>| Self::box_compare(a.clone(), b.clone(), Axis::Y),
- |a: &Arc<dyn Hittable>, b: &Arc<dyn Hittable>| Self::box_compare(a.clone(), b.clone(), Axis::Z),
- ].choose(&mut rand::thread_rng()).unwrap();
+ |a: &Arc<dyn Hittable>, b: &Arc<dyn Hittable>| {
+ Self::box_compare(a.clone(), b.clone(), Axis::X)
+ },
+ |a: &Arc<dyn Hittable>, b: &Arc<dyn Hittable>| {
+ Self::box_compare(a.clone(), b.clone(), Axis::Y)
+ },
+ |a: &Arc<dyn Hittable>, b: &Arc<dyn Hittable>| {
+ Self::box_compare(a.clone(), b.clone(), Axis::Z)
+ },
+ ]
+ .choose(&mut rand::thread_rng())
+ .unwrap();
let object_span = end - start;
let (left, right) = match object_span {
- 1 => (objects.get(start).unwrap().clone(), objects.get(start).unwrap().clone()),
+ 1 => (
+ objects.get(start).unwrap().clone(),
+ objects.get(start).unwrap().clone(),
+ ),
2 => match comparator(objects.get(start).unwrap(), objects.get(start + 1).unwrap()) {
- cmp::Ordering::Less => (objects.get(start).unwrap().clone(), objects.get(start + 1).unwrap().clone()),
- _ => (objects.get(start + 1).unwrap().clone(), objects.get(start).unwrap().clone()),
- }
+ cmp::Ordering::Less => (
+ objects.get(start).unwrap().clone(),
+ objects.get(start + 1).unwrap().clone(),
+ ),
+ _ => (
+ objects.get(start + 1).unwrap().clone(),
+ objects.get(start).unwrap().clone(),
+ ),
+ },
_ => {
objects[start..end].sort_by(comparator);
let mid = start + object_span / 2;
- (Arc::new(BVHNode::from_objects(&objects, start, mid, time_start, time_end)) as Arc<dyn Hittable>,
- Arc::new(BVHNode::from_objects(&objects, mid, end, time_start, time_end)) as Arc<dyn Hittable>)
-
+ (
+ Arc::new(BVHNode::from_objects(
+ &objects, start, mid, time_start, time_end,
+ )) as Arc<dyn Hittable>,
+ Arc::new(BVHNode::from_objects(
+ &objects, mid, end, time_start, time_end,
+ )) as Arc<dyn Hittable>,
+ )
}
};
- let box_left = left.bounding_box(time_start, time_end).expect("No bounding box in bvh_node constructor!");
- let box_right = right.bounding_box(time_start, time_end).expect("No bounding box in bvh_node constructor!");
+ let box_left = left
+ .bounding_box(time_start, time_end)
+ .expect("No bounding box in bvh_node constructor!");
+ let box_right = right
+ .bounding_box(time_start, time_end)
+ .expect("No bounding box in bvh_node constructor!");
BVHNode {
left,
@@ -56,19 +94,28 @@ impl BVHNode {
}
}
- fn box_compare (a: Arc<dyn Hittable>, b: Arc<dyn Hittable>, axis: Axis) -> cmp::Ordering {
- let box_a = a.bounding_box(0.0, 0.0).expect("No bounding box in bvh_node constructor!");
- let box_b = b.bounding_box(0.0, 0.0).expect("No bounding box in bvh_node constructor!");
+ fn box_compare(a: Arc<dyn Hittable>, b: Arc<dyn Hittable>, axis: Axis) -> cmp::Ordering {
+ let box_a = a
+ .bounding_box(0.0, 0.0)
+ .expect("No bounding box in bvh_node constructor!");
+ let box_b = b
+ .bounding_box(0.0, 0.0)
+ .expect("No bounding box in bvh_node constructor!");
// TODO: total_cmp is unstable :(
- box_a.minimum.get(axis as usize).unwrap().partial_cmp(box_b.minimum.get(axis as usize).unwrap()).unwrap()
+ box_a
+ .minimum
+ .get(axis as usize)
+ .unwrap()
+ .partial_cmp(box_b.minimum.get(axis as usize).unwrap())
+ .unwrap()
}
}
impl Hittable for BVHNode {
fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
if !self.aabb.hit(ray, t_min, t_max) {
- return None
+ return None;
}
let hit_left = self.left.hit(ray, t_min, t_max);
let hit_right_threshold = if let Some(hit_record_left) = &hit_left {
diff --git a/src/hittable/constant_medium.rs b/src/hittable/constant_medium.rs
index 36ac2ff..50bddc6 100644
--- a/src/hittable/constant_medium.rs
+++ b/src/hittable/constant_medium.rs
@@ -1,6 +1,12 @@
use std::sync::Arc;
-use crate::{hittable::{HitRecord, Hittable, AABB}, material::{Isotropic, Material}, ray::Ray, texture::Texture, vec3::{Vec3, Point3}};
+use crate::{
+ hittable::{HitRecord, Hittable, AABB},
+ material::{Isotropic, Material},
+ ray::Ray,
+ texture::Texture,
+ vec3::Vec3,
+};
pub struct ConstantMedium {
boundary: Arc<dyn Hittable>,
@@ -13,7 +19,7 @@ impl ConstantMedium {
Self {
boundary,
phase_function: Arc::new(Isotropic::from_texture(texture)),
- neg_inv_density: -1.0/density,
+ neg_inv_density: -1.0 / density,
}
}
}
@@ -52,10 +58,14 @@ impl Hittable for ConstantMedium {
p: ray.at(t),
t,
material: Some(self.phase_function.clone()),
- normal: Vec3 { x: 1.0, y: 0.0, z: 0.0 }, // arbitrary
+ normal: Vec3 {
+ x: 1.0,
+ y: 0.0,
+ z: 0.0,
+ }, // arbitrary
front_face: true, // arbitrary
- u: 0.0, // arbitrary
- v: 0.0, // arbitrary
+ u: 0.0, // arbitrary
+ v: 0.0, // arbitrary
})
}
diff --git a/src/hittable/hittable_box.rs b/src/hittable/hittable_box.rs
index 7b95cc7..9631635 100644
--- a/src/hittable/hittable_box.rs
+++ b/src/hittable/hittable_box.rs
@@ -1,6 +1,14 @@
use std::sync::Arc;
-use crate::{hittable::{HitRecord, Hittable, AABB, hittable_list::HittableList, xy_rect::XYRect, xz_rect::XZRect, yz_rect::YZRect}, material::Material, ray::Ray, vec3::Point3};
+use crate::{
+ hittable::{
+ hittable_list::HittableList, xy_rect::XYRect, xz_rect::XZRect, yz_rect::YZRect, HitRecord,
+ Hittable, AABB,
+ },
+ material::Material,
+ ray::Ray,
+ vec3::Point3,
+};
pub struct HittableBox {
min: Point3,
@@ -12,20 +20,58 @@ impl HittableBox {
pub fn new(min: Point3, max: Point3, material: Arc<dyn Material>) -> Self {
let mut sides = HittableList::new();
- sides.add(Arc::new(XYRect { material: material.clone(), x0: min.x, x1: max.x, y0: min.y, y1: max.y, k: max.z }));
- sides.add(Arc::new(XYRect { material: material.clone(), x0: min.x, x1: max.x, y0: min.y, y1: max.y, k: min.z }));
+ sides.add(Arc::new(XYRect {
+ material: material.clone(),
+ x0: min.x,
+ x1: max.x,
+ y0: min.y,
+ y1: max.y,
+ k: max.z,
+ }));
+ sides.add(Arc::new(XYRect {
+ material: material.clone(),
+ x0: min.x,
+ x1: max.x,
+ y0: min.y,
+ y1: max.y,
+ k: min.z,
+ }));
- sides.add(Arc::new(XZRect { material: material.clone(), x0: min.x, x1: max.x, z0: min.z, z1: max.z, k: max.y }));
- sides.add(Arc::new(XZRect { material: material.clone(), x0: min.x, x1: max.x, z0: min.z, z1: max.z, k: min.y }));
+ sides.add(Arc::new(XZRect {
+ material: material.clone(),
+ x0: min.x,
+ x1: max.x,
+ z0: min.z,
+ z1: max.z,
+ k: max.y,
+ }));
+ sides.add(Arc::new(XZRect {
+ material: material.clone(),
+ x0: min.x,
+ x1: max.x,
+ z0: min.z,
+ z1: max.z,
+ k: min.y,
+ }));
- sides.add(Arc::new(YZRect { material: material.clone(), y0: min.y, y1: max.y, z0: min.z, z1: max.z, k: max.x }));
- sides.add(Arc::new(YZRect { material: material.clone(), y0: min.y, y1: max.y, z0: min.z, z1: max.z, k: min.x }));
+ sides.add(Arc::new(YZRect {
+ material: material.clone(),
+ y0: min.y,
+ y1: max.y,
+ z0: min.z,
+ z1: max.z,
+ k: max.x,
+ }));
+ sides.add(Arc::new(YZRect {
+ material: material.clone(),
+ y0: min.y,
+ y1: max.y,
+ z0: min.z,
+ z1: max.z,
+ k: min.x,
+ }));
- Self {
- min,
- max,
- sides,
- }
+ Self { min, max, sides }
}
}
@@ -35,6 +81,9 @@ impl Hittable for HittableBox {
}
fn bounding_box(&self, _: f64, _: f64) -> Option<AABB> {
- Some(AABB { minimum: self.min.clone(), maximum: self.max.clone() })
+ Some(AABB {
+ minimum: self.min.clone(),
+ maximum: self.max.clone(),
+ })
}
}
diff --git a/src/hittable/instance/moving.rs b/src/hittable/instance/moving.rs
index 418fdbb..062af86 100644
--- a/src/hittable/instance/moving.rs
+++ b/src/hittable/instance/moving.rs
@@ -1,7 +1,7 @@
use std::sync::Arc;
-use crate::{ray::Ray, vec3::Vec3};
use crate::hittable::{HitRecord, Hittable, AABB};
+use crate::{ray::Ray, vec3::Vec3};
pub struct Moving {
pub hittable: Arc<dyn Hittable>,
@@ -13,13 +13,19 @@ pub struct Moving {
impl Moving {
fn offset_at(&self, time: f64) -> Vec3 {
- &self.offset_start + ((time - self.time_start) / (self.time_end - self.time_start)) * (&self.offset_end - &self.offset_start)
+ &self.offset_start
+ + ((time - self.time_start) / (self.time_end - self.time_start))
+ * (&self.offset_end - &self.offset_start)
}
}
impl Hittable for Moving {
fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
- let moved_ray = Ray { origin: &ray.origin - &self.offset_at(ray.time), direction: ray.direction.clone(), time: ray.time };
+ let moved_ray = Ray {
+ origin: &ray.origin - &self.offset_at(ray.time),
+ direction: ray.direction.clone(),
+ time: ray.time,
+ };
let mut hit_record = self.hittable.hit(&moved_ray, t_min, t_max)?;
hit_record.p += self.offset_at(ray.time).clone();
let normal = hit_record.normal.clone();
@@ -29,12 +35,15 @@ impl Hittable for Moving {
fn bounding_box(&self, time_start: f64, time_end: f64) -> Option<AABB> {
let output_box = self.hittable.bounding_box(time_start, time_end)?;
- Some(AABB {
- minimum: &output_box.minimum + &self.offset_at(time_start),
- maximum: &output_box.maximum + &self.offset_at(time_start),
- }.surrounding_box(&AABB {
- minimum: &output_box.minimum + &self.offset_at(time_end),
- maximum: &output_box.maximum + &self.offset_at(time_end),
- }))
+ Some(
+ AABB {
+ minimum: &output_box.minimum + &self.offset_at(time_start),
+ maximum: &output_box.maximum + &self.offset_at(time_start),
+ }
+ .surrounding_box(&AABB {
+ minimum: &output_box.minimum + &self.offset_at(time_end),
+ maximum: &output_box.maximum + &self.offset_at(time_end),
+ }),
+ )
}
}
diff --git a/src/hittable/instance/rotate_x.rs b/src/hittable/instance/rotate_x.rs
index 4ebc04d..0e09223 100644
--- a/src/hittable/instance/rotate_x.rs
+++ b/src/hittable/instance/rotate_x.rs
@@ -1,6 +1,11 @@
use std::sync::Arc;
-use crate::{hittable::{HitRecord, Hittable, AABB}, ray::Ray, util::degrees_to_radians, vec3::{Point3, Vec3}};
+use crate::{
+ hittable::{HitRecord, Hittable, AABB},
+ ray::Ray,
+ util::degrees_to_radians,
+ vec3::{Point3, Vec3},
+};
pub struct RotateX {
hittable: Arc<dyn Hittable>,
@@ -14,11 +19,25 @@ impl RotateX {
let radians = degrees_to_radians(angle);
let sin_theta = radians.sin();
let cos_theta = radians.cos();
- match hittable.bounding_box(0.0, 1.0) { // TODO: passing in 0.0 and 1.0 for time seems suspicious.
- None => Self { hittable, sin_theta, cos_theta, aabb: None },
+ match hittable.bounding_box(0.0, 1.0) {
+ // TODO: passing in 0.0 and 1.0 for time seems suspicious.
+ None => Self {
+ hittable,
+ sin_theta,
+ cos_theta,
+ aabb: None,
+ },
Some(aabb) => {
- let mut min = Point3 { x: f64::INFINITY, y: f64::INFINITY, z: f64::INFINITY };
- let mut max = Point3 { x: -f64::INFINITY, y: -f64::INFINITY, z: -f64::INFINITY };
+ let mut min = Point3 {
+ x: f64::INFINITY,
+ y: f64::INFINITY,
+ z: f64::INFINITY,
+ };
+ let mut max = Point3 {
+ x: -f64::INFINITY,
+ y: -f64::INFINITY,
+ z: -f64::INFINITY,
+ };
for i in 0..2 {
for j in 0..2 {
for k in 0..2 {
@@ -28,15 +47,24 @@ impl RotateX {
let new_y = cos_theta * y + sin_theta * y;
let new_z = -sin_theta * y + cos_theta * z;
- let tester = Vec3 { y: new_y, x, z: new_z };
+ let tester = Vec3 {
+ y: new_y,
+ x,
+ z: new_z,
+ };
for c in 0..3 {
- *min.get_mut(c).unwrap() = min.get(c).unwrap().min(*tester.get(c).unwrap());
- *max.get_mut(c).unwrap() = max.get(c).unwrap().max(*tester.get(c).unwrap());
+ *min.get_mut(c).unwrap() =
+ min.get(c).unwrap().min(*tester.get(c).unwrap());
+ *max.get_mut(c).unwrap() =
+ max.get(c).unwrap().max(*tester.get(c).unwrap());
}
}
}
}
- let aabb = AABB { minimum: min, maximum: max };
+ let aabb = AABB {
+ minimum: min,
+ maximum: max,
+ };
Self {
hittable,
@@ -56,17 +84,21 @@ impl Hittable for RotateX {
origin.y = self.cos_theta * ray.origin.y - self.sin_theta * ray.origin.z;
origin.z = self.sin_theta * ray.origin.y + self.cos_theta * ray.origin.z;
-
+
direction.y = self.cos_theta * ray.direction.y - self.sin_theta * ray.direction.z;
direction.z = self.sin_theta * ray.direction.y + self.cos_theta * ray.direction.z;
- let rotated_ray = Ray { origin, direction, time: ray.time };
+ let rotated_ray = Ray {
+ origin,
+ direction,
+ time: ray.time,
+ };
let mut hit_record = self.hittable.hit(&rotated_ray, t_min, t_max)?;
let mut p = hit_record.p.clone();
let mut normal = hit_record.normal.clone();
- p.y = self.cos_theta * hit_record.p.y+ self.sin_theta * hit_record.p.z;
+ p.y = self.cos_theta * hit_record.p.y + self.sin_theta * hit_record.p.z;
p.z = -self.sin_theta * hit_record.p.y + self.cos_theta * hit_record.p.z;
normal.y = self.cos_theta * hit_record.normal.y + self.sin_theta * hit_record.normal.z;
diff --git a/src/hittable/instance/rotate_y.rs b/src/hittable/instance/rotate_y.rs
index 8611616..8f34c09 100644
--- a/src/hittable/instance/rotate_y.rs
+++ b/src/hittable/instance/rotate_y.rs
@@ -1,6 +1,11 @@
use std::sync::Arc;
-use crate::{hittable::{HitRecord, Hittable, AABB}, ray::Ray, util::degrees_to_radians, vec3::{Point3, Vec3}};
+use crate::{
+ hittable::{HitRecord, Hittable, AABB},
+ ray::Ray,
+ util::degrees_to_radians,
+ vec3::{Point3, Vec3},
+};
pub struct RotateY {
hittable: Arc<dyn Hittable>,
@@ -14,11 +19,25 @@ impl RotateY {
let radians = degrees_to_radians(angle);
let sin_theta = radians.sin();
let cos_theta = radians.cos();
- match hittable.bounding_box(0.0, 1.0) { // TODO: passing in 0.0 and 1.0 for time seems suspicious.
- None => Self { hittable, sin_theta, cos_theta, aabb: None },
+ match hittable.bounding_box(0.0, 1.0) {
+ // TODO: passing in 0.0 and 1.0 for time seems suspicious.
+ None => Self {
+ hittable,
+ sin_theta,
+ cos_theta,
+ aabb: None,
+ },
Some(aabb) => {
- let mut min = Point3 { x: f64::INFINITY, y: f64::INFINITY, z: f64::INFINITY };
- let mut max = Point3 { x: -f64::INFINITY, y: -f64::INFINITY, z: -f64::INFINITY };
+ let mut min = Point3 {
+ x: f64::INFINITY,
+ y: f64::INFINITY,
+ z: f64::INFINITY,
+ };
+ let mut max = Point3 {
+ x: -f64::INFINITY,
+ y: -f64::INFINITY,
+ z: -f64::INFINITY,
+ };
for i in 0..2 {
for j in 0..2 {
for k in 0..2 {
@@ -28,15 +47,24 @@ impl RotateY {
let new_x = cos_theta * x + sin_theta * z;
let new_z = -sin_theta * x + cos_theta * z;
- let tester = Vec3 { x: new_x, y, z: new_z };
+ let tester = Vec3 {
+ x: new_x,
+ y,
+ z: new_z,
+ };
for c in 0..3 {
- *min.get_mut(c).unwrap() = min.get(c).unwrap().min(*tester.get(c).unwrap());
- *max.get_mut(c).unwrap() = max.get(c).unwrap().max(*tester.get(c).unwrap());
+ *min.get_mut(c).unwrap() =
+ min.get(c).unwrap().min(*tester.get(c).unwrap());
+ *max.get_mut(c).unwrap() =
+ max.get(c).unwrap().max(*tester.get(c).unwrap());
}
}
}
}
- let aabb = AABB { minimum: min, maximum: max };
+ let aabb = AABB {
+ minimum: min,
+ maximum: max,
+ };
Self {
hittable,
@@ -56,11 +84,15 @@ impl Hittable for RotateY {
origin.x = self.cos_theta * ray.origin.x - self.sin_theta * ray.origin.z;
origin.z = self.sin_theta * ray.origin.x + self.cos_theta * ray.origin.z;
-
+
direction.x = self.cos_theta * ray.direction.x - self.sin_theta * ray.direction.z;
direction.z = self.sin_theta * ray.direction.x + self.cos_theta * ray.direction.z;
- let rotated_ray = Ray { origin, direction, time: ray.time };
+ let rotated_ray = Ray {
+ origin,
+ direction,
+ time: ray.time,
+ };
let mut hit_record = self.hittable.hit(&rotated_ray, t_min, t_max)?;
let mut p = hit_record.p.clone();
diff --git a/src/hittable/instance/rotate_z.rs b/src/hittable/instance/rotate_z.rs
index 119baca..38601ce 100644
--- a/src/hittable/instance/rotate_z.rs
+++ b/src/hittable/instance/rotate_z.rs
@@ -1,6 +1,11 @@
use std::sync::Arc;
-use crate::{hittable::{HitRecord, Hittable, AABB}, ray::Ray, util::degrees_to_radians, vec3::{Point3, Vec3}};
+use crate::{
+ hittable::{HitRecord, Hittable, AABB},
+ ray::Ray,
+ util::degrees_to_radians,
+ vec3::{Point3, Vec3},
+};
pub struct RotateZ {
hittable: Arc<dyn Hittable>,
@@ -14,11 +19,25 @@ impl RotateZ {
let radians = degrees_to_radians(angle);
let sin_theta = radians.sin();
let cos_theta = radians.cos();
- match hittable.bounding_box(0.0, 1.0) { // TODO: passing in 0.0 and 1.0 for time seems suspicious.
- None => Self { hittable, sin_theta, cos_theta, aabb: None },
+ match hittable.bounding_box(0.0, 1.0) {
+ // TODO: passing in 0.0 and 1.0 for time seems suspicious.
+ None => Self {
+ hittable,
+ sin_theta,
+ cos_theta,
+ aabb: None,
+ },
Some(aabb) => {
- let mut min = Point3 { x: f64::INFINITY, y: f64::INFINITY, z: f64::INFINITY };
- let mut max = Point3 { x: -f64::INFINITY, y: -f64::INFINITY, z: -f64::INFINITY };
+ let mut min = Point3 {
+ x: f64::INFINITY,
+ y: f64::INFINITY,
+ z: f64::INFINITY,
+ };
+ let mut max = Point3 {
+ x: -f64::INFINITY,
+ y: -f64::INFINITY,
+ z: -f64::INFINITY,
+ };
for i in 0..2 {
for j in 0..2 {
for k in 0..2 {
@@ -28,15 +47,24 @@ impl RotateZ {
let new_x = cos_theta * x + sin_theta * y;
let new_y = -sin_theta * x + cos_theta * y;
- let tester = Vec3 { x: new_x, z, y: new_y };
+ let tester = Vec3 {
+ x: new_x,
+ z,
+ y: new_y,
+ };
for c in 0..3 {
- *min.get_mut(c).unwrap() = min.get(c).unwrap().min(*tester.get(c).unwrap());
- *max.get_mut(c).unwrap() = max.get(c).unwrap().max(*tester.get(c).unwrap());
+ *min.get_mut(c).unwrap() =
+ min.get(c).unwrap().min(*tester.get(c).unwrap());
+ *max.get_mut(c).unwrap() =
+ max.get(c).unwrap().max(*tester.get(c).unwrap());
}
}
}
}
- let aabb = AABB { minimum: min, maximum: max };
+ let aabb = AABB {
+ minimum: min,
+ maximum: max,
+ };
Self {
hittable,
@@ -56,11 +84,15 @@ impl Hittable for RotateZ {
origin.x = self.cos_theta * ray.origin.x - self.sin_theta * ray.origin.y;
origin.y = self.sin_theta * ray.origin.x + self.cos_theta * ray.origin.y;
-
+
direction.x = self.cos_theta * ray.direction.x - self.sin_theta * ray.direction.y;
direction.y = self.sin_theta * ray.direction.x + self.cos_theta * ray.direction.y;
- let rotated_ray = Ray { origin, direction, time: ray.time };
+ let rotated_ray = Ray {
+ origin,
+ direction,
+ time: ray.time,
+ };
let mut hit_record = self.hittable.hit(&rotated_ray, t_min, t_max)?;
let mut p = hit_record.p.clone();
diff --git a/src/hittable/instance/translate.rs b/src/hittable/instance/translate.rs
index a9c8162..8478bd4 100644
--- a/src/hittable/instance/translate.rs
+++ b/src/hittable/instance/translate.rs
@@ -1,6 +1,10 @@
use std::sync::Arc;
-use crate::{hittable::{HitRecord, Hittable, AABB}, ray::Ray, vec3::Vec3};
+use crate::{
+ hittable::{HitRecord, Hittable, AABB},
+ ray::Ray,
+ vec3::Vec3,
+};
pub struct Translate {
pub hittable: Arc<dyn Hittable>,
@@ -9,7 +13,11 @@ pub struct Translate {
impl Hittable for Translate {
fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
- let moved_ray = Ray { origin: &ray.origin - &self.offset, direction: ray.direction.clone(), time: ray.time };
+ let moved_ray = Ray {
+ origin: &ray.origin - &self.offset,
+ direction: ray.direction.clone(),
+ time: ray.time,
+ };
let mut hit_record = self.hittable.hit(&moved_ray, t_min, t_max)?;
hit_record.p += self.offset.clone();
let normal = hit_record.normal.clone();
diff --git a/src/hittable/mod.rs b/src/hittable/mod.rs
index e888c71..b2b06f0 100644
--- a/src/hittable/mod.rs
+++ b/src/hittable/mod.rs
@@ -1,5 +1,5 @@
-pub mod instance;
mod bvh_node;
+pub mod instance;
pub use bvh_node::BVHNode;
mod constant_medium;
pub use constant_medium::ConstantMedium;
@@ -23,9 +23,9 @@ mod aabb;
use std::sync::Arc;
+use crate::material::Material;
use crate::ray::Ray;
use crate::vec3::{Point3, Vec3};
-use crate::material::Material;
use aabb::AABB;
#[derive(Clone)]
diff --git a/src/hittable/model.rs b/src/hittable/model.rs
index 1a652be..6357ab1 100644
--- a/src/hittable/model.rs
+++ b/src/hittable/model.rs
@@ -1,7 +1,12 @@
use std::sync::Arc;
use std::vec::Vec;
-use crate::{hittable::{HitRecord, Hittable, AABB, HittableList, Triangle}, material::Material, ray::Ray, vec3::{Point3, Vec3}};
+use crate::{
+ hittable::{HitRecord, Hittable, HittableList, Triangle, AABB},
+ material::Material,
+ ray::Ray,
+ vec3::Vec3,
+};
pub struct Model {
faces: HittableList,
@@ -10,7 +15,15 @@ pub struct Model {
impl Model {
fn parse_face_triplet(triplet: &str) -> Option<(isize, Option<isize>, Option<isize>)> {
let mut triplet_iter = triplet.split("/");
- Some((triplet_iter.next()?.parse::<isize>().ok()?, triplet_iter.next().and_then(|val| val.parse::<isize>().ok()) , triplet_iter.next().and_then(|val| val.parse::<isize>().ok())))
+ Some((
+ triplet_iter.next()?.parse::<isize>().ok()?,
+ triplet_iter
+ .next()
+ .and_then(|val| val.parse::<isize>().ok()),
+ triplet_iter
+ .next()
+ .and_then(|val| val.parse::<isize>().ok()),
+ ))
}
pub fn from_obj(obj_data: &str, material: Arc<dyn Material>) -> Self {
let mut geometric_vertices: Vec<Vec3> = Vec::new();
@@ -34,95 +47,85 @@ impl Model {
None => {
eprintln!("Malformed {} entry in OBJ: Missing x!", operator);
continue;
- },
- Some(val) => {
- match val.parse::<f64>() {
- Err(_) => {
- eprintln!("Malformed {} entry in OBJ: Malformed f64 x!", operator);
- continue;
- },
- Ok(val) => val,
- }
}
+ Some(val) => match val.parse::<f64>() {
+ Err(_) => {
+ eprintln!("Malformed {} entry in OBJ: Malformed f64 x!", operator);
+ continue;
+ }
+ Ok(val) => val,
+ },
};
let y = match entry_iter.next() {
None => {
eprintln!("Malformed {} entry in OBJ: Missing y!", operator);
continue;
- },
- Some(val) => {
- match val.parse::<f64>() {
- Err(_) => {
- eprintln!("Malformed {} entry in OBJ: Malformed f64 y!", operator);
- continue;
- },
- Ok(val) => val,
- }
}
+ Some(val) => match val.parse::<f64>() {
+ Err(_) => {
+ eprintln!("Malformed {} entry in OBJ: Malformed f64 y!", operator);
+ continue;
+ }
+ Ok(val) => val,
+ },
};
let z = match entry_iter.next() {
None => {
eprintln!("Malformed {} entry in OBJ: Missing z!", operator);
continue;
- },
- Some(val) => {
- match val.parse::<f64>() {
- Err(_) => {
- eprintln!("Malformed {} entry in OBJ: Malformed f64 z!", operator);
- continue;
- },
- Ok(val) => val,
- }
}
+ Some(val) => match val.parse::<f64>() {
+ Err(_) => {
+ eprintln!("Malformed {} entry in OBJ: Malformed f64 z!", operator);
+ continue;
+ }
+ Ok(val) => val,
+ },
};
// who cares about w
match operator {
- "v" => geometric_vertices.push(Vec3 {x, y, z}),
- "vn" => vertex_normals.push(Vec3 {x, y, z}),
+ "v" => geometric_vertices.push(Vec3 { x, y, z }),
+ "vn" => vertex_normals.push(Vec3 { x, y, z }),
_ => panic!(),
}
- },
+ }
"vt" => {
let u = match entry_iter.next() {
None => {
eprintln!("Malformed vt entry in OBJ: Missing u!");
continue;
- },
- Some(val) => {
- match val.parse::<f64>() {
- Err(_) => {
- eprintln!("Malformed vt entry in OBJ: Malformed f64 u!");
- continue;
- },
- Ok(val) => val,
- }
}
+ Some(val) => match val.parse::<f64>() {
+ Err(_) => {
+ eprintln!("Malformed vt entry in OBJ: Malformed f64 u!");
+ continue;
+ }
+ Ok(val) => val,
+ },
};
let v = match entry_iter.next() {
None => {
eprintln!("Malformed vt entry in OBJ: Missing v!");
continue;
- },
- Some(val) => {
- match val.parse::<f64>() {
- Err(_) => {
- eprintln!("Malformed v entry in OBJ: Malformed f64 v!");
- continue;
- },
- Ok(val) => val,
- }
}
+ Some(val) => match val.parse::<f64>() {
+ Err(_) => {
+ eprintln!("Malformed v entry in OBJ: Malformed f64 v!");
+ continue;
+ }
+ Ok(val) => val,
+ },
};
// who cares about w
texture_vertices.push((u, v));
- },
+ }
"f" => {
- let mut triplets : Vec<(isize, Option<isize>, Option<isize>)> = Vec::new();
+ let mut triplets: Vec<(isize, Option<isize>, Option<isize>)> = Vec::new();
for triplet in entry_iter {
match Self::parse_face_triplet(triplet) {
None => {
eprintln!("Encountered malformed triplet in f operator!");
- },
+ }
Some(val) => {
triplets.push(val);
}
@@ -163,7 +166,7 @@ impl Model {
if let Some(vn2) = triplets.get(2).unwrap().2 {
if vn0 != vn1 || vn1 != vn2 {
eprintln!("Unsupported geometry in OBJ file: Multiple normals for face!");
- continue
+ continue;
}
let mut vn0 = vn0;
if vn0 < 0 {
@@ -171,16 +174,17 @@ impl Model {
} else {
vn0 = vn0 - 1;
}
- triangle.custom_normal = Some(vertex_normals.get(vn0 as usize).unwrap().unit_vector());
+ triangle.custom_normal =
+ Some(vertex_normals.get(vn0 as usize).unwrap().unit_vector());
}
}
}
faces.push(Arc::new(triangle));
- },
+ }
_ => {
eprintln!("Ignoring unknown operator {} in OBJ!", operator);
continue;
- },
+ }
}
}
Self {
diff --git a/src/hittable/sphere.rs b/src/hittable/sphere.rs
index 783b788..f276366 100644
--- a/src/hittable/sphere.rs
+++ b/src/hittable/sphere.rs
@@ -1,9 +1,13 @@
-use std::sync::Arc;
use std::f64::consts;
+use std::sync::Arc;
-use crate::{hittable::{HitRecord, Hittable, AABB}, material::Material, vec3::Vec3};
use crate::ray::Ray;
use crate::vec3::Point3;
+use crate::{
+ hittable::{HitRecord, Hittable, AABB},
+ material::Material,
+ vec3::Vec3,
+};
pub struct Sphere {
pub center: Point3,
@@ -54,8 +58,18 @@ impl Hittable for Sphere {
fn bounding_box(&self, _: f64, _: f64) -> Option<AABB> {
Some(AABB {
- minimum: &self.center - Vec3 { x: self.radius, y: self.radius, z: self.radius },
- maximum: &self.center + Vec3 { x: self.radius, y: self.radius, z: self.radius },
+ minimum: &self.center
+ - Vec3 {
+ x: self.radius,
+ y: self.radius,
+ z: self.radius,
+ },
+ maximum: &self.center
+ + Vec3 {
+ x: self.radius,
+ y: self.radius,
+ z: self.radius,
+ },
})
}
}
diff --git a/src/hittable/triangle.rs b/src/hittable/triangle.rs
index 0fe5fc4..82b9e18 100644
--- a/src/hittable/triangle.rs
+++ b/src/hittable/triangle.rs
@@ -1,6 +1,11 @@
use std::sync::Arc;
-use crate::{hittable::{HitRecord, Hittable, AABB}, material::Material, ray::Ray, vec3::{Point3, Vec3}};
+use crate::{
+ hittable::{HitRecord, Hittable, AABB},
+ material::Material,
+ ray::Ray,
+ vec3::{Point3, Vec3},
+};
pub struct Triangle {
pub v0: Point3,
@@ -12,7 +17,9 @@ pub struct Triangle {
impl Triangle {
fn has_vertex_at_infinity(&self) -> bool {
- self.v0.has_infinite_member() || self.v1.has_infinite_member() || self.v2.has_infinite_member()
+ self.v0.has_infinite_member()
+ || self.v1.has_infinite_member()
+ || self.v2.has_infinite_member()
}
}
@@ -71,9 +78,9 @@ impl Hittable for Triangle {
maximum: Point3 {
x: self.v0.x.max(self.v1.x).max(self.v2.x) + 0.0001,
y: self.v0.y.max(self.v1.y).max(self.v2.y) + 0.0001,
- z: self.v0.z.max(self.v1.z).max(self.v2.z) + 0.0001,
+ z: self.v0.z.max(self.v1.z).max(self.v2.z) + 0.0001,
},
- })
+ }),
}
}
}
diff --git a/src/hittable/xy_rect.rs b/src/hittable/xy_rect.rs
index 8421bae..2d7dbeb 100644
--- a/src/hittable/xy_rect.rs
+++ b/src/hittable/xy_rect.rs
@@ -1,6 +1,11 @@
use std::sync::Arc;
-use crate::{hittable::{HitRecord, Hittable, AABB}, material::Material, ray::Ray, vec3::{Point3, Vec3}};
+use crate::{
+ hittable::{HitRecord, Hittable, AABB},
+ material::Material,
+ ray::Ray,
+ vec3::{Point3, Vec3},
+};
pub struct XYRect {
pub material: Arc<dyn Material>,
@@ -13,7 +18,10 @@ pub struct XYRect {
impl XYRect {
fn has_infinite_bounds(&self) -> bool {
- self.x0.is_infinite() || self.x1.is_infinite() || self.y0.is_infinite() || self.y1.is_infinite()
+ self.x0.is_infinite()
+ || self.x1.is_infinite()
+ || self.y0.is_infinite()
+ || self.y1.is_infinite()
}
}
@@ -32,7 +40,11 @@ impl Hittable for XYRect {
hit_record.u = (x - self.x0) / (self.x1 - self.x0);
hit_record.v = (y - self.y0) / (self.y1 - self.y0);
hit_record.t = t;
- let outward_normal = Vec3 { x: 0.0, y: 0.0, z: 1.0 };
+ let outward_normal = Vec3 {
+ x: 0.0,
+ y: 0.0,
+ z: 1.0,
+ };
hit_record.set_face_normal(ray, &outward_normal);
hit_record.material = Some(self.material.clone());
hit_record.p = ray.at(t);
@@ -42,7 +54,18 @@ impl Hittable for XYRect {
fn bounding_box(&self, _: f64, _: f64) -> Option<AABB> {
match self.has_infinite_bounds() {
true => None,
- false => Some(AABB { minimum: Point3 { x: self.x0, y: self.y0, z: self.k - 0.0001 }, maximum: Point3 { x: self.x1, y: self.y1, z: self.k + 0.0001 } }),
+ false => Some(AABB {
+ minimum: Point3 {
+ x: self.x0,
+ y: self.y0,
+ z: self.k - 0.0001,
+ },
+ maximum: Point3 {
+ x: self.x1,
+ y: self.y1,
+ z: self.k + 0.0001,
+ },
+ }),
}
}
}
diff --git a/src/hittable/xz_rect.rs b/src/hittable/xz_rect.rs
index 4761f36..c990de5 100644
--- a/src/hittable/xz_rect.rs
+++ b/src/hittable/xz_rect.rs
@@ -1,6 +1,11 @@
use std::sync::Arc;
-use crate::{hittable::{HitRecord, Hittable, AABB}, material::Material, ray::Ray, vec3::{Point3, Vec3}};
+use crate::{
+ hittable::{HitRecord, Hittable, AABB},
+ material::Material,
+ ray::Ray,
+ vec3::{Point3, Vec3},
+};
pub struct XZRect {
pub material: Arc<dyn Material>,
@@ -13,7 +18,10 @@ pub struct XZRect {
impl XZRect {
fn has_infinite_bounds(&self) -> bool {
- self.x0.is_infinite() || self.x1.is_infinite() || self.z0.is_infinite() || self.z1.is_infinite()
+ self.x0.is_infinite()
+ || self.x1.is_infinite()
+ || self.z0.is_infinite()
+ || self.z1.is_infinite()
}
}
@@ -32,7 +40,11 @@ impl Hittable for XZRect {
hit_record.u = (x - self.x0) / (self.x1 - self.x0);
hit_record.v = (z - self.z0) / (self.z1 - self.z0);
hit_record.t = t;
- let outward_normal = Vec3 { x: 0.0, y: 1.0, z: 0.0 };
+ let outward_normal = Vec3 {
+ x: 0.0,
+ y: 1.0,
+ z: 0.0,
+ };
hit_record.set_face_normal(ray, &outward_normal);
hit_record.material = Some(self.material.clone());
hit_record.p = ray.at(t);
@@ -42,7 +54,18 @@ impl Hittable for XZRect {
fn bounding_box(&self, _: f64, _: f64) -> Option<AABB> {
match self.has_infinite_bounds() {
true => None,
- false => Some(AABB { minimum: Point3 { x: self.x0, y: self.k - 0.0001, z: self.z0 }, maximum: Point3 { x: self.x1, y: self.k + 0.0001, z: self.z1 } }),
+ false => Some(AABB {
+ minimum: Point3 {
+ x: self.x0,
+ y: self.k - 0.0001,
+ z: self.z0,
+ },
+ maximum: Point3 {
+ x: self.x1,
+ y: self.k + 0.0001,
+ z: self.z1,
+ },
+ }),
}
}
}
diff --git a/src/hittable/yz_rect.rs b/src/hittable/yz_rect.rs
index dd90bdb..db068dd 100644
--- a/src/hittable/yz_rect.rs
+++ b/src/hittable/yz_rect.rs
@@ -1,6 +1,11 @@
use std::sync::Arc;
-use crate::{hittable::{HitRecord, Hittable, AABB}, material::Material, ray::Ray, vec3::{Point3, Vec3}};
+use crate::{
+ hittable::{HitRecord, Hittable, AABB},
+ material::Material,
+ ray::Ray,
+ vec3::{Point3, Vec3},
+};
pub struct YZRect {
pub material: Arc<dyn Material>,
@@ -13,7 +18,10 @@ pub struct YZRect {
impl YZRect {
fn has_infinite_bounds(&self) -> bool {
- self.y0.is_infinite() || self.y1.is_infinite() || self.z0.is_infinite() || self.z1.is_infinite()
+ self.y0.is_infinite()
+ || self.y1.is_infinite()
+ || self.z0.is_infinite()
+ || self.z1.is_infinite()
}
}
@@ -32,7 +40,11 @@ impl Hittable for YZRect {
hit_record.u = (y - self.y0) / (self.y1 - self.y0);
hit_record.v = (z - self.z0) / (self.z1 - self.z0);
hit_record.t = t;
- let outward_normal = Vec3 { x: 1.0, y: 0.0, z: 0.0 };
+ let outward_normal = Vec3 {
+ x: 1.0,
+ y: 0.0,
+ z: 0.0,
+ };
hit_record.set_face_normal(ray, &outward_normal);
hit_record.material = Some(self.material.clone());
hit_record.p = ray.at(t);
@@ -42,7 +54,18 @@ impl Hittable for YZRect {
fn bounding_box(&self, _: f64, _: f64) -> Option<AABB> {
match self.has_infinite_bounds() {
true => None,
- false => Some(AABB { minimum: Point3 { x: self.k - 0.0001, y: self.y0, z: self.z0 }, maximum: Point3 { x: self.k + 0.0001, y: self.y1, z: self.z1 } }),
+ false => Some(AABB {
+ minimum: Point3 {
+ x: self.k - 0.0001,
+ y: self.y0,
+ z: self.z0,
+ },
+ maximum: Point3 {
+ x: self.k + 0.0001,
+ y: self.y1,
+ z: self.z1,
+ },
+ }),
}
}
}
diff --git a/src/main.rs b/src/main.rs
index 0fe2df9..1e889e6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,21 +1,24 @@
mod camera;
+mod display;
mod hittable;
mod material;
mod ray;
+mod scenes;
+mod texture;
mod util;
mod vec3;
-mod display;
-mod texture;
-mod scenes;
-use std::{sync::{Arc, mpsc}, thread};
+use std::{
+ sync::{mpsc, Arc},
+ thread,
+};
use camera::Camera;
-use hittable::Hittable;
use display::{Display, Image, Pixelflut};
+use hittable::Hittable;
use ray::Ray;
-use vec3::{Vec3, Color, Point3};
use scenes::get_scene;
+use vec3::{Color, Vec3};
struct PixelUpdate {
color: Color,
@@ -33,7 +36,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(mut rec) => {
+ Some(rec) => {
let mut scattered = Ray::new();
let mut attenuation = Color::new();
if let Some(material) = &rec.material {
@@ -44,13 +47,26 @@ fn ray_color(ray: &Ray, background: &Color, world: &dyn Hittable, depth: u32) ->
emitted + attenuation * ray_color(&scattered, background, world, depth - 1)
}
} else {
- Color { x: 0.0, y: 0.0, z: 0.0 }
+ Color {
+ x: 0.0,
+ y: 0.0,
+ z: 0.0,
+ }
}
- },
+ }
}
}
-fn render(image_width: u32, image_height: u32, samples_per_pixel: u32, max_depth: u32, world: Arc<dyn Hittable>, background: Color, camera: Arc<Camera>, tx: mpsc::Sender<PixelUpdate>) {
+fn render(
+ image_width: u32,
+ image_height: u32,
+ samples_per_pixel: u32,
+ max_depth: u32,
+ world: Arc<dyn Hittable>,
+ background: Color,
+ camera: Arc<Camera>,
+ tx: mpsc::Sender<PixelUpdate>,
+) {
for j in (0..image_height).rev() {
for i in 0..image_width {
for _ in 0..samples_per_pixel {
@@ -58,7 +74,12 @@ fn render(image_width: u32, image_height: u32, samples_per_pixel: u32, max_depth
let v = ((j as f64) + rand::random::<f64>()) / ((image_height - 1) as f64);
let ray = camera.get_ray(u, v);
- tx.send(PixelUpdate { color: ray_color(&ray, &background, world.as_ref(), max_depth), x: i as usize, y: j as usize}).unwrap();
+ tx.send(PixelUpdate {
+ color: ray_color(&ray, &background, world.as_ref(), max_depth),
+ x: i as usize,
+ y: j as usize,
+ })
+ .unwrap();
}
}
}
@@ -76,27 +97,67 @@ fn main() {
const TIME_START: f64 = 0.0;
const TIME_END: f64 = 1.0;
// World
- let (world, lookfrom, lookat, vfov, aperture, background) = get_scene(std::env::args().nth(1).unwrap_or("0".to_string()).trim().parse().unwrap_or(0));
+ let (world, lookfrom, lookat, vfov, aperture, background) = get_scene(
+ std::env::args()
+ .nth(1)
+ .unwrap_or("0".to_string())
+ .trim()
+ .parse()
+ .unwrap_or(0),
+ );
// Camera
- let vup = Vec3 { x: 0.0, y: 1.0, z: 0.0 };
+ let vup = Vec3 {
+ x: 0.0,
+ y: 1.0,
+ z: 0.0,
+ };
let dist_to_focus = 10.0;
- let cam = Arc::new(Camera::new(lookfrom, lookat, vup, vfov, ASPECT_RATIO, aperture, dist_to_focus, TIME_START, TIME_END));
+ let cam = Arc::new(Camera::new(
+ lookfrom,
+ lookat,
+ vup,
+ vfov,
+ ASPECT_RATIO,
+ aperture,
+ dist_to_focus,
+ TIME_START,
+ TIME_END,
+ ));
// Render
// let mut final_image = Image::new(IMAGE_WIDTH as usize, IMAGE_HEIGHT as usize);
- let mut final_image = Pixelflut::new("192.168.0.38:1337", 0, 0, IMAGE_WIDTH as usize, IMAGE_HEIGHT as usize);
+ let mut final_image = Pixelflut::new(
+ "192.168.0.38:1337",
+ 0,
+ 0,
+ IMAGE_WIDTH as usize,
+ IMAGE_HEIGHT as usize,
+ );
let (tx, rx) = mpsc::channel::<PixelUpdate>();
for _ in 0..THREAD_COUNT {
let sender = tx.clone();
let world_ref = world.clone();
let camera_ref = cam.clone();
let background_clone = background.clone();
- thread::spawn( || {
- render(IMAGE_WIDTH, IMAGE_HEIGHT, SAMPLES_PER_PIXEL / THREAD_COUNT, MAX_DEPTH, world_ref, background_clone, camera_ref, sender);
+ thread::spawn(|| {
+ render(
+ IMAGE_WIDTH,
+ IMAGE_HEIGHT,
+ SAMPLES_PER_PIXEL / THREAD_COUNT,
+ MAX_DEPTH,
+ world_ref,
+ background_clone,
+ camera_ref,
+ sender,
+ );
});
}
- let expected_updates: u64 = (SAMPLES_PER_PIXEL / THREAD_COUNT) as u64 * THREAD_COUNT as u64 * IMAGE_HEIGHT as u64 * IMAGE_WIDTH as u64;
- let print_frequency: u64 = (SAMPLES_PER_PIXEL / THREAD_COUNT) as u64 * THREAD_COUNT as u64 * IMAGE_WIDTH as u64;
+ let expected_updates: u64 = (SAMPLES_PER_PIXEL / THREAD_COUNT) as u64
+ * THREAD_COUNT as u64
+ * IMAGE_HEIGHT as u64
+ * IMAGE_WIDTH as u64;
+ let print_frequency: u64 =
+ (SAMPLES_PER_PIXEL / THREAD_COUNT) as u64 * THREAD_COUNT as u64 * IMAGE_WIDTH as u64;
let print_frequency = print_frequency * 3;
let mut update_count: u64 = 0;
loop {
@@ -105,11 +166,14 @@ fn main() {
final_image.add_sample(update.x, update.y, update.color);
if update_count % print_frequency == 0 {
final_image.maybe_update();
- eprint!("\rCurrent completion: {:.2}%", (update_count as f64 / expected_updates as f64) * 100.0)
+ eprint!(
+ "\rCurrent completion: {:.2}%",
+ (update_count as f64 / expected_updates as f64) * 100.0
+ )
}
} else {
if Arc::strong_count(&world) == 1 {
- break
+ break;
}
}
}
diff --git a/src/material/dielectric.rs b/src/material/dielectric.rs
index 1a49f73..af6f9b0 100644
--- a/src/material/dielectric.rs
+++ b/src/material/dielectric.rs
@@ -1,9 +1,9 @@
use std::ops::Neg;
use super::Material;
-use crate::{hittable::HitRecord, vec3::Vec3};
-use crate::vec3::Color;
use crate::ray::Ray;
+use crate::vec3::Color;
+use crate::{hittable::HitRecord, vec3::Vec3};
pub struct DielectricAttenuation {
pub albedo: Color,
@@ -25,7 +25,13 @@ impl Dielectric {
}
impl Material for Dielectric {
- fn scatter(&self, ray_in: &Ray, hit_record: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool {
+ fn scatter(
+ &self,
+ ray_in: &Ray,
+ hit_record: &HitRecord,
+ attenuation: &mut Color,
+ scattered: &mut Ray,
+ ) -> bool {
if let Some(props) = &self.attenuation {
let outward_normal = if hit_record.front_face {
hit_record.normal.clone()
@@ -40,9 +46,17 @@ impl Material for Dielectric {
*attenuation = props.albedo.clone();
}
} else {
- *attenuation = Color { x: 1.0, y: 1.0, z: 1.0 };
+ *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 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);
let sin_theta = (1.0 - cos_theta * cos_theta).sqrt();
@@ -50,13 +64,18 @@ impl Material for Dielectric {
let cannot_refract = refraction_ratio * sin_theta > 1.0;
let direction: Vec3;
- if cannot_refract || Self::reflectance(cos_theta, refraction_ratio) > rand::random::<f64>() {
+ if cannot_refract || Self::reflectance(cos_theta, refraction_ratio) > rand::random::<f64>()
+ {
direction = unit_direction.reflect(&hit_record.normal)
} else {
direction = unit_direction.refract(&hit_record.normal, refraction_ratio)
}
- *scattered = Ray { origin: hit_record.p.clone(), direction, time: ray_in.time };
+ *scattered = Ray {
+ origin: hit_record.p.clone(),
+ direction,
+ time: ray_in.time,
+ };
true
}
}
diff --git a/src/material/diffuse_light.rs b/src/material/diffuse_light.rs
index fecbcff..4feca3b 100644
--- a/src/material/diffuse_light.rs
+++ b/src/material/diffuse_light.rs
@@ -1,10 +1,10 @@
use std::sync::Arc;
use super::Material;
-use crate::{hittable::HitRecord, texture::Texture, vec3::Point3};
-use crate::vec3::Color;
-use crate::texture::SolidColor;
use crate::ray::Ray;
+use crate::texture::SolidColor;
+use crate::vec3::Color;
+use crate::{hittable::HitRecord, texture::Texture, vec3::Point3};
pub struct DiffuseLight {
emit: Arc<dyn Texture>,
diff --git a/src/material/isotropic.rs b/src/material/isotropic.rs
index f59fa7d..9949abd 100644
--- a/src/material/isotropic.rs
+++ b/src/material/isotropic.rs
@@ -1,32 +1,39 @@
use std::sync::Arc;
use super::Material;
-use crate::{hittable::HitRecord, texture::Texture, vec3::Vec3};
-use crate::vec3::Color;
-use crate::texture::SolidColor;
use crate::ray::Ray;
+use crate::vec3::Color;
+use crate::{hittable::HitRecord, texture::Texture, vec3::Vec3};
pub struct Isotropic {
albedo: Arc<dyn Texture>,
}
impl Isotropic {
- pub fn from_color(color: Color) -> Self {
- Self {
- albedo: Arc::new(SolidColor::from_color(color)),
- }
- }
+ // pub fn from_color(color: Color) -> Self {
+ // Self {
+ // albedo: Arc::new(SolidColor::from_color(color)),
+ // }
+ // }
pub fn from_texture(texture: Arc<dyn Texture>) -> Self {
- Self {
- albedo: texture,
- }
+ Self { albedo: texture }
}
}
impl Material for Isotropic {
- fn scatter(&self, ray_in: &Ray, hit_record: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool {
- *scattered = Ray { origin: hit_record.p.clone(), direction: Vec3::random_in_unit_sphere(), time: ray_in.time };
+ fn scatter(
+ &self,
+ ray_in: &Ray,
+ hit_record: &HitRecord,
+ attenuation: &mut Color,
+ scattered: &mut Ray,
+ ) -> bool {
+ *scattered = Ray {
+ origin: hit_record.p.clone(),
+ direction: Vec3::random_in_unit_sphere(),
+ time: ray_in.time,
+ };
*attenuation = self.albedo.value(hit_record.u, hit_record.v, &hit_record.p);
true
}
diff --git a/src/material/lambertian.rs b/src/material/lambertian.rs
index 95f698e..fed26f9 100644
--- a/src/material/lambertian.rs
+++ b/src/material/lambertian.rs
@@ -1,10 +1,10 @@
use std::sync::Arc;
use super::Material;
-use crate::{hittable::HitRecord, texture::Texture, vec3::Vec3};
-use crate::vec3::Color;
-use crate::texture::SolidColor;
use crate::ray::Ray;
+use crate::texture::SolidColor;
+use crate::vec3::Color;
+use crate::{hittable::HitRecord, texture::Texture, vec3::Vec3};
pub struct Lambertian {
pub albedo: Arc<dyn Texture>,
@@ -13,13 +13,21 @@ pub struct Lambertian {
impl Lambertian {
pub fn from_color(color: Color) -> Self {
Self {
- albedo: Arc::new(SolidColor { color_value: color.clone() }),
+ albedo: Arc::new(SolidColor {
+ color_value: color.clone(),
+ }),
}
}
}
impl Material for Lambertian {
- fn scatter(&self, ray_in : &Ray, hit_record: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool {
+ fn scatter(
+ &self,
+ ray_in: &Ray,
+ hit_record: &HitRecord,
+ attenuation: &mut Color,
+ scattered: &mut Ray,
+ ) -> bool {
let mut scatter_direction = &hit_record.normal + Vec3::random_unit_vector();
// Catch zero-vector scatter directions that will generate issues later
@@ -27,7 +35,11 @@ impl Material for Lambertian {
scatter_direction = hit_record.normal.clone();
}
- *scattered = Ray { origin: hit_record.p.clone(), direction: scatter_direction, time: ray_in.time };
+ *scattered = Ray {
+ origin: hit_record.p.clone(),
+ direction: scatter_direction,
+ time: ray_in.time,
+ };
*attenuation = self.albedo.value(hit_record.u, hit_record.v, &hit_record.p);
true
}
diff --git a/src/material/metal.rs b/src/material/metal.rs
index 2865a2f..638e5e4 100644
--- a/src/material/metal.rs
+++ b/src/material/metal.rs
@@ -1,7 +1,7 @@
use super::Material;
-use crate::{hittable::HitRecord, vec3::Vec3};
-use crate::vec3::Color;
use crate::ray::Ray;
+use crate::vec3::Color;
+use crate::{hittable::HitRecord, vec3::Vec3};
pub struct Metal {
pub albedo: Color,
@@ -9,9 +9,19 @@ pub struct Metal {
}
impl Material for Metal {
- fn scatter(&self, ray_in: &Ray, hit_record: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool {
+ fn scatter(
+ &self,
+ ray_in: &Ray,
+ hit_record: &HitRecord,
+ attenuation: &mut Color,
+ scattered: &mut Ray,
+ ) -> bool {
let reflected = ray_in.direction.unit_vector().reflect(&hit_record.normal);
- *scattered = Ray { origin: hit_record.p.clone(), direction: reflected + self.fuzz * Vec3::random_in_unit_sphere(), time: ray_in.time };
+ *scattered = Ray {
+ origin: hit_record.p.clone(),
+ direction: reflected + self.fuzz * Vec3::random_in_unit_sphere(),
+ time: ray_in.time,
+ };
*attenuation = self.albedo.clone();
scattered.direction.dot(&hit_record.normal) > 0.0
}
diff --git a/src/material/mod.rs b/src/material/mod.rs
index c292ea1..cded09b 100644
--- a/src/material/mod.rs
+++ b/src/material/mod.rs
@@ -10,13 +10,23 @@ pub use diffuse_light::DiffuseLight;
mod isotropic;
pub use isotropic::Isotropic;
-use crate::{hittable::HitRecord, vec3::Point3};
-use crate::vec3::Color;
use crate::ray::Ray;
+use crate::vec3::Color;
+use crate::{hittable::HitRecord, vec3::Point3};
pub trait Material: Send + Sync {
fn emitted(&self, _: f64, _: f64, _: &Point3) -> Color {
- Color { x: 0.0, y: 0.0, z: 0.0 }
+ Color {
+ x: 0.0,
+ y: 0.0,
+ z: 0.0,
+ }
}
- fn scatter(&self, ray_in: &Ray, hit_record: &HitRecord, attenuation: &mut Color, scattered: &mut Ray) -> bool;
+ fn scatter(
+ &self,
+ ray_in: &Ray,
+ hit_record: &HitRecord,
+ attenuation: &mut Color,
+ scattered: &mut Ray,
+ ) -> bool;
}
diff --git a/src/ray.rs b/src/ray.rs
index 0a4fc3c..a3636e6 100644
--- a/src/ray.rs
+++ b/src/ray.rs
@@ -9,9 +9,17 @@ pub struct Ray {
impl Ray {
pub fn new() -> Ray {
Ray {
- origin: Point3 { x: 0.0, y: 0.0, z: 0.0 },
- direction: Vec3 { x: 0.0, y:0.0, z: 0.0},
- time: 0.0
+ origin: Point3 {
+ x: 0.0,
+ y: 0.0,
+ z: 0.0,
+ },
+ direction: Vec3 {
+ x: 0.0,
+ y: 0.0,
+ z: 0.0,
+ },
+ time: 0.0,
}
}
diff --git a/src/scenes.rs b/src/scenes.rs
index 54f6eb3..096055e 100644
--- a/src/scenes.rs
+++ b/src/scenes.rs
@@ -1,23 +1,25 @@
use std::sync::Arc;
-use crate::hittable::{ConstantMedium, Hittable};
-use crate::hittable::HittableBox;
-use crate::hittable::HittableList;
-use crate::material::{Dielectric, DielectricAttenuation, DiffuseLight, Lambertian, Material, Metal};
-use crate::hittable::instance::RotateY;
+use crate::hittable::instance::Moving;
use crate::hittable::instance::RotateX;
+use crate::hittable::instance::RotateY;
use crate::hittable::instance::RotateZ;
-use crate::hittable::Sphere;
use crate::hittable::instance::Translate;
-use crate::vec3::{Point3, Vec3, Color};
use crate::hittable::BVHNode;
-use crate::texture::{CheckerTexture, ImageTexture, NoiseTexture, SolidColor};
+use crate::hittable::HittableBox;
+use crate::hittable::HittableList;
+use crate::hittable::Model;
+use crate::hittable::Sphere;
+use crate::hittable::Triangle;
use crate::hittable::XYRect;
use crate::hittable::XZRect;
use crate::hittable::YZRect;
-use crate::hittable::Triangle;
-use crate::hittable::Model;
-use crate::hittable::instance::Moving;
+use crate::hittable::{ConstantMedium, Hittable};
+use crate::material::{
+ Dielectric, DielectricAttenuation, DiffuseLight, Lambertian, Material, Metal,
+};
+use crate::texture::{CheckerTexture, ImageTexture, NoiseTexture, SolidColor};
+use crate::vec3::{Color, Point3, Vec3};
pub fn get_scene(id: u32) -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) {
match id {
@@ -37,141 +39,647 @@ pub fn get_scene(id: u32) -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color
fn random_scene() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) {
let mut world = HittableList::new();
- let checker = Arc::new(CheckerTexture::from_colors(Color { x: 0.2, y: 0.3, z: 0.1 } , Color { x: 0.9, y: 0.9, z: 0.9 }));
+ let checker = Arc::new(CheckerTexture::from_colors(
+ Color {
+ x: 0.2,
+ y: 0.3,
+ z: 0.1,
+ },
+ Color {
+ x: 0.9,
+ y: 0.9,
+ z: 0.9,
+ },
+ ));
let ground_material = Arc::new(Lambertian { albedo: checker });
- world.add(Arc::new(Sphere{ center: Point3 { x: 0.0, y: -1000.0, z: 0.0 }, radius: 1000.0, material: ground_material }));
+ world.add(Arc::new(Sphere {
+ center: Point3 {
+ x: 0.0,
+ y: -1000.0,
+ z: 0.0,
+ },
+ radius: 1000.0,
+ material: ground_material,
+ }));
for a in -11..11 {
for b in -11..11 {
let choose_mat = rand::random::<f64>();
- let center = Point3 { x: (a as f64) + 0.9 * rand::random::<f64>(), y: 0.2, z: (b as f64) + 0.9 * rand::random::<f64>() };
-
- if (&center - Point3 { x: 4.0, y: 0.3, z: 0.0 }).length() > 0.9 {
+ let center = Point3 {
+ x: (a as f64) + 0.9 * rand::random::<f64>(),
+ y: 0.2,
+ z: (b as f64) + 0.9 * rand::random::<f64>(),
+ };
+
+ if (&center
+ - Point3 {
+ x: 4.0,
+ y: 0.3,
+ z: 0.0,
+ })
+ .length()
+ > 0.9
+ {
let sphere_material: Arc<dyn Material>;
if choose_mat < 0.8 {
- let albedo = Arc::new(SolidColor::from_color(Color::random() * Color::random()));
+ let albedo =
+ Arc::new(SolidColor::from_color(Color::random() * Color::random()));
sphere_material = Arc::new(Lambertian { albedo });
- world.add(Arc::new(Sphere { center, radius: 0.2, material: sphere_material }));
+ world.add(Arc::new(Sphere {
+ center,
+ radius: 0.2,
+ material: sphere_material,
+ }));
} else if choose_mat < 0.95 {
let albedo = Color::random_in_range(0.5, 1.0);
let fuzz = rand::random::<f64>() / 2.0;
sphere_material = Arc::new(Metal { albedo, fuzz });
- world.add(Arc::new(Sphere { center, radius: 0.2, material: sphere_material }));
+ world.add(Arc::new(Sphere {
+ center,
+ radius: 0.2,
+ material: sphere_material,
+ }));
} else {
- 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 }));
+ 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, 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 })) });
- world.add(Arc::new(Sphere { center: Point3 { x: -4.0, y: 1.0, z: 0.0 }, radius: 1.0, material: material2 }));
-
- let material3 = Arc::new(Metal { albedo: Color { x: 0.7, y: 0.6, z: 0.5 }, fuzz: 0.0 });
- world.add(Arc::new(Sphere { center: Point3 { x: 4.0, y: 1.0, z: 0.0 }, radius: 1.0, material: material3 }));
-
- (Arc::new(BVHNode::new(&world, 0.0, 1.0)), Point3 { x: 13.0, y: 2.0, z: 3.0}, Point3::new(), 20.0, 0.1, Color { x: 0.7, y: 0.8, z: 1.0 })
+ 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,
+ })),
+ });
+ world.add(Arc::new(Sphere {
+ center: Point3 {
+ x: -4.0,
+ y: 1.0,
+ z: 0.0,
+ },
+ radius: 1.0,
+ material: material2,
+ }));
+
+ let material3 = Arc::new(Metal {
+ albedo: Color {
+ x: 0.7,
+ y: 0.6,
+ z: 0.5,
+ },
+ fuzz: 0.0,
+ });
+ world.add(Arc::new(Sphere {
+ center: Point3 {
+ x: 4.0,
+ y: 1.0,
+ z: 0.0,
+ },
+ radius: 1.0,
+ material: material3,
+ }));
+
+ (
+ Arc::new(BVHNode::new(&world, 0.0, 1.0)),
+ Point3 {
+ x: 13.0,
+ y: 2.0,
+ z: 3.0,
+ },
+ Point3::new(),
+ 20.0,
+ 0.1,
+ Color {
+ x: 0.7,
+ y: 0.8,
+ z: 1.0,
+ },
+ )
}
fn two_spheres() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) {
let mut objects = HittableList::new();
- let checker = Arc::new(Lambertian { albedo: Arc::new(CheckerTexture::from_colors(Color { x: 0.2, y: 0.3, z: 0.1 } , Color { x: 0.9, y: 0.9, z: 0.9 })) });
- objects.add(Arc::new(Sphere { center: Point3 { x: 0.0, y: -10.0, z: 0.0 }, radius: 10.0, material: checker.clone() }));
- objects.add(Arc::new(Sphere { center: Point3 { x: 0.0, y: 10.0, z: 0.0 }, radius: 10.0, material: checker }));
- (Arc::new(BVHNode::new(&objects, 0.0, 1.0)), Point3 { x: 13.0, y: 2.0, z: 3.0}, Point3::new(), 20.0, 0.0, Color { x: 0.7, y: 0.8, z: 1.0 })
+ let checker = Arc::new(Lambertian {
+ albedo: Arc::new(CheckerTexture::from_colors(
+ Color {
+ x: 0.2,
+ y: 0.3,
+ z: 0.1,
+ },
+ Color {
+ x: 0.9,
+ y: 0.9,
+ z: 0.9,
+ },
+ )),
+ });
+ objects.add(Arc::new(Sphere {
+ center: Point3 {
+ x: 0.0,
+ y: -10.0,
+ z: 0.0,
+ },
+ radius: 10.0,
+ material: checker.clone(),
+ }));
+ objects.add(Arc::new(Sphere {
+ center: Point3 {
+ x: 0.0,
+ y: 10.0,
+ z: 0.0,
+ },
+ radius: 10.0,
+ material: checker,
+ }));
+ (
+ Arc::new(BVHNode::new(&objects, 0.0, 1.0)),
+ Point3 {
+ x: 13.0,
+ y: 2.0,
+ z: 3.0,
+ },
+ Point3::new(),
+ 20.0,
+ 0.0,
+ Color {
+ x: 0.7,
+ y: 0.8,
+ z: 1.0,
+ },
+ )
}
fn two_perlin_spheres() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) {
let mut objects = HittableList::new();
- let pertext = Arc::new(Lambertian { albedo: Arc::new(NoiseTexture::new(4.0)) });
- objects.add(Arc::new(Sphere { center: Point3 { x: 0.0, y: -1000.0, z: 0.0 }, radius: 1000.0, material: pertext.clone() }));
- objects.add(Arc::new(Sphere { center: Point3 { x: 0.0, y: 2.0, z: 0.0 }, radius: 2.0, material: pertext.clone() }));
- (Arc::new(BVHNode::new(&objects, 0.0, 1.0)), Point3 { x: 13.0, y: 2.0, z: 3.0}, Point3::new(), 20.0, 0.0, Color { x: 0.7, y: 0.8, z: 1.0 })
+ let pertext = Arc::new(Lambertian {
+ albedo: Arc::new(NoiseTexture::new(4.0)),
+ });
+ objects.add(Arc::new(Sphere {
+ center: Point3 {
+ x: 0.0,
+ y: -1000.0,
+ z: 0.0,
+ },
+ radius: 1000.0,
+ material: pertext.clone(),
+ }));
+ objects.add(Arc::new(Sphere {
+ center: Point3 {
+ x: 0.0,
+ y: 2.0,
+ z: 0.0,
+ },
+ radius: 2.0,
+ material: pertext.clone(),
+ }));
+ (
+ Arc::new(BVHNode::new(&objects, 0.0, 1.0)),
+ Point3 {
+ x: 13.0,
+ y: 2.0,
+ z: 3.0,
+ },
+ Point3::new(),
+ 20.0,
+ 0.0,
+ Color {
+ x: 0.7,
+ y: 0.8,
+ z: 1.0,
+ },
+ )
}
fn earth() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) {
let mut objects = HittableList::new();
- let earth_texture = Arc::new(ImageTexture::from_bmp_data(&include_bytes!("../res/earthmap.bmp").to_vec()));
- let earth_surface = Arc::new(Lambertian { albedo: earth_texture });
- objects.add(Arc::new(Sphere { center: Point3 { x: 0.0, y: 0.0, z: 0.0 }, radius: 2.0, material: earth_surface }));
- (Arc::new(BVHNode::new(&objects, 0.0, 1.0)), Point3 { x: 13.0, y: 2.0, z: 3.0}, Point3::new(), 20.0, 0.0, Color { x: 0.7, y: 0.8, z: 1.0 })
+ let earth_texture = Arc::new(ImageTexture::from_bmp_data(
+ &include_bytes!("../res/earthmap.bmp").to_vec(),
+ ));
+ let earth_surface = Arc::new(Lambertian {
+ albedo: earth_texture,
+ });
+ objects.add(Arc::new(Sphere {
+ center: Point3 {
+ x: 0.0,
+ y: 0.0,
+ z: 0.0,
+ },
+ radius: 2.0,
+ material: earth_surface,
+ }));
+ (
+ Arc::new(BVHNode::new(&objects, 0.0, 1.0)),
+ Point3 {
+ x: 13.0,
+ y: 2.0,
+ z: 3.0,
+ },
+ Point3::new(),
+ 20.0,
+ 0.0,
+ Color {
+ x: 0.7,
+ y: 0.8,
+ z: 1.0,
+ },
+ )
}
fn simple_light() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) {
let mut objects = HittableList::new();
- let pertext = Arc::new(Lambertian { albedo: Arc::new(NoiseTexture::new(4.0)) });
- objects.add(Arc::new(Sphere { center: Point3 { x: 0.0, y: -1000.0, z: 0.0 }, radius: 1000.0, material: pertext.clone() }));
- objects.add(Arc::new(Sphere { center: Point3 { x: 0.0, y: 2.0, z: 0.0 }, radius: 2.0, material: pertext.clone() }));
- let diff_light = Arc::new(DiffuseLight::from_color(Color { x: 4.0, y: 4.0, z: 4.0 }));
- objects.add(Arc::new(XYRect { material: diff_light, x0: 3.0, x1: 5.0, y0: 1.0, y1: 3.0, k: -2.0 }));
- (Arc::new(BVHNode::new(&objects, 0.0, 1.0)), Point3 { x: 26.0, y: 3.0, z: 6.0}, Point3 { x: 0.0, y: 2.0, z: 0.0}, 20.0, 0.0, Color::new())
+ let pertext = Arc::new(Lambertian {
+ albedo: Arc::new(NoiseTexture::new(4.0)),
+ });
+ objects.add(Arc::new(Sphere {
+ center: Point3 {
+ x: 0.0,
+ y: -1000.0,
+ z: 0.0,
+ },
+ radius: 1000.0,
+ material: pertext.clone(),
+ }));
+ objects.add(Arc::new(Sphere {
+ center: Point3 {
+ x: 0.0,
+ y: 2.0,
+ z: 0.0,
+ },
+ radius: 2.0,
+ material: pertext.clone(),
+ }));
+ let diff_light = Arc::new(DiffuseLight::from_color(Color {
+ x: 4.0,
+ y: 4.0,
+ z: 4.0,
+ }));
+ objects.add(Arc::new(XYRect {
+ material: diff_light,
+ x0: 3.0,
+ x1: 5.0,
+ y0: 1.0,
+ y1: 3.0,
+ k: -2.0,
+ }));
+ (
+ Arc::new(BVHNode::new(&objects, 0.0, 1.0)),
+ Point3 {
+ x: 26.0,
+ y: 3.0,
+ z: 6.0,
+ },
+ Point3 {
+ x: 0.0,
+ y: 2.0,
+ z: 0.0,
+ },
+ 20.0,
+ 0.0,
+ Color::new(),
+ )
}
fn cornell_box() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) {
let mut objects = HittableList::new();
- let red = Arc::new(Lambertian::from_color(Color { x: 0.65, y: 0.05, z: 0.05 }));
- let white = Arc::new(Lambertian::from_color(Color { x: 0.73, y: 0.73, z: 0.73 }));
- let green = Arc::new(Lambertian::from_color(Color { x: 0.12, y: 0.45, z: 0.15 }));
- let light = Arc::new(DiffuseLight::from_color(Color { x: 15.0, y: 15.0, z: 15.0 }));
-
- objects.add(Arc::new(YZRect { material: green, y0: 0.0, y1: 555.0, z0: 0.0, z1: 555.0, k: 555.0 }));
- objects.add(Arc::new(YZRect { material: red, y0: 0.0, y1: 555.0, z0: 0.0, z1: 555.0, k: 0.0 }));
- objects.add(Arc::new(XZRect { material: light, x0: 213.0, x1: 343.0, z0: 227.0, z1: 332.0, k: 554.0 }));
- objects.add(Arc::new(XZRect { material: white.clone(), x0: 0.0, x1: 555.0, z0: 0.0, z1: 555.0, k: 0.0 }));
- objects.add(Arc::new(XZRect { material: white.clone(), x0: 0.0, x1: 555.0, z0: 0.0, z1: 555.0, k: 555.0 }));
- objects.add(Arc::new(XYRect { material: white.clone(), x0: 0.0, x1: 555.0, y0: 0.0, y1: 555.0, k: 555.0 }));
+ let red = Arc::new(Lambertian::from_color(Color {
+ x: 0.65,
+ y: 0.05,
+ z: 0.05,
+ }));
+ let white = Arc::new(Lambertian::from_color(Color {
+ x: 0.73,
+ y: 0.73,
+ z: 0.73,
+ }));
+ let green = Arc::new(Lambertian::from_color(Color {
+ x: 0.12,
+ y: 0.45,
+ z: 0.15,
+ }));
+ let light = Arc::new(DiffuseLight::from_color(Color {
+ x: 15.0,
+ y: 15.0,
+ z: 15.0,
+ }));
+
+ objects.add(Arc::new(YZRect {
+ material: green,
+ y0: 0.0,
+ y1: 555.0,
+ z0: 0.0,
+ z1: 555.0,
+ k: 555.0,
+ }));
+ objects.add(Arc::new(YZRect {
+ material: red,
+ y0: 0.0,
+ y1: 555.0,
+ z0: 0.0,
+ z1: 555.0,
+ k: 0.0,
+ }));
+ objects.add(Arc::new(XZRect {
+ material: light,
+ x0: 213.0,
+ x1: 343.0,
+ z0: 227.0,
+ z1: 332.0,
+ k: 554.0,
+ }));
+ objects.add(Arc::new(XZRect {
+ material: white.clone(),
+ x0: 0.0,
+ x1: 555.0,
+ z0: 0.0,
+ z1: 555.0,
+ k: 0.0,
+ }));
+ objects.add(Arc::new(XZRect {
+ material: white.clone(),
+ x0: 0.0,
+ x1: 555.0,
+ z0: 0.0,
+ z1: 555.0,
+ k: 555.0,
+ }));
+ objects.add(Arc::new(XYRect {
+ material: white.clone(),
+ x0: 0.0,
+ x1: 555.0,
+ y0: 0.0,
+ y1: 555.0,
+ k: 555.0,
+ }));
//objects.add(Arc::new(HittableBox::new(Point3 { x: 130.0, y: 0.0, z: 65.0 }, Point3 { x: 295.0, y: 165.0, z: 230.0 }, white.clone())));
//objects.add(Arc::new(HittableBox::new(Point3 { x: 265.0, y: 0.0, z: 295.0 }, Point3 { x: 430.0, y: 330.0, z: 460.0 }, white.clone())));
- let box_1 = Arc::new(HittableBox::new(Point3 { x: 0.0, y: 0.0, z: 0.0 }, Point3 { x: 165.0, y: 330.0, z: 165.0 }, white.clone()));
+ let box_1 = Arc::new(HittableBox::new(
+ Point3 {
+ x: 0.0,
+ y: 0.0,
+ z: 0.0,
+ },
+ Point3 {
+ x: 165.0,
+ y: 330.0,
+ z: 165.0,
+ },
+ white.clone(),
+ ));
let box_1 = Arc::new(RotateY::new(box_1, 15.0));
- let box_1 = Arc::new(Translate { hittable: box_1, offset: Point3 { x: 265.0, y: 0.0, z: 295.0 } });
+ let box_1 = Arc::new(Translate {
+ hittable: box_1,
+ offset: Point3 {
+ x: 265.0,
+ y: 0.0,
+ z: 295.0,
+ },
+ });
objects.add(box_1);
- let box_2 = Arc::new(HittableBox::new(Point3 { x: 0.0, y: 0.0, z: 0.0 }, Point3 { x: 165.0, y: 165.0, z: 165.0 }, white.clone()));
+ let box_2 = Arc::new(HittableBox::new(
+ Point3 {
+ x: 0.0,
+ y: 0.0,
+ z: 0.0,
+ },
+ Point3 {
+ x: 165.0,
+ y: 165.0,
+ z: 165.0,
+ },
+ white.clone(),
+ ));
let box_2 = Arc::new(RotateY::new(box_2, -18.0));
- let box_2 = Arc::new(Translate { hittable: box_2, offset: Point3 { x: 130.0, y: 0.0, z: 65.0 } });
+ let box_2 = Arc::new(Translate {
+ hittable: box_2,
+ offset: Point3 {
+ x: 130.0,
+ y: 0.0,
+ z: 65.0,
+ },
+ });
objects.add(box_2);
- (Arc::new(BVHNode::new(&objects, 0.0, 1.0)), Point3 { x: 278.0, y: 278.0, z: -800.0}, Point3 { x: 278.0, y: 278.0, z: 0.0}, 40.0, 0.0, Color::new())
+ (
+ Arc::new(BVHNode::new(&objects, 0.0, 1.0)),
+ Point3 {
+ x: 278.0,
+ y: 278.0,
+ z: -800.0,
+ },
+ Point3 {
+ x: 278.0,
+ y: 278.0,
+ z: 0.0,
+ },
+ 40.0,
+ 0.0,
+ Color::new(),
+ )
}
fn cornell_smoke() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) {
let mut objects = HittableList::new();
- let red = Arc::new(Lambertian::from_color(Color { x: 0.65, y: 0.05, z: 0.05 }));
- let white = Arc::new(Lambertian::from_color(Color { x: 0.73, y: 0.73, z: 0.73 }));
- let green = Arc::new(Lambertian::from_color(Color { x: 0.12, y: 0.45, z: 0.15 }));
- let light = Arc::new(DiffuseLight::from_color(Color { x: 7.0, y: 7.0, z: 7.0 }));
-
- objects.add(Arc::new(YZRect { material: green, y0: 0.0, y1: 555.0, z0: 0.0, z1: 555.0, k: 555.0 }));
- objects.add(Arc::new(YZRect { material: red, y0: 0.0, y1: 555.0, z0: 0.0, z1: 555.0, k: 0.0 }));
- objects.add(Arc::new(XZRect { material: light, x0: 113.0, x1: 443.0, z0: 127.0, z1: 432.0, k: 554.0 }));
- objects.add(Arc::new(XZRect { material: white.clone(), x0: 0.0, x1: 555.0, z0: 0.0, z1: 555.0, k: 0.0 }));
- objects.add(Arc::new(XZRect { material: white.clone(), x0: 0.0, x1: 555.0, z0: 0.0, z1: 555.0, k: 555.0 }));
- objects.add(Arc::new(XYRect { material: white.clone(), x0: 0.0, x1: 555.0, y0: 0.0, y1: 555.0, k: 555.0 }));
+ let red = Arc::new(Lambertian::from_color(Color {
+ x: 0.65,
+ y: 0.05,
+ z: 0.05,
+ }));
+ let white = Arc::new(Lambertian::from_color(Color {
+ x: 0.73,
+ y: 0.73,
+ z: 0.73,
+ }));
+ let green = Arc::new(Lambertian::from_color(Color {
+ x: 0.12,
+ y: 0.45,
+ z: 0.15,
+ }));
+ let light = Arc::new(DiffuseLight::from_color(Color {
+ x: 7.0,
+ y: 7.0,
+ z: 7.0,
+ }));
+
+ objects.add(Arc::new(YZRect {
+ material: green,
+ y0: 0.0,
+ y1: 555.0,
+ z0: 0.0,
+ z1: 555.0,
+ k: 555.0,
+ }));
+ objects.add(Arc::new(YZRect {
+ material: red,
+ y0: 0.0,
+ y1: 555.0,
+ z0: 0.0,
+ z1: 555.0,
+ k: 0.0,
+ }));
+ objects.add(Arc::new(XZRect {
+ material: light,
+ x0: 113.0,
+ x1: 443.0,
+ z0: 127.0,
+ z1: 432.0,
+ k: 554.0,
+ }));
+ objects.add(Arc::new(XZRect {
+ material: white.clone(),
+ x0: 0.0,
+ x1: 555.0,
+ z0: 0.0,
+ z1: 555.0,
+ k: 0.0,
+ }));
+ objects.add(Arc::new(XZRect {
+ material: white.clone(),
+ x0: 0.0,
+ x1: 555.0,
+ z0: 0.0,
+ z1: 555.0,
+ k: 555.0,
+ }));
+ objects.add(Arc::new(XYRect {
+ material: white.clone(),
+ x0: 0.0,
+ x1: 555.0,
+ y0: 0.0,
+ y1: 555.0,
+ k: 555.0,
+ }));
//objects.add(Arc::new(HittableBox::new(Point3 { x: 130.0, y: 0.0, z: 65.0 }, Point3 { x: 295.0, y: 165.0, z: 230.0 }, white.clone())));
//objects.add(Arc::new(HittableBox::new(Point3 { x: 265.0, y: 0.0, z: 295.0 }, Point3 { x: 430.0, y: 330.0, z: 460.0 }, white.clone())));
- let box_1 = Arc::new(HittableBox::new(Point3 { x: 0.0, y: 0.0, z: 0.0 }, Point3 { x: 165.0, y: 330.0, z: 165.0 }, white.clone()));
+ let box_1 = Arc::new(HittableBox::new(
+ Point3 {
+ x: 0.0,
+ y: 0.0,
+ z: 0.0,
+ },
+ Point3 {
+ x: 165.0,
+ y: 330.0,
+ z: 165.0,
+ },
+ white.clone(),
+ ));
let box_1 = Arc::new(RotateY::new(box_1, 15.0));
- let box_1 = Arc::new(Translate { hittable: box_1, offset: Point3 { x: 265.0, y: 0.0, z: 295.0 } });
- let box_2 = Arc::new(HittableBox::new(Point3 { x: 0.0, y: 0.0, z: 0.0 }, Point3 { x: 165.0, y: 165.0, z: 165.0 }, white.clone()));
+ let box_1 = Arc::new(Translate {
+ hittable: box_1,
+ offset: Point3 {
+ x: 265.0,
+ y: 0.0,
+ z: 295.0,
+ },
+ });
+ let box_2 = Arc::new(HittableBox::new(
+ Point3 {
+ x: 0.0,
+ y: 0.0,
+ z: 0.0,
+ },
+ Point3 {
+ x: 165.0,
+ y: 165.0,
+ z: 165.0,
+ },
+ white.clone(),
+ ));
let box_2 = Arc::new(RotateY::new(box_2, -18.0));
- let box_2 = Arc::new(Translate { hittable: box_2, offset: Point3 { x: 130.0, y: 0.0, z: 65.0 } });
-
- objects.add(Arc::new(ConstantMedium::new(box_1, 0.01, Arc::new(SolidColor::from_color(Color { x: 0.0, y: 0.0, z: 0.0 })))));
- objects.add(Arc::new(ConstantMedium::new(box_2, 0.01, Arc::new(SolidColor::from_color(Color { x: 1.0, y: 1.0, z: 1.0 })))));
-
- (Arc::new(BVHNode::new(&objects, 0.0, 1.0)), Point3 { x: 278.0, y: 278.0, z: -800.0}, Point3 { x: 278.0, y: 278.0, z: 0.0}, 40.0, 0.0, Color::new())
+ let box_2 = Arc::new(Translate {
+ hittable: box_2,
+ offset: Point3 {
+ x: 130.0,
+ y: 0.0,
+ z: 65.0,
+ },
+ });
+
+ objects.add(Arc::new(ConstantMedium::new(
+ box_1,
+ 0.01,
+ Arc::new(SolidColor::from_color(Color {
+ x: 0.0,
+ y: 0.0,
+ z: 0.0,
+ })),
+ )));
+ objects.add(Arc::new(ConstantMedium::new(
+ box_2,
+ 0.01,
+ Arc::new(SolidColor::from_color(Color {
+ x: 1.0,
+ y: 1.0,
+ z: 1.0,
+ })),
+ )));
+
+ (
+ Arc::new(BVHNode::new(&objects, 0.0, 1.0)),
+ Point3 {
+ x: 278.0,
+ y: 278.0,
+ z: -800.0,
+ },
+ Point3 {
+ x: 278.0,
+ y: 278.0,
+ z: 0.0,
+ },
+ 40.0,
+ 0.0,
+ Color::new(),
+ )
}
fn final_scene() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) {
let mut boxes_1 = HittableList::new();
- let ground = Arc::new(Lambertian::from_color(Color { x: 0.48, y: 0.83, z: 0.53 }));
+ let ground = Arc::new(Lambertian::from_color(Color {
+ x: 0.48,
+ y: 0.83,
+ z: 0.53,
+ }));
const BOXES_PER_SIDE: usize = 20;
for i in 0..BOXES_PER_SIDE {
@@ -183,70 +691,310 @@ fn final_scene() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) {
let x1 = x0 + w;
let y1 = 1.0 + 100.0 * rand::random::<f64>();
let z1 = z0 + w;
- boxes_1.add(Arc::new(HittableBox::new(Point3 { x: x0, y: y0, z: z0 }, Point3 { x: x1, y: y1, z: z1 }, ground.clone())));
+ boxes_1.add(Arc::new(HittableBox::new(
+ Point3 {
+ x: x0,
+ y: y0,
+ z: z0,
+ },
+ Point3 {
+ x: x1,
+ y: y1,
+ z: z1,
+ },
+ ground.clone(),
+ )));
}
}
let mut objects = HittableList::new();
objects.add(Arc::new(BVHNode::new(&boxes_1, 0.0, 1.0)));
- let light = Arc::new(DiffuseLight::from_color(Color { x: 7.0, y: 7.0, z: 7.0 }));
- objects.add(Arc::new(XZRect { material: light.clone(), x0: 123.0, x1: 423.0, z0: 147.0, z1: 412.0, k: 554.0 }));
-
- let center_1 = Point3 { x: 400.0, y: 400.0, z: 200.0 };
- let center_2 = &center_1 + Vec3 { x: 30.0, y: 0.0, z: 0.0 };
-
- 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, 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, attenuation: None }) });
+ let light = Arc::new(DiffuseLight::from_color(Color {
+ x: 7.0,
+ y: 7.0,
+ z: 7.0,
+ }));
+ objects.add(Arc::new(XZRect {
+ material: light.clone(),
+ x0: 123.0,
+ x1: 423.0,
+ z0: 147.0,
+ z1: 412.0,
+ k: 554.0,
+ }));
+
+ let center_1 = Point3 {
+ x: 400.0,
+ y: 400.0,
+ z: 200.0,
+ };
+ let center_2 = &center_1
+ + Vec3 {
+ x: 30.0,
+ y: 0.0,
+ z: 0.0,
+ };
+
+ 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,
+ 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,
+ 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, 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())) });
- objects.add(Arc::new(Sphere { center: Point3 { x: 400.0, y: 200.0, z: 400.0 }, radius: 100.0, material: emat }));
- let pertext = Arc::new(Lambertian { albedo: Arc::new(NoiseTexture::new(0.1)) });
- objects.add(Arc::new(Sphere { center: Point3 { x: 220.0, y: 280.0, z: 300.0 }, radius: 80.0, material: pertext }));
+ 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,
+ 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(),
+ )),
+ });
+ objects.add(Arc::new(Sphere {
+ center: Point3 {
+ x: 400.0,
+ y: 200.0,
+ z: 400.0,
+ },
+ radius: 100.0,
+ material: emat,
+ }));
+ let pertext = Arc::new(Lambertian {
+ albedo: Arc::new(NoiseTexture::new(0.1)),
+ });
+ objects.add(Arc::new(Sphere {
+ center: Point3 {
+ x: 220.0,
+ y: 280.0,
+ z: 300.0,
+ },
+ radius: 80.0,
+ material: pertext,
+ }));
let mut boxes_2 = HittableList::new();
- let white = Arc::new(Lambertian::from_color(Color { x: 0.73, y: 0.73, z: 0.73 }));
+ let white = Arc::new(Lambertian::from_color(Color {
+ x: 0.73,
+ y: 0.73,
+ z: 0.73,
+ }));
for _ in 0..1000 {
- boxes_2.add(Arc::new(Sphere { center: Point3::random_in_range(0.0, 165.0), radius: 10.0, material: white.clone() }));
+ boxes_2.add(Arc::new(Sphere {
+ center: Point3::random_in_range(0.0, 165.0),
+ radius: 10.0,
+ material: white.clone(),
+ }));
}
- objects.add(Arc::new(Translate { hittable: Arc::new(RotateY::new(Arc::new(BVHNode::new(&boxes_2, 0.0, 1.0)), 15.0)), offset: Vec3 { x: -100.0, y: 270.0, z: 395.0 } }));
- (Arc::new(objects), Point3 { x: 478.0, y: 278.0, z: -600.0}, Point3 { x: 278.0, y: 278.0, z: 0.0}, 40.0, 0.0, Color::new())
+ objects.add(Arc::new(Translate {
+ hittable: Arc::new(RotateY::new(
+ Arc::new(BVHNode::new(&boxes_2, 0.0, 1.0)),
+ 15.0,
+ )),
+ offset: Vec3 {
+ x: -100.0,
+ y: 270.0,
+ z: 395.0,
+ },
+ }));
+ (
+ Arc::new(objects),
+ Point3 {
+ x: 478.0,
+ y: 278.0,
+ z: -600.0,
+ },
+ Point3 {
+ x: 278.0,
+ y: 278.0,
+ z: 0.0,
+ },
+ 40.0,
+ 0.0,
+ Color::new(),
+ )
}
fn test_scene() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) {
let mut objects = HittableList::new();
//let earth_texture = Arc::new(ImageTexture::from_bmp_data(&include_bytes!("../res/earthmap.bmp").to_vec()));
//let earth_surface = Arc::new(Lambertian { albedo: earth_texture });
- let pertext = Arc::new(Lambertian { albedo: Arc::new(NoiseTexture::new(4.0)) });
- objects.add(Arc::new(XZRect { material: pertext, x0: -f64::INFINITY, x1: f64::INFINITY, z0: -f64::INFINITY, z1: f64::INFINITY, k: 0.0 }));
+ let pertext = Arc::new(Lambertian {
+ albedo: Arc::new(NoiseTexture::new(4.0)),
+ });
+ objects.add(Arc::new(XZRect {
+ material: pertext,
+ x0: -f64::INFINITY,
+ x1: f64::INFINITY,
+ z0: -f64::INFINITY,
+ z1: f64::INFINITY,
+ k: 0.0,
+ }));
//(Arc::new(BVHNode::new(&objects, 0.0, 1.0)), Point3 { x: 13.0, y: 2.0, z: 3.0}, Point3::new(), 20.0, 0.0, Color { x: 0.7, y: 0.8, z: 1.0 })
- (Arc::new(objects), Point3 { x: 13.0, y: 2.0, z: 3.0}, Point3::new(), 20.0, 0.0, Color { x: 0.7, y: 0.8, z: 1.0 })
+ (
+ Arc::new(objects),
+ Point3 {
+ x: 13.0,
+ y: 2.0,
+ z: 3.0,
+ },
+ Point3::new(),
+ 20.0,
+ 0.0,
+ Color {
+ x: 0.7,
+ y: 0.8,
+ z: 1.0,
+ },
+ )
}
fn triangle_scene() -> (Arc<dyn Hittable>, Point3, Point3, f64, f64, Color) {
let mut objects = HittableList::new();
- let checker = Arc::new(CheckerTexture::from_colors(Color { x: 0.2, y: 0.3, z: 0.1 } , Color { x: 0.9, y: 0.9, z: 0.9 }));
+ let checker = Arc::new(CheckerTexture::from_colors(
+ Color {
+ x: 0.2,
+ y: 0.3,
+ z: 0.1,
+ },
+ Color {
+ x: 0.9,
+ y: 0.9,
+ z: 0.9,
+ },
+ ));
let ground_material = Arc::new(Lambertian { albedo: checker });
- objects.add(Arc::new(Sphere{ center: Point3 { x: 0.0, y: -1001.0, z: 0.0 }, radius: 1000.0, material: ground_material }));
+ objects.add(Arc::new(Sphere {
+ center: Point3 {
+ x: 0.0,
+ y: -1001.0,
+ z: 0.0,
+ },
+ radius: 1000.0,
+ material: ground_material,
+ }));
//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, 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(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);
//(Arc::new(objects), Point3 { x: 5.0, y: 5.0, z: 5.0}, Point3::new(), 20.0, 0.0, Color { x: 0.7, y: 0.8, z: 1.0 })
- (Arc::new(BVHNode::new(&objects, 0.0, 1.0)), Point3 { x: 5.0, y: 5.0, z: 5.0}, Point3 { x: 0.0, y: 0.0, z: 0.0}, 20.0, 0.0, Color { x: 0.7, y: 0.8, z: 1.0 })
+ (
+ Arc::new(BVHNode::new(&objects, 0.0, 1.0)),
+ Point3 {
+ x: 5.0,
+ y: 5.0,
+ z: 5.0,
+ },
+ Point3 {
+ x: 0.0,
+ y: 0.0,
+ z: 0.0,
+ },
+ 20.0,
+ 0.0,
+ Color {
+ x: 0.7,
+ y: 0.8,
+ z: 1.0,
+ },
+ )
}
diff --git a/src/texture/checker_texture.rs b/src/texture/checker_texture.rs
index 385017b..d10166e 100644
--- a/src/texture/checker_texture.rs
+++ b/src/texture/checker_texture.rs
@@ -1,6 +1,6 @@
use std::sync::Arc;
-use super::{Texture, SolidColor};
+use super::{SolidColor, Texture};
use crate::{vec3::Color, vec3::Point3};
pub struct CheckerTexture {
diff --git a/src/texture/image_texture.rs b/src/texture/image_texture.rs
index 763c3f0..d90b9b6 100644
--- a/src/texture/image_texture.rs
+++ b/src/texture/image_texture.rs
@@ -50,8 +50,12 @@ impl Texture for ImageTexture {
let mut i = (u * self.width as f64) as usize;
let mut j = (v * self.height as f64) as usize;
- if i >= self.width { i = self.width - 1 };
- if j >= self.height { j = self.height - 1 };
+ if i >= self.width {
+ i = self.width - 1
+ };
+ if j >= self.height {
+ j = self.height - 1
+ };
let color_scale = 1.0 / 255.0;
let pixel = j * self.bytes_per_scanline + i * BYTES_PER_PIXEL;
Color {
diff --git a/src/texture/noise_texture.rs b/src/texture/noise_texture.rs
index 92ac166..7fe3cdb 100644
--- a/src/texture/noise_texture.rs
+++ b/src/texture/noise_texture.rs
@@ -1,4 +1,4 @@
-use super::{Texture, perlin::Perlin};
+use super::{perlin::Perlin, Texture};
use crate::{vec3::Color, vec3::Point3};
pub struct NoiseTexture {
@@ -17,6 +17,11 @@ impl NoiseTexture {
impl Texture for NoiseTexture {
fn value(&self, _: f64, _: f64, p: &Point3) -> Color {
- Color { x: 1.0, y: 1.0, z: 1.0 } * 0.5 * (1.0 + (self.scale * p.z + 10.0 * self.noise.turb(p, 7)).sin())
+ Color {
+ x: 1.0,
+ y: 1.0,
+ z: 1.0,
+ } * 0.5
+ * (1.0 + (self.scale * p.z + 10.0 * self.noise.turb(p, 7)).sin())
}
}
diff --git a/src/texture/perlin.rs b/src/texture/perlin.rs
index 43d8f64..a796a43 100644
--- a/src/texture/perlin.rs
+++ b/src/texture/perlin.rs
@@ -1,4 +1,4 @@
-use crate::vec3::{Vec3, Point3};
+use crate::vec3::{Point3, Vec3};
const POINT_COUNT: usize = 256;
@@ -55,7 +55,8 @@ impl Perlin {
^ self.perm_z.get(((k + dk as i32) & 255) as usize).unwrap())
as usize,
)
- .unwrap().clone();
+ .unwrap()
+ .clone();
}
}
}
@@ -73,11 +74,15 @@ impl Perlin {
let i_f = i as f64;
let j_f = j as f64;
let k_f = k as f64;
- let weight_v = Vec3 { x: u - i_f, y: v - j_f, z: w - k_f };
- accum += (i_f * uu + (1.0 - i_f) * (1.0 - uu)) *
- (j_f * vv + (1.0 - j_f) * (1.0 - vv)) *
- (k_f * ww + (1.0 - k_f) * (1.0 - ww)) *
- c[i][j][k].dot(&weight_v);
+ let weight_v = Vec3 {
+ x: u - i_f,
+ y: v - j_f,
+ z: w - k_f,
+ };
+ accum += (i_f * uu + (1.0 - i_f) * (1.0 - uu))
+ * (j_f * vv + (1.0 - j_f) * (1.0 - vv))
+ * (k_f * ww + (1.0 - k_f) * (1.0 - ww))
+ * c[i][j][k].dot(&weight_v);
}
}
}
diff --git a/src/texture/solid_color.rs b/src/texture/solid_color.rs
index 3af46ca..1bbc463 100644
--- a/src/texture/solid_color.rs
+++ b/src/texture/solid_color.rs
@@ -7,9 +7,7 @@ pub struct SolidColor {
impl SolidColor {
pub fn from_color(color_value: Color) -> Self {
- Self {
- color_value,
- }
+ Self { color_value }
}
}
diff --git a/src/vec3.rs b/src/vec3.rs
index 8525fdd..e2f253a 100644
--- a/src/vec3.rs
+++ b/src/vec3.rs
@@ -88,7 +88,7 @@ impl Vec3 {
if p.length_squared() < 1.0 {
return p;
}
- };
+ }
}
pub fn random_unit_vector() -> Vec3 {
@@ -98,8 +98,8 @@ impl Vec3 {
pub fn random_in_unit_disk() -> Vec3 {
loop {
let p = Vec3 {
- x: 2.0 * rand::random::<f64>() -1.0,
- y: 2.0 * rand::random::<f64>() -1.0,
+ x: 2.0 * rand::random::<f64>() - 1.0,
+ y: 2.0 * rand::random::<f64>() - 1.0,
z: 0.0,
};
if p.length_squared() < 1.0 {
@@ -166,7 +166,7 @@ impl<'a> Iterator for Vec3Iterator<'a> {
}
}
-impl_op_ex!(- |a: &Vec3| -> Vec3 {
+impl_op_ex!(-|a: &Vec3| -> Vec3 {
Vec3 {
x: -a.x,
y: -a.y,