Added Defocus Blur and Final Scene, Some refactors
1. Added Defocus Blur Scene and the Final Scene 2. Refactored how the fields from `Chunk` were referenced in `render_chunk` methods 3. Fixed a issue in camera where it remained out of focus regardless of focus distance value 4. Fixed a issue in random_in_unit_disc where it kept generating random nums in a weird space than a disc
This commit is contained in:
parent
f75d0d2b7d
commit
0da70546cd
|
@ -45,8 +45,8 @@ impl Camera {
|
|||
- u * focus_distance * half_width
|
||||
- v * focus_distance * half_height
|
||||
- w * focus_distance;
|
||||
let horizontal = u * half_width * 2.0;
|
||||
let vertical = v * half_height * 2.0;
|
||||
let horizontal = u * half_width * focus_distance * 2.0;
|
||||
let vertical = v * half_height * focus_distance * 2.0;
|
||||
let lens_radius = aperture / 2.0;
|
||||
|
||||
Self {
|
||||
|
@ -73,7 +73,7 @@ impl Camera {
|
|||
}
|
||||
|
||||
fn random_in_unit_disk(rng: &mut rand::rngs::ThreadRng) -> Vec3 {
|
||||
let mut p = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), 0.0) * 2.0 - Vec3::new(1.0, 0.0, 0.0);
|
||||
let mut p = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), 0.0) * 2.0 - Vec3::new(1.0, 1.0, 0.0);
|
||||
|
||||
while p.dot(&p) >= 1.0 {
|
||||
p = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), 0.0) * 2.0 - Vec3::new(1.0, 0.0, 0.0);
|
||||
|
|
|
@ -39,14 +39,14 @@ impl Demo for DefocusBlur {
|
|||
Box::new(Sphere::with_material(
|
||||
Vec3::new(0.0, -100.5, -1.0),
|
||||
100.0,
|
||||
Box::new(Lambertian::new(Vec3::new(0.8, 0.8, 0.0))),
|
||||
Box::new(Lambertian::new(Vec3::new(0.2, 0.2, 0.6))),
|
||||
)),
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
fn camera(&self, aspect_ratio: f64) -> Option<Camera> {
|
||||
let lookfrom = Vec3::new(3.0, 3.0, 2.0);
|
||||
let lookfrom = Vec3::new(3.0, 3.0, 3.0);
|
||||
let lookat = Vec3::new(0.0, 0.0, -1.0);
|
||||
let aperture = 2.0;
|
||||
let distance_to_focus = (lookfrom - lookat).length();
|
||||
|
@ -69,13 +69,15 @@ impl Demo for DefocusBlur {
|
|||
world: Option<&HitableList>,
|
||||
samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
let ny = chunk.ny;
|
||||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
let &mut Chunk {
|
||||
x,
|
||||
y,
|
||||
nx,
|
||||
ny,
|
||||
start_x,
|
||||
start_y,
|
||||
ref mut buffer,
|
||||
} = chunk;
|
||||
let camera = camera.unwrap();
|
||||
let world = world.unwrap();
|
||||
|
||||
|
|
|
@ -56,13 +56,15 @@ impl Demo for DielectricMaterial {
|
|||
world: Option<&HitableList>,
|
||||
samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
let ny = chunk.ny;
|
||||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
let &mut Chunk {
|
||||
x,
|
||||
y,
|
||||
nx,
|
||||
ny,
|
||||
start_x,
|
||||
start_y,
|
||||
ref mut buffer,
|
||||
} = chunk;
|
||||
let camera = camera.unwrap();
|
||||
let world = world.unwrap();
|
||||
|
||||
|
|
|
@ -30,13 +30,15 @@ impl Demo for DiffuseMaterials {
|
|||
world: Option<&HitableList>,
|
||||
samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
let ny = chunk.ny;
|
||||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
let &mut Chunk {
|
||||
x,
|
||||
y,
|
||||
nx,
|
||||
ny,
|
||||
start_x,
|
||||
start_y,
|
||||
ref mut buffer,
|
||||
} = chunk;
|
||||
let camera = camera.unwrap();
|
||||
let world = world.unwrap();
|
||||
|
||||
|
|
177
src/demos/final_scene.rs
Normal file
177
src/demos/final_scene.rs
Normal file
|
@ -0,0 +1,177 @@
|
|||
use {
|
||||
crate::{
|
||||
demos::{Chunk, Demo},
|
||||
types::{
|
||||
material::{Dielectric, Lambertian, Metal},
|
||||
Hitable, HitableList, Ray, Sphere, Vec3,
|
||||
},
|
||||
Camera,
|
||||
},
|
||||
rand::Rng,
|
||||
};
|
||||
|
||||
pub struct FinalScene;
|
||||
|
||||
impl Demo for FinalScene {
|
||||
fn name(&self) -> &'static str {
|
||||
"final-scene"
|
||||
}
|
||||
|
||||
fn world(&self) -> Option<HitableList> {
|
||||
let mut world = HitableList {
|
||||
list: Vec::with_capacity(500),
|
||||
};
|
||||
|
||||
world.push(Box::new(Sphere::with_material(
|
||||
Vec3::new(0.0, -1000.0, 0.0),
|
||||
1000.0,
|
||||
Box::new(Lambertian::new(Vec3::new(0.5, 0.5, 0.5))),
|
||||
)));
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let radius = 0.2;
|
||||
let l = Vec3::new(4.0, 0.2, 0.0);
|
||||
|
||||
for a in -11..11 {
|
||||
let a = a as f64;
|
||||
for b in -11..11 {
|
||||
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(Box::new(Sphere::with_material(
|
||||
center,
|
||||
radius,
|
||||
Box::new(Lambertian::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(Box::new(Sphere::with_material(
|
||||
center,
|
||||
radius,
|
||||
Box::new(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(Box::new(Sphere::with_material(
|
||||
center,
|
||||
radius,
|
||||
Box::new(Dielectric::new(1.5)),
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
world.push(Box::new(Sphere::with_material(
|
||||
Vec3::new(0.0, 1.0, 0.0),
|
||||
1.0,
|
||||
Box::new(Dielectric::new(1.5)),
|
||||
)));
|
||||
world.push(Box::new(Sphere::with_material(
|
||||
Vec3::new(-4.0, 1.0, 0.0),
|
||||
1.0,
|
||||
Box::new(Lambertian::new(Vec3::new(0.4, 0.2, 0.1))),
|
||||
)));
|
||||
world.push(Box::new(Sphere::with_material(
|
||||
Vec3::new(4.0, 1.0, 0.0),
|
||||
1.0,
|
||||
Box::new(Metal::with_fuzz(Vec3::new(0.7, 0.6, 0.5), 0.0)),
|
||||
)));
|
||||
|
||||
println!("world size = {}", world.list.len());
|
||||
Some(world)
|
||||
}
|
||||
|
||||
fn camera(&self, aspect_ratio: f64) -> Option<Camera> {
|
||||
let lookfrom = Vec3::new(13.0, 2.0, 3.0);
|
||||
let lookat = Vec3::new(0.0, 0.0, 0.0);
|
||||
let camera = Camera::new(
|
||||
lookfrom,
|
||||
lookat,
|
||||
Vec3::new(0.0, 1.0, 0.0),
|
||||
20.0,
|
||||
aspect_ratio,
|
||||
0.1,
|
||||
10.0,
|
||||
);
|
||||
Some(camera)
|
||||
}
|
||||
|
||||
fn render_chunk(
|
||||
&self,
|
||||
chunk: &mut Chunk,
|
||||
camera: Option<&Camera>,
|
||||
world: Option<&HitableList>,
|
||||
samples: u8,
|
||||
) {
|
||||
let &mut Chunk {
|
||||
x,
|
||||
y,
|
||||
nx,
|
||||
ny,
|
||||
start_x,
|
||||
start_y,
|
||||
ref mut buffer,
|
||||
} = chunk;
|
||||
let camera = camera.unwrap();
|
||||
let world = world.unwrap();
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut offset = 0;
|
||||
|
||||
for j in start_y..start_y + ny {
|
||||
for i in start_x..start_x + nx {
|
||||
let mut color = Vec3::new(0.0, 0.0, 0.0);
|
||||
for _s in 0..samples {
|
||||
let u = (i as f64 + rng.gen::<f64>()) / x as f64;
|
||||
let v = (j as f64 + rng.gen::<f64>()) / y as f64;
|
||||
|
||||
let ray = camera.get_ray(u, v);
|
||||
color += calc_color(ray, &world, 0);
|
||||
}
|
||||
|
||||
color /= samples as f64;
|
||||
|
||||
// gamma 2 corrected
|
||||
buffer[offset] = (255.99 * color.r().sqrt()) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.g().sqrt()) as u8;
|
||||
buffer[offset + 2] = (255.99 * color.b().sqrt()) as u8;
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn calc_color(ray: Ray, world: &HitableList, depth: u32) -> Vec3 {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f64::MAX) {
|
||||
if depth >= 50 {
|
||||
Vec3::new(0.0, 0.0, 0.0)
|
||||
} else {
|
||||
let material = hit_rec.material.as_ref();
|
||||
if let (attenuation, Some(scattered_ray)) = material.unwrap().scatter(&ray, &hit_rec) {
|
||||
calc_color(scattered_ray, &world, depth + 1) * attenuation
|
||||
} else {
|
||||
Vec3::new(0.0, 0.0, 0.0)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let unit_direction = ray.direction().unit_vector();
|
||||
let t = 0.5 * (unit_direction.y() + 1.0);
|
||||
Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t
|
||||
}
|
||||
}
|
|
@ -26,13 +26,15 @@ impl Demo for HitableSphere {
|
|||
world: Option<&HitableList>,
|
||||
_samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
let ny = chunk.ny;
|
||||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
let &mut Chunk {
|
||||
x,
|
||||
y,
|
||||
nx,
|
||||
ny,
|
||||
start_x,
|
||||
start_y,
|
||||
ref mut buffer,
|
||||
} = chunk;
|
||||
let world = world.unwrap();
|
||||
|
||||
let lower_left_corner = Vec3::new(-2.0, -1.0, -1.0);
|
||||
|
|
|
@ -18,13 +18,15 @@ impl Demo for LinearGradientRectangle {
|
|||
_world: Option<&HitableList>,
|
||||
_samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
let ny = chunk.ny;
|
||||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
let &mut Chunk {
|
||||
x,
|
||||
y,
|
||||
nx,
|
||||
ny,
|
||||
start_x,
|
||||
start_y,
|
||||
ref mut buffer,
|
||||
} = chunk;
|
||||
|
||||
// -2.0 and 4.0 in lower_left_corner and horizontal respectively
|
||||
// because our canvas is in 2:1 ratio
|
||||
|
|
|
@ -51,13 +51,15 @@ impl Demo for Materials {
|
|||
world: Option<&HitableList>,
|
||||
samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
let ny = chunk.ny;
|
||||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
let &mut Chunk {
|
||||
x,
|
||||
y,
|
||||
nx,
|
||||
ny,
|
||||
start_x,
|
||||
start_y,
|
||||
ref mut buffer,
|
||||
} = chunk;
|
||||
let camera = camera.unwrap();
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
mod defocus_blur;
|
||||
mod dielectric_material;
|
||||
mod diffuse_materials;
|
||||
mod final_scene;
|
||||
mod hitable_sphere;
|
||||
mod linear_gradient_rectangle;
|
||||
mod materials;
|
||||
|
@ -13,6 +14,7 @@ mod surface_normal_sphere;
|
|||
pub use defocus_blur::DefocusBlur;
|
||||
pub use dielectric_material::DielectricMaterial;
|
||||
pub use diffuse_materials::DiffuseMaterials;
|
||||
pub use final_scene::FinalScene;
|
||||
pub use hitable_sphere::HitableSphere;
|
||||
pub use linear_gradient_rectangle::LinearGradientRectangle;
|
||||
pub use materials::Materials;
|
||||
|
@ -35,7 +37,6 @@ use {
|
|||
},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Chunk {
|
||||
x: usize,
|
||||
y: usize,
|
||||
|
|
|
@ -66,13 +66,15 @@ impl Demo for PositionableCamera {
|
|||
world: Option<&HitableList>,
|
||||
samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
let ny = chunk.ny;
|
||||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
let &mut Chunk {
|
||||
x,
|
||||
y,
|
||||
nx,
|
||||
ny,
|
||||
start_x,
|
||||
start_y,
|
||||
ref mut buffer,
|
||||
} = chunk;
|
||||
let camera = camera.unwrap();
|
||||
let world = world.unwrap();
|
||||
let mut rng = rand::thread_rng();
|
||||
|
|
|
@ -29,13 +29,15 @@ impl Demo for SimpleAntialiasing {
|
|||
world: Option<&HitableList>,
|
||||
samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
let ny = chunk.ny;
|
||||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
let &mut Chunk {
|
||||
x,
|
||||
y,
|
||||
nx,
|
||||
ny,
|
||||
start_x,
|
||||
start_y,
|
||||
ref mut buffer,
|
||||
} = chunk;
|
||||
let camera = camera.unwrap();
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
|
|
|
@ -18,14 +18,15 @@ impl Demo for SimpleRectangle {
|
|||
_world: Option<&HitableList>,
|
||||
_samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
let ny = chunk.ny;
|
||||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
|
||||
let &mut Chunk {
|
||||
x,
|
||||
y,
|
||||
nx,
|
||||
ny,
|
||||
start_x,
|
||||
start_y,
|
||||
ref mut buffer,
|
||||
} = chunk;
|
||||
let mut offset = 0;
|
||||
|
||||
for j in start_y..start_y + ny {
|
||||
|
|
|
@ -20,14 +20,15 @@ impl Demo for SimpleSphere {
|
|||
_world: Option<&HitableList>,
|
||||
_samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
let ny = chunk.ny;
|
||||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
|
||||
let &mut Chunk {
|
||||
x,
|
||||
y,
|
||||
nx,
|
||||
ny,
|
||||
start_x,
|
||||
start_y,
|
||||
ref mut buffer,
|
||||
} = chunk;
|
||||
// Usually, lower_left_corner should've been -1.0,-1.0,-1.0 and
|
||||
// horizontal should've been 2.0,0.0,0.0
|
||||
// but we are working with a canvas that is 2:1 in size.
|
||||
|
|
|
@ -19,14 +19,15 @@ impl Demo for SurfaceNormalSphere {
|
|||
_world: Option<&HitableList>,
|
||||
_samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
let ny = chunk.ny;
|
||||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
|
||||
let &mut Chunk {
|
||||
x,
|
||||
y,
|
||||
nx,
|
||||
ny,
|
||||
start_x,
|
||||
start_y,
|
||||
ref mut buffer,
|
||||
} = chunk;
|
||||
// Usually, lower_left_corner should've been -1.0,-1.0,-1.0 and
|
||||
// horizontal should've been 2.0,0.0,0.0
|
||||
// but we are working with a canvas that is 2:1 in size.
|
||||
|
|
|
@ -23,8 +23,7 @@ const HORIZONTAL_PARTITION: usize = 8;
|
|||
fn main() -> Result<(), String> {
|
||||
let sdl_ctx = sdl2::init()?;
|
||||
let video_subsys = sdl_ctx.video()?;
|
||||
|
||||
let (mut width, mut height) = (1280usize, 640usize);
|
||||
let (mut width, mut height): (usize, usize) = (1600, 800);
|
||||
|
||||
let window = video_subsys
|
||||
.window("Ray tracing in a weekend", width as u32, height as u32)
|
||||
|
@ -81,6 +80,7 @@ fn main() -> Result<(), String> {
|
|||
Some(Keycode::Num9) => active_demo = Box::new(demos::DielectricMaterial),
|
||||
Some(Keycode::Num0) => active_demo = Box::new(demos::PositionableCamera),
|
||||
Some(Keycode::Minus) => active_demo = Box::new(demos::DefocusBlur),
|
||||
Some(Keycode::Equals) => active_demo = Box::new(demos::FinalScene),
|
||||
None => unreachable!(),
|
||||
_ => (),
|
||||
};
|
||||
|
|
|
@ -17,3 +17,9 @@ impl Hitable for HitableList {
|
|||
hit_rec
|
||||
}
|
||||
}
|
||||
|
||||
impl HitableList {
|
||||
pub fn push(&mut self, obj: Box<dyn Hitable>) {
|
||||
self.list.push(obj);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user