Added a positionable camera system, Minor fixes

1. Added a positionable camera system.
2. Changed some demo names
This commit is contained in:
Ishan Jain 2020-03-10 23:40:30 +05:30
parent 75e866a1a0
commit 52c6c76c0d
8 changed files with 142 additions and 20 deletions

View File

@ -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,
)
}
}

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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;

View 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
}
}

View File

@ -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;

View File

@ -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!(),
_ => (),
};