Added a positionable camera system, Minor fixes
1. Added a positionable camera system. 2. Changed some demo names
This commit is contained in:
parent
75e866a1a0
commit
52c6c76c0d
|
@ -8,17 +8,31 @@ pub struct Camera {
|
|||
}
|
||||
|
||||
impl Camera {
|
||||
pub const fn new(
|
||||
origin: Vec3,
|
||||
horizontal: Vec3,
|
||||
vertical: Vec3,
|
||||
lower_left_corner: Vec3,
|
||||
) -> Self {
|
||||
// vertical_fov is the viewable angle from top->bottom
|
||||
// look_from is basically camera position
|
||||
// look_at is the point where camera is looking
|
||||
// v_up is camera's up vector. i.e. it points upwards from the camera
|
||||
// orthogonal to look_from - look_at vector
|
||||
pub fn new(look_from: Vec3, look_at: Vec3, v_up: Vec3, vertical_fov: f64, aspect: f64) -> Self {
|
||||
// convert degree to radian
|
||||
let angle = vertical_fov * std::f64::consts::PI / 180.0;
|
||||
let half_height = (angle / 2.0).tan();
|
||||
let half_width = aspect * half_height;
|
||||
|
||||
let origin = look_from;
|
||||
let w = (look_from - look_at).unit_vector();
|
||||
let u = v_up.cross(&w).unit_vector();
|
||||
let v = w.cross(&u);
|
||||
|
||||
let lower_left_corner = origin - u * half_width - v * half_height - w;
|
||||
let horizontal = u * half_width * 2.0;
|
||||
let vertical = v * half_height * 2.0;
|
||||
|
||||
Self {
|
||||
origin,
|
||||
lower_left_corner,
|
||||
horizontal,
|
||||
vertical,
|
||||
lower_left_corner,
|
||||
origin,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,12 +46,13 @@ impl Camera {
|
|||
|
||||
impl std::default::Default for Camera {
|
||||
fn default() -> Self {
|
||||
Camera {
|
||||
origin: Vec3::new(0.0, 0.0, 0.0),
|
||||
// Because canvas is in 2:1 ratio
|
||||
horizontal: Vec3::new(4.0, 0.0, 0.0),
|
||||
vertical: Vec3::new(0.0, 2.0, 0.0),
|
||||
lower_left_corner: Vec3::new(-2.0, -1.0, -1.0),
|
||||
}
|
||||
Camera::new(
|
||||
Vec3::new(0.0, 0.0, 0.0),
|
||||
Vec3::new(0.0, 0.0, -1.0),
|
||||
Vec3::new(0.0, 1.0, 0.0),
|
||||
90.0,
|
||||
// 2:1 aspect ratio width:height
|
||||
2.0,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ pub struct DiffuseMaterials;
|
|||
|
||||
impl Demo for DiffuseMaterials {
|
||||
fn name(&self) -> &'static str {
|
||||
"Diffuse Materials"
|
||||
"diffuse-materials"
|
||||
}
|
||||
|
||||
fn render_chunk(&self, chunk: &mut Chunk, samples: u8) {
|
||||
|
|
|
@ -6,7 +6,7 @@ pub struct HitableSphere;
|
|||
|
||||
impl Demo for HitableSphere {
|
||||
fn name(&self) -> &'static str {
|
||||
"Sphere using Hit table"
|
||||
"sphere-using-hit-table"
|
||||
}
|
||||
|
||||
fn render_chunk(&self, chunk: &mut Chunk, _samples: u8) {
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
|
||||
impl Demo for LinearGradientRectangle {
|
||||
fn name(&self) -> &'static str {
|
||||
"Linear Gradient Rectangle"
|
||||
"linear-gradient-rectangle"
|
||||
}
|
||||
|
||||
fn render_chunk(&self, chunk: &mut Chunk, _samples: u8) {
|
||||
|
|
|
@ -3,6 +3,7 @@ mod diffuse_materials;
|
|||
mod hitable_sphere;
|
||||
mod linear_gradient_rectangle;
|
||||
mod materials;
|
||||
mod positionable_camera;
|
||||
mod simple_antialiasing;
|
||||
mod simple_rectangle;
|
||||
mod simple_sphere;
|
||||
|
@ -13,6 +14,7 @@ pub use diffuse_materials::DiffuseMaterials;
|
|||
pub use hitable_sphere::HitableSphere;
|
||||
pub use linear_gradient_rectangle::LinearGradientRectangle;
|
||||
pub use materials::Materials;
|
||||
pub use positionable_camera::PositionableCamera;
|
||||
pub use simple_antialiasing::SimpleAntialiasing;
|
||||
pub use simple_rectangle::SimpleRectangle;
|
||||
pub use simple_sphere::SimpleSphere;
|
||||
|
|
105
src/demos/positionable_camera.rs
Normal file
105
src/demos/positionable_camera.rs
Normal file
|
@ -0,0 +1,105 @@
|
|||
use {
|
||||
crate::{
|
||||
demos::{Chunk, Demo},
|
||||
types::{
|
||||
material::{Dielectric, Lambertian, Metal},
|
||||
Hitable, HitableList, Ray, Sphere, Vec3,
|
||||
},
|
||||
Camera,
|
||||
},
|
||||
rand::Rng,
|
||||
};
|
||||
|
||||
pub struct PositionableCamera;
|
||||
|
||||
impl Demo for PositionableCamera {
|
||||
fn name(&self) -> &'static str {
|
||||
"positionable-camera"
|
||||
}
|
||||
|
||||
fn render_chunk(&self, chunk: &mut Chunk, 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 radius = (std::f64::consts::PI / 4.0).cos();
|
||||
|
||||
let world = HitableList {
|
||||
list: vec![
|
||||
Box::new(Sphere::with_material(
|
||||
Vec3::new(-radius, 0.0, -1.0),
|
||||
radius,
|
||||
Box::new(Lambertian::new(Vec3::new(0.0, 0.0, 1.0))),
|
||||
)),
|
||||
Box::new(Sphere::with_material(
|
||||
Vec3::new(radius, 0.0, -1.0),
|
||||
radius,
|
||||
Box::new(Metal::with_fuzz(Vec3::new(0.5, 0.5, 0.0), 0.2)),
|
||||
)),
|
||||
Box::new(Sphere::with_material(
|
||||
Vec3::new(-3.0 * radius, 0.0, -1.0),
|
||||
radius,
|
||||
Box::new(Dielectric::new(1.5)),
|
||||
)),
|
||||
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))),
|
||||
)),
|
||||
],
|
||||
};
|
||||
|
||||
let camera = Camera::new(
|
||||
Vec3::new(-2.0, 2.0, 1.0),
|
||||
Vec3::new(0.0, 0.0, -1.0),
|
||||
Vec3::new(0.0, 1.0, 0.0),
|
||||
68.0,
|
||||
nx as f64 / ny as f64,
|
||||
);
|
||||
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
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ pub struct SimpleAntialiasing;
|
|||
|
||||
impl Demo for SimpleAntialiasing {
|
||||
fn name(&self) -> &'static str {
|
||||
"A simple antialiasing implementation"
|
||||
"simple-antialiasing"
|
||||
}
|
||||
fn render_chunk(&self, chunk: &mut Chunk, samples: u8) {
|
||||
let x = chunk.x;
|
||||
|
|
|
@ -17,7 +17,6 @@ use {
|
|||
};
|
||||
|
||||
const NUM_SAMPLES: u8 = 100;
|
||||
|
||||
const VERTICAL_PARTITION: usize = 8;
|
||||
const HORIZONTAL_PARTITION: usize = 8;
|
||||
|
||||
|
@ -80,6 +79,7 @@ fn main() -> Result<(), String> {
|
|||
Some(Keycode::Num7) => active_demo = Box::new(demos::DiffuseMaterials),
|
||||
Some(Keycode::Num8) => active_demo = Box::new(demos::Materials),
|
||||
Some(Keycode::Num9) => active_demo = Box::new(demos::DielectricMaterial),
|
||||
Some(Keycode::Num0) => active_demo = Box::new(demos::PositionableCamera),
|
||||
None => unreachable!(),
|
||||
_ => (),
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user