refactored some code and added two spheres
This commit is contained in:
parent
6037fe2802
commit
b4d7ddfc4d
119
src/demos/checkered_motion_blur.rs
Normal file
119
src/demos/checkered_motion_blur.rs
Normal file
|
@ -0,0 +1,119 @@
|
|||
use crate::{
|
||||
demos::{Demo, ParallelHit},
|
||||
materials::{Dielectric, Lambertian, Metal},
|
||||
shapes::{MovingSphere, Sphere},
|
||||
texture::{Checker, Solid},
|
||||
types::Vec3,
|
||||
BvhNode, Camera,
|
||||
};
|
||||
use rand::{rngs::SmallRng, Rng, SeedableRng};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct CheckeredMotionBlur {}
|
||||
|
||||
impl Demo for CheckeredMotionBlur {
|
||||
type DemoT = BvhNode<Arc<dyn ParallelHit>>;
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"checkered_motion_blur"
|
||||
}
|
||||
|
||||
fn world(&self) -> Self::DemoT {
|
||||
let mut world: Vec<Arc<dyn ParallelHit>> = Vec::with_capacity(500);
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = SmallRng::from_rng(&mut rng).unwrap();
|
||||
|
||||
world.push(Arc::new(Sphere::new(
|
||||
Vec3::new(0.0, -1000.0, 0.0),
|
||||
1000.0,
|
||||
Lambertian::new(Checker::new(
|
||||
Solid::new(Vec3::new(0.2, 0.3, 0.1)),
|
||||
Solid::new(Vec3::new(0.9, 0.9, 0.9)),
|
||||
)),
|
||||
)));
|
||||
|
||||
let radius = 0.2;
|
||||
let l = Vec3::new(4.0, 0.2, 0.0);
|
||||
|
||||
for a in -10..10 {
|
||||
let a = a as f64;
|
||||
for b in -10..10 {
|
||||
let b = b as f64;
|
||||
let choose_material_probability = rng.gen::<f64>();
|
||||
let center = Vec3::new(a + 0.9 * rng.gen::<f64>(), 0.2, b + 0.9 * rng.gen::<f64>());
|
||||
|
||||
if (center - l).length() > 0.9 {
|
||||
if choose_material_probability < 0.8 {
|
||||
// diffuse material
|
||||
world.push(Arc::new(MovingSphere::new(
|
||||
center,
|
||||
center + Vec3::new(0.0, 0.5 * rng.gen::<f64>(), 0.0),
|
||||
0.0,
|
||||
1.0,
|
||||
radius,
|
||||
Lambertian::new(Solid::new(Vec3::new(
|
||||
rng.gen::<f64>() * rng.gen::<f64>(),
|
||||
rng.gen::<f64>() * rng.gen::<f64>(),
|
||||
rng.gen::<f64>() * rng.gen::<f64>(),
|
||||
))),
|
||||
)));
|
||||
} else if choose_material_probability < 0.95 {
|
||||
// metal material
|
||||
world.push(Arc::new(Sphere::new(
|
||||
center,
|
||||
radius,
|
||||
Metal::with_fuzz(
|
||||
Vec3::new(
|
||||
(1.0 + rng.gen::<f64>()) * 0.5,
|
||||
(1.0 + rng.gen::<f64>()) * 0.5,
|
||||
(1.0 + rng.gen::<f64>()) * 0.5,
|
||||
),
|
||||
0.5 * rng.gen::<f64>(),
|
||||
),
|
||||
)));
|
||||
} else {
|
||||
// glass material
|
||||
world.push(Arc::new(Sphere::new(center, radius, Dielectric::new(1.5))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
world.push(Arc::new(Sphere::new(
|
||||
Vec3::new(0.0, 1.0, 0.0),
|
||||
1.0,
|
||||
Dielectric::new(1.5),
|
||||
)));
|
||||
world.push(Arc::new(Sphere::new(
|
||||
Vec3::new(-4.0, 1.0, 0.0),
|
||||
1.0,
|
||||
Lambertian::new(Solid::new(Vec3::new(0.4, 0.2, 0.1))),
|
||||
)));
|
||||
world.push(Arc::new(Sphere::new(
|
||||
Vec3::new(4.0, 1.0, 0.0),
|
||||
1.0,
|
||||
Metal::with_fuzz(Vec3::new(0.7, 0.6, 0.5), 0.0),
|
||||
)));
|
||||
|
||||
BvhNode::new(&mut rng, &mut world, 0.0, 1.0)
|
||||
}
|
||||
|
||||
fn camera(&self, aspect_ratio: f64) -> Camera {
|
||||
let lookfrom = Vec3::new(13.0, 2.0, 3.0);
|
||||
let lookat = Vec3::new(0.0, 0.0, 0.0);
|
||||
let aperture = 0.1;
|
||||
let focus_distance = 10.0;
|
||||
Camera::new(
|
||||
lookfrom,
|
||||
lookat,
|
||||
Vec3::new(0.0, 1.0, 0.0),
|
||||
20.0,
|
||||
aspect_ratio,
|
||||
aperture,
|
||||
focus_distance,
|
||||
0.0,
|
||||
1.0,
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,9 +1,6 @@
|
|||
use crate::{
|
||||
materials::{Dielectric, Lambertian, Metal},
|
||||
shapes::{MovingSphere, Sphere},
|
||||
texture::{Checker, Solid},
|
||||
types::{Ray, Vec3},
|
||||
BvhNode, Camera, Hitable, HORIZONTAL_PARTITION, VERTICAL_PARTITION,
|
||||
Camera, Hitable, HORIZONTAL_PARTITION, VERTICAL_PARTITION,
|
||||
};
|
||||
use rand::{rngs::SmallRng, Rng, SeedableRng};
|
||||
use rayon::prelude::*;
|
||||
|
@ -14,6 +11,12 @@ use std::{
|
|||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
mod checkered_motion_blur;
|
||||
mod two_spheres;
|
||||
|
||||
pub use checkered_motion_blur::CheckeredMotionBlur;
|
||||
pub use two_spheres::TwoSpheres;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Chunk {
|
||||
num: usize,
|
||||
|
@ -39,113 +42,16 @@ impl Display for Chunk {
|
|||
pub trait ParallelHit: Hitable + Send + Sync {}
|
||||
impl<T: Hitable + Send + Sync> ParallelHit for T {}
|
||||
|
||||
pub struct Demo;
|
||||
pub trait Demo: Send + Sync {
|
||||
type DemoT: Hitable + Send + Sync;
|
||||
|
||||
impl Demo {
|
||||
pub fn name(&self) -> &'static str {
|
||||
"motion_blur"
|
||||
}
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
fn world(&self) -> impl Hitable {
|
||||
let mut world: Vec<Arc<dyn ParallelHit>> = Vec::with_capacity(500);
|
||||
fn world(&self) -> Self::DemoT;
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = SmallRng::from_rng(&mut rng).unwrap();
|
||||
fn camera(&self, aspect_ratio: f64) -> Camera;
|
||||
|
||||
world.push(Arc::new(Sphere::new(
|
||||
Vec3::new(0.0, -1000.0, 0.0),
|
||||
1000.0,
|
||||
Lambertian::new(Checker::new(
|
||||
Solid::new(Vec3::new(0.2, 0.3, 0.1)),
|
||||
Solid::new(Vec3::new(0.9, 0.9, 0.9)),
|
||||
)),
|
||||
)));
|
||||
|
||||
let radius = 0.2;
|
||||
let l = Vec3::new(4.0, 0.2, 0.0);
|
||||
|
||||
for a in -10..10 {
|
||||
let a = a as f64;
|
||||
for b in -10..10 {
|
||||
let b = b as f64;
|
||||
let choose_material_probability = rng.gen::<f64>();
|
||||
let center = Vec3::new(a + 0.9 * rng.gen::<f64>(), 0.2, b + 0.9 * rng.gen::<f64>());
|
||||
|
||||
if (center - l).length() > 0.9 {
|
||||
if choose_material_probability < 0.8 {
|
||||
// diffuse material
|
||||
world.push(Arc::new(MovingSphere::new(
|
||||
center,
|
||||
center + Vec3::new(0.0, 0.5 * rng.gen::<f64>(), 0.0),
|
||||
0.0,
|
||||
1.0,
|
||||
radius,
|
||||
Lambertian::new(Solid::new(Vec3::new(
|
||||
rng.gen::<f64>() * rng.gen::<f64>(),
|
||||
rng.gen::<f64>() * rng.gen::<f64>(),
|
||||
rng.gen::<f64>() * rng.gen::<f64>(),
|
||||
))),
|
||||
)));
|
||||
} else if choose_material_probability < 0.95 {
|
||||
// metal material
|
||||
world.push(Arc::new(Sphere::new(
|
||||
center,
|
||||
radius,
|
||||
Metal::with_fuzz(
|
||||
Vec3::new(
|
||||
(1.0 + rng.gen::<f64>()) * 0.5,
|
||||
(1.0 + rng.gen::<f64>()) * 0.5,
|
||||
(1.0 + rng.gen::<f64>()) * 0.5,
|
||||
),
|
||||
0.5 * rng.gen::<f64>(),
|
||||
),
|
||||
)));
|
||||
} else {
|
||||
// glass material
|
||||
world.push(Arc::new(Sphere::new(center, radius, Dielectric::new(1.5))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
world.push(Arc::new(Sphere::new(
|
||||
Vec3::new(0.0, 1.0, 0.0),
|
||||
1.0,
|
||||
Dielectric::new(1.5),
|
||||
)));
|
||||
world.push(Arc::new(Sphere::new(
|
||||
Vec3::new(-4.0, 1.0, 0.0),
|
||||
1.0,
|
||||
Lambertian::new(Solid::new(Vec3::new(0.4, 0.2, 0.1))),
|
||||
)));
|
||||
world.push(Arc::new(Sphere::new(
|
||||
Vec3::new(4.0, 1.0, 0.0),
|
||||
1.0,
|
||||
Metal::with_fuzz(Vec3::new(0.7, 0.6, 0.5), 0.0),
|
||||
)));
|
||||
|
||||
BvhNode::new(&mut rng, &mut world, 0.0, 1.0)
|
||||
}
|
||||
|
||||
fn camera(&self, aspect_ratio: f64) -> Camera {
|
||||
let lookfrom = Vec3::new(13.0, 2.0, 3.0);
|
||||
let lookat = Vec3::new(0.0, 0.0, 0.0);
|
||||
let aperture = 0.1;
|
||||
let focus_distance = 10.0;
|
||||
Camera::new(
|
||||
lookfrom,
|
||||
lookat,
|
||||
Vec3::new(0.0, 1.0, 0.0),
|
||||
20.0,
|
||||
aspect_ratio,
|
||||
aperture,
|
||||
focus_distance,
|
||||
0.0,
|
||||
1.0,
|
||||
)
|
||||
}
|
||||
|
||||
fn render_chunk(&self, chunk: &mut Chunk, camera: &Camera, world: &impl Hitable, samples: u8) {
|
||||
fn render_chunk(&self, chunk: &mut Chunk, camera: &Camera, world: &Self::DemoT, samples: u8) {
|
||||
let &mut Chunk {
|
||||
num: _,
|
||||
x,
|
||||
|
@ -180,7 +86,7 @@ impl Demo {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn render(&self, buf: &mut Vec<u8>, x: usize, y: usize, samples: u8) {
|
||||
fn render(&self, buf: &mut Vec<u8>, x: usize, y: usize, samples: u8) {
|
||||
let world = self.world();
|
||||
let delta_x = x / VERTICAL_PARTITION;
|
||||
let delta_y = y / HORIZONTAL_PARTITION;
|
||||
|
@ -253,10 +159,16 @@ impl Demo {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn save_as_ppm(&self, buf: &[u8], width: usize, height: usize) {
|
||||
fn save_as_ppm(&self, buf: &[u8], width: usize, height: usize, samples: u8) {
|
||||
let header = format!("P3\n{} {}\n255\n", width, height);
|
||||
|
||||
let mut file = match File::create(&format!("{}-{}x{}.ppm", self.name(), width, height)) {
|
||||
let mut file = match File::create(&format!(
|
||||
"{}-{}x{}_{}.ppm",
|
||||
self.name(),
|
||||
width,
|
||||
height,
|
||||
samples,
|
||||
)) {
|
||||
Ok(file) => file,
|
||||
Err(e) => panic!("couldn't create {}: {}", self.name(), e),
|
||||
};
|
67
src/demos/two_spheres.rs
Normal file
67
src/demos/two_spheres.rs
Normal file
|
@ -0,0 +1,67 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use rand::{prelude::SmallRng, SeedableRng};
|
||||
|
||||
use crate::{
|
||||
demos::{Demo, ParallelHit},
|
||||
materials::Lambertian,
|
||||
shapes::Sphere,
|
||||
texture::{Checker, Solid},
|
||||
types::Vec3,
|
||||
BvhNode, Camera,
|
||||
};
|
||||
|
||||
pub struct TwoSpheres {}
|
||||
|
||||
impl Demo for TwoSpheres {
|
||||
type DemoT = BvhNode<Arc<dyn ParallelHit>>;
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"two_checkered_sphere"
|
||||
}
|
||||
|
||||
fn world(&self) -> Self::DemoT {
|
||||
let mut world: Vec<Arc<dyn ParallelHit>> = Vec::with_capacity(500);
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = SmallRng::from_rng(&mut rng).unwrap();
|
||||
|
||||
world.push(Arc::new(Sphere::new(
|
||||
Vec3::new(0.0, -10.0, 0.0),
|
||||
10.0,
|
||||
Lambertian::new(Checker::new(
|
||||
Solid::new(Vec3::new(0.2, 0.3, 0.1)),
|
||||
Solid::new(Vec3::new(0.9, 0.9, 0.9)),
|
||||
)),
|
||||
)));
|
||||
|
||||
world.push(Arc::new(Sphere::new(
|
||||
Vec3::new(0.0, 10.0, 0.0),
|
||||
10.0,
|
||||
Lambertian::new(Checker::new(
|
||||
Solid::new(Vec3::new(0.2, 0.3, 0.1)),
|
||||
Solid::new(Vec3::new(0.9, 0.9, 0.9)),
|
||||
)),
|
||||
)));
|
||||
|
||||
BvhNode::new(&mut rng, &mut world, 0.0, 1.0)
|
||||
}
|
||||
|
||||
fn camera(&self, aspect_ratio: f64) -> Camera {
|
||||
let lookfrom = Vec3::new(13.0, 2.0, 3.0);
|
||||
let lookat = Vec3::new(0.0, 0.0, 0.0);
|
||||
let aperture = 0.1;
|
||||
let focus_distance = 10.0;
|
||||
Camera::new(
|
||||
lookfrom,
|
||||
lookat,
|
||||
Vec3::new(0.0, 1.0, 0.0),
|
||||
20.0,
|
||||
aspect_ratio,
|
||||
aperture,
|
||||
focus_distance,
|
||||
0.0,
|
||||
1.0,
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use crate::{demo::ParallelHit, types::Ray, Aabb, HitRecord, Hitable};
|
||||
use crate::{demos::ParallelHit, types::Ray, Aabb, HitRecord, Hitable};
|
||||
|
||||
pub struct HitableList {
|
||||
pub list: Vec<Arc<dyn ParallelHit>>,
|
||||
|
|
48
src/main.rs
48
src/main.rs
|
@ -3,7 +3,7 @@
|
|||
mod aabb;
|
||||
mod bvh;
|
||||
mod camera;
|
||||
mod demo;
|
||||
mod demos;
|
||||
mod hitable;
|
||||
mod hitable_list;
|
||||
mod materials;
|
||||
|
@ -11,17 +11,19 @@ mod shapes;
|
|||
mod texture;
|
||||
mod types;
|
||||
|
||||
pub use camera::Camera;
|
||||
|
||||
pub use aabb::Aabb;
|
||||
pub use bvh::BvhNode;
|
||||
pub use camera::Camera;
|
||||
pub use hitable::{HitRecord, Hitable};
|
||||
pub use hitable_list::HitableList;
|
||||
pub use materials::Material;
|
||||
use std::time::Instant;
|
||||
pub use texture::Texture;
|
||||
|
||||
const NUM_SAMPLES: u8 = 20;
|
||||
use demos::Demo;
|
||||
|
||||
use std::time::Instant;
|
||||
|
||||
const NUM_SAMPLES: u8 = 25;
|
||||
const VERTICAL_PARTITION: usize = 12;
|
||||
const HORIZONTAL_PARTITION: usize = 12;
|
||||
const WIDTH: usize = 1920;
|
||||
|
@ -33,16 +35,18 @@ fn main() -> Result<(), String> {
|
|||
|
||||
#[cfg(feature = "gui")]
|
||||
fn run(mut width: usize, mut height: usize) -> Result<(), String> {
|
||||
use demos::ParallelHit;
|
||||
use sdl2::{
|
||||
event::{Event, WindowEvent},
|
||||
keyboard::Keycode,
|
||||
pixels::PixelFormatEnum,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
let sdl_ctx = sdl2::init()?;
|
||||
let video_subsys = sdl_ctx.video()?;
|
||||
let window = video_subsys
|
||||
.window("Ray tracing in a weekend", width as u32, height as u32)
|
||||
.window("Ray tracing the Next Week", width as u32, height as u32)
|
||||
.position_centered()
|
||||
.build()
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
@ -63,9 +67,10 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> {
|
|||
.create_texture_static(PixelFormatEnum::BGR888, width as u32, height as u32)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let active_demo = demo::Demo;
|
||||
|
||||
let mut active_demo: &dyn Demo<DemoT = BvhNode<Arc<dyn ParallelHit>>> =
|
||||
&demos::CheckeredMotionBlur {};
|
||||
let mut should_update = true;
|
||||
|
||||
loop {
|
||||
for event in event_pump.poll_iter() {
|
||||
match event {
|
||||
|
@ -77,9 +82,17 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> {
|
|||
Event::KeyUp { keycode, .. } => {
|
||||
match keycode {
|
||||
Some(Keycode::S) => {
|
||||
active_demo.save_as_ppm(&buffer, width, height);
|
||||
active_demo.save_as_ppm(&buffer, width, height, NUM_SAMPLES);
|
||||
should_update = false;
|
||||
}
|
||||
Some(Keycode::Num1) => {
|
||||
active_demo = &demos::CheckeredMotionBlur {};
|
||||
should_update = true;
|
||||
}
|
||||
Some(Keycode::Num2) => {
|
||||
active_demo = &demos::TwoSpheres {};
|
||||
should_update = true;
|
||||
}
|
||||
None => unreachable!(),
|
||||
_ => (),
|
||||
};
|
||||
|
@ -107,7 +120,6 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> {
|
|||
active_demo.name(),
|
||||
now.elapsed().as_secs_f64()
|
||||
);
|
||||
|
||||
texture.update(None, &buffer, width * 4).unwrap();
|
||||
canvas.copy(&texture, None, None).unwrap();
|
||||
canvas.present();
|
||||
|
@ -118,9 +130,16 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> {
|
|||
|
||||
#[cfg(not(feature = "gui"))]
|
||||
fn run(width: usize, height: usize) -> Result<(), String> {
|
||||
let mut buffer = vec![0; width * height * 4];
|
||||
run_and_save_demo(demos::CheckeredMotionBlur {}, width, height);
|
||||
|
||||
let demo = demo::Demo;
|
||||
run_and_save_demo(demos::TwoSpheres {}, width, height);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "gui"))]
|
||||
fn run_and_save_demo(demo: impl Demo, width: usize, height: usize) {
|
||||
let mut buffer = vec![0; width * height * 4];
|
||||
|
||||
println!(
|
||||
"Starting {} at {}x{} with {} samples",
|
||||
|
@ -129,6 +148,7 @@ fn run(width: usize, height: usize) -> Result<(), String> {
|
|||
height,
|
||||
NUM_SAMPLES
|
||||
);
|
||||
|
||||
let now = Instant::now();
|
||||
demo.render(&mut buffer, width, height, NUM_SAMPLES);
|
||||
println!(
|
||||
|
@ -137,7 +157,5 @@ fn run(width: usize, height: usize) -> Result<(), String> {
|
|||
now.elapsed().as_secs_f64()
|
||||
);
|
||||
|
||||
demo.save_as_ppm(&buffer, width, height);
|
||||
|
||||
Ok(())
|
||||
demo.save_as_ppm(&buffer, width, height, NUM_SAMPLES);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user