Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
303 changes: 274 additions & 29 deletions Cargo.lock

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ version = "0.1.0"
edition = "2021"

[profile.release]
lto = "fat"
debug = 1
opt-level = 3

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
image = "0.23.14"
glam = "0.20.2"
image = "0.24.2"
glam = { version = "0.21.2", features = ["fast-math"] }
rayon = "1.5.1"
rand = { version = "0.8.4", features = ["small_rng"] }
rand = { version = "0.8.4", features = ["small_rng"] }
48 changes: 33 additions & 15 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ mod rt;

use color_output::*;
use math::*;
use rand::distributions::{Standard as StandardDist};
use rand::prelude::*;
use rayon::prelude::*;
use rt::geometry;
Expand All @@ -20,18 +19,18 @@ fn report_progress(scanline: u32) {
io::stderr().flush().unwrap();
}

fn random_scene(rng: &mut impl Rng) -> Vec<geometry::Sphere> {
fn random_scene(rng: &mut impl Rng) -> Vec<Box<dyn Hittable>> {
let n = 22;
let mut world = Vec::with_capacity(n);
let mut world: Vec<Box<dyn Hittable>> = Vec::with_capacity(n);

let mat_ground = rt::Material::Lambertian {
albedo: Color::splat(0.5),
};
world.push(geometry::Sphere::new(
world.push(Box::new(geometry::sphere(
Point3::new(0.0, -1000.0, 0.0),
1000.0,
mat_ground,
));
)));

let upper_m: i64 = n as i64 / 2;
let lower_m: i64 = -upper_m;
Expand Down Expand Up @@ -61,7 +60,17 @@ fn random_scene(rng: &mut impl Rng) -> Vec<geometry::Sphere> {
}
};

world.push(geometry::Sphere::new(center, 0.2, mat));
if mat_prob < 0.8 {
let center2 =
center + Vec3::new(0.0, rng.sample::<f32, _>(StandardDist) * 0.5, 0.0);
world.push(Box::new(geometry::moving_sphere(
geometry::sphere(center, 0.2, mat),
center2,
0.0..1.0,
)));
} else {
world.push(Box::new(geometry::sphere(center, 0.2, mat)));
}
}
}

Expand All @@ -70,35 +79,43 @@ fn random_scene(rng: &mut impl Rng) -> Vec<geometry::Sphere> {
roughness: 0.01,
ior: 1.5,
};
world.push(geometry::Sphere::new(Point3::new(0.0, 1.0, 0.0), 1.0, mat1));
world.push(Box::new(geometry::sphere(
Point3::new(0.0, 1.0, 0.0),
1.0,
mat1,
)));

let mat2 = rt::Material::Lambertian {
albedo: Color::new(0.4, 0.2, 0.1),
};
world.push(geometry::Sphere::new(
world.push(Box::new(geometry::sphere(
Point3::new(-4.0, 1.0, 0.0),
1.0,
mat2,
));
)));

let mat3 = rt::Material::Metallic {
albedo: Color::new(0.7, 0.6, 0.5),
roughness: 0.01,
};
world.push(geometry::Sphere::new(Point3::new(4.0, 1.0, 0.0), 1.0, mat3));
world.push(Box::new(geometry::sphere(
Point3::new(4.0, 1.0, 0.0),
1.0,
mat3,
)));
world
}

fn main() {
// Image
let aspect_ratio = 3.0 / 2.0;
let samples_per_pixel = 256;
let image_width = 1200u32;
let aspect_ratio = 16.0 / 9.0;
let samples_per_pixel = 32;
let image_width = 1280u32;
let image_height = (image_width as f32 / aspect_ratio) as u32;

// World
let mut world_rng = SmallRng::seed_from_u64(0xEDADBEEF);
let world = random_scene(&mut world_rng);
let world = Bvh::new(random_scene(&mut world_rng), 0.0..1.0);

// Camera
let camera = Camera::new(
Expand All @@ -107,6 +124,7 @@ fn main() {
Point3::Y,
20.0,
aspect_ratio,
0.0..1.0,
0.1,
Some(10.0),
);
Expand Down Expand Up @@ -138,7 +156,7 @@ fn main() {
let v = (j as f32 + v_offset) / (image_height - 1) as f32;

r = camera.get_ray(u, v, &mut rng);
color += ray_color(r, world.as_slice(), &mut rng);
color += ray_color(&mut r, &world, &mut rng);
}
output_color(color * color_scale)
})
Expand Down
7 changes: 5 additions & 2 deletions src/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ pub type Point3 = glam::Vec3A;
pub type Vec3 = glam::Vec3A;

mod ray;

pub use ray::Ray;

use rand::prelude::*;

use crate::color_output::Color;

pub use rand::distributions::Standard as StandardDist;

#[inline(always)]
pub fn random_vec3(rng: &mut impl Rng, min: f32, max: f32) -> Vec3 {
let values: [f32; 3] = rng.sample(rand::distributions::Standard);
let values: [f32; 3] = rng.sample(StandardDist);
(max - min) * Vec3::from_slice(&values) + Vec3::splat(min)
}

Expand All @@ -21,7 +24,7 @@ pub fn random_on_unit_sphere(rng: &mut impl Rng) -> Vec3 {

pub fn random_in_unit_disk(rng: &mut impl Rng) -> Vec3 {
loop {
let values: [f32; 2] = rng.sample(rand::distributions::Standard);
let values: [f32; 2] = rng.sample(StandardDist);
let vec = Vec3::new(values[0], values[1], 0.0);
if vec.length_squared() >= 1.0 {
continue;
Expand Down
33 changes: 28 additions & 5 deletions src/math/ray.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,40 @@
use super::*;

#[derive(Copy, Clone)]
#[derive(Debug, Copy, Clone)]
pub struct Ray {
pub orig: Point3,
pub dir: Vec3,
pub time: f32,
pub color: Color,
}

impl Ray {
pub fn new(orig: Point3, dir: Vec3) -> Ray {
Ray {orig, dir}
pub fn new(orig: Point3, dir: Vec3, time: f32) -> Ray {
Ray {
orig,
dir,
time,
..Default::default()
}
}

pub fn at(&self, t: f32) -> Point3 {
self.orig + t*self.dir
self.orig + t * self.dir
}
}

pub fn attenuate(mut self, incoming_color: Color) -> Self {
self.color = attenuate(self.color, incoming_color);
self
}
}

impl Default for Ray {
fn default() -> Self {
Ray {
orig: Vec3::ZERO,
dir: Vec3::ONE,
time: 0.0,
color: Color::ONE - Color::splat(0.001),
}
}
}
24 changes: 8 additions & 16 deletions src/rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,29 @@ mod camera;
pub mod geometry;
mod hittable;
mod material;
mod aabb;
mod bvh;

pub use camera::*;
pub use hittable::*;
pub use material::*;
pub use aabb::*;
pub use bvh::*;

use crate::color_output::*;
use crate::math::*;
use rand::prelude::*;

pub fn ray_color<T: Hittable + ?Sized>(mut r: Ray, world: &T, rng: &mut impl Rng) -> Color {
pub fn ray_color<T: Hittable + ?Sized>(r: &mut Ray, world: &T, rng: &mut impl Rng) -> Color {
let white = Color::splat(1.0);
let skyblue = Color::new(0.5, 0.7, 1.0);
let mut color = Color::ONE;
let mut bounces = 0;

while let Some(hit) = world.hit(&r, 0.001, f32::INFINITY) {
if let Some(MaterialResponse {
attenuation: a,
new_ray,
}) = hit.material.scatter(&r, &hit, rng)
{
color = attenuate(color, a);
r = new_ray;
} else {
color = Color::ZERO;
break;
}
while let Some(hit) = world.hit(r, 0.001, f32::INFINITY) {
*r = hit.material.scatter(r, &hit, rng);

bounces += 1;
if bounces > 50 {
color = Color::ZERO;
break;
}
}
Expand All @@ -41,5 +33,5 @@ pub fn ray_color<T: Hittable + ?Sized>(mut r: Ray, world: &T, rng: &mut impl Rng
let t = 0.5 * (unit_dir.y + 1.0);
let env_color = white.lerp(skyblue, t);

color * env_color
attenuate(r.color, env_color)
}
65 changes: 65 additions & 0 deletions src/rt/aabb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use crate::math::*;

#[derive(Clone, Copy, Debug)]
pub struct Aabb {
pub min: Point3,
pub max: Point3,
infinite: bool,
}

impl Aabb {
pub fn new(min: Point3, max: Point3) -> Self {
Aabb {
min,
max,
infinite: false,
}
}

pub fn infinite() -> Self {
Aabb {
min: Vec3::splat(f32::NEG_INFINITY),
max: Vec3::splat(f32::INFINITY),
infinite: true,
}
}

pub fn surrounding_box(self, other: Self) -> Self {
Self {
min: self.min.min(other.min),
max: self.max.max(other.max),
infinite: self.infinite || other.infinite,
}
}

pub fn doubled_centroid(&self) -> Vec3 {
self.max - self.min
}

pub fn surface_area(&self) -> f32 {
let measurements = self.max - self.min;
2.0 * (measurements.x * measurements.y
+ measurements.y * measurements.z
+ measurements.z * measurements.x)
}

pub fn hit(&self, r: &Ray, t_min: f32, t_max: f32) -> bool {
if self.infinite {
return true;
}

let inv_d = 1.0 / r.dir;
let t00 = (self.min - r.orig) * inv_d;
let t01 = (self.max - r.orig) * inv_d;

// swap t0_i and t1_i if inv_d_i is negative and thus t0_i > t1_i
let ltz = inv_d.cmplt(Vec3::ZERO);
let t0 = Vec3::select(ltz, t01, t00);
let t1 = Vec3::select(ltz, t00, t01);

let t_min_1 = t_min.max(t0.max_element());
let t_max_1 = t_max.min(t1.min_element());

t_max_1 > t_min_1
}
}
Loading