ft: 7: camera class
This commit is contained in:
85
src/camera.rs
Normal file
85
src/camera.rs
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
use std::cmp::max;
|
||||||
|
|
||||||
|
use log::info;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
objects::{hit::Hit, traits::Hittable},
|
||||||
|
ray::Ray,
|
||||||
|
vec3::{Colour, Vec3},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Camera {
|
||||||
|
image_width: u32,
|
||||||
|
image_height: u32,
|
||||||
|
center: Vec3,
|
||||||
|
pixel00_loc: Vec3,
|
||||||
|
pixel_delta_u: Vec3,
|
||||||
|
pixel_delta_v: Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Camera {
|
||||||
|
pub fn new(aspect_ratio: f32, image_width: u32) -> Camera {
|
||||||
|
let image_height = max(1, (image_width as f32 / aspect_ratio) as u32);
|
||||||
|
|
||||||
|
//camera
|
||||||
|
let focal_length = 1.;
|
||||||
|
let viewport_height = 2.;
|
||||||
|
let viewport_width = viewport_height * (image_width as f32 / image_height as f32);
|
||||||
|
let camera_center = Vec3::nil();
|
||||||
|
|
||||||
|
//viewport
|
||||||
|
let viewport_u = Vec3::new(viewport_width as f32, 0., 0.);
|
||||||
|
let viewport_v = Vec3::new(0., -viewport_height as f32, 0.);
|
||||||
|
|
||||||
|
let pixel_delta_u = viewport_u / image_width as f32;
|
||||||
|
let pixel_delta_v = viewport_v / image_height as f32;
|
||||||
|
|
||||||
|
let viewport_upper_left =
|
||||||
|
camera_center - Vec3::new(0., 0., focal_length) - viewport_u / 2 - viewport_v / 2;
|
||||||
|
let pixel00_loc = viewport_upper_left + 0.5 * (pixel_delta_u + pixel_delta_v);
|
||||||
|
|
||||||
|
Camera {
|
||||||
|
image_width: image_width,
|
||||||
|
image_height: image_height,
|
||||||
|
center: camera_center,
|
||||||
|
pixel00_loc: pixel00_loc,
|
||||||
|
pixel_delta_u: pixel_delta_u,
|
||||||
|
pixel_delta_v: pixel_delta_v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render<T: Hittable>(&self, hittables: &Vec<T>) {
|
||||||
|
let mut imgbuf = image::ImageBuffer::new(self.image_width, self.image_height);
|
||||||
|
|
||||||
|
// render
|
||||||
|
for j in 0..self.image_height {
|
||||||
|
info!("{}\tScanlines remaining.", (self.image_height - j));
|
||||||
|
for i in 0..self.image_width {
|
||||||
|
let pixel_center =
|
||||||
|
self.pixel00_loc + (i * self.pixel_delta_u) + (j * self.pixel_delta_v);
|
||||||
|
let ray_dir = pixel_center - self.center;
|
||||||
|
let r = Ray::new(self.center, ray_dir);
|
||||||
|
|
||||||
|
let pixel = imgbuf.get_pixel_mut(i, j);
|
||||||
|
*pixel = self.ray_colour(&hittables, &r).output();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Writing image file...");
|
||||||
|
imgbuf.save("output.png").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ray_colour<T: Hittable>(&self, hittables: &Vec<T>, r: &Ray) -> Colour {
|
||||||
|
let closest = Hit::hit_list(hittables, r);
|
||||||
|
if let Some(hit) = closest {
|
||||||
|
let n = hit.n();
|
||||||
|
return 0.5 * Colour::new(n.x() + 1., n.y() + 1., n.z() + 1.);
|
||||||
|
}
|
||||||
|
|
||||||
|
// background
|
||||||
|
let unit_dir = r.dir().get_unit();
|
||||||
|
let a = 0.5 * (unit_dir.y() + 1.);
|
||||||
|
|
||||||
|
(1.0 - a) * Colour::new(1., 1., 1.) + a * Colour::new(0.5, 0.7, 1.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
70
src/main.rs
70
src/main.rs
@@ -1,78 +1,24 @@
|
|||||||
#![feature(core_float_math)]
|
#![feature(core_float_math)]
|
||||||
|
|
||||||
|
mod camera;
|
||||||
mod objects;
|
mod objects;
|
||||||
mod ray;
|
mod ray;
|
||||||
mod vec3;
|
mod vec3;
|
||||||
|
|
||||||
use core::f32;
|
use crate::camera::Camera;
|
||||||
use std::cmp::max;
|
|
||||||
|
|
||||||
use crate::objects::hit::Hit;
|
|
||||||
use crate::objects::sphere::Sphere;
|
use crate::objects::sphere::Sphere;
|
||||||
use crate::objects::traits::Hittable;
|
|
||||||
use crate::ray::Ray;
|
use crate::ray::Ray;
|
||||||
use crate::vec3::{Colour, Vec3};
|
use crate::vec3::Vec3;
|
||||||
use log::info;
|
|
||||||
use pretty_env_logger;
|
use pretty_env_logger;
|
||||||
|
|
||||||
fn ray_colour<T: Hittable>(hittables: &Vec<T>, r: &Ray) -> Colour {
|
|
||||||
let closest = Hit::hit_list(hittables, r);
|
|
||||||
if let Some(hit) = closest {
|
|
||||||
let n = hit.n();
|
|
||||||
return 0.5 * Colour::new(n.x() + 1., n.y() + 1., n.z() + 1.);
|
|
||||||
}
|
|
||||||
|
|
||||||
// background
|
|
||||||
let unit_dir = r.dir().get_unit();
|
|
||||||
let a = 0.5 * (unit_dir.y() + 1.);
|
|
||||||
|
|
||||||
(1.0 - a) * Colour::new(1., 1., 1.) + a * Colour::new(0.5, 0.7, 1.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
pretty_env_logger::init();
|
pretty_env_logger::init();
|
||||||
|
|
||||||
// setup objects
|
// setup objects
|
||||||
let mut objects = vec![Sphere::new(Vec3::new(0., 0., -1.), 0.5)];
|
let mut world = vec![Sphere::new(Vec3::new(0., 0., -1.), 0.5)];
|
||||||
objects.push(Sphere::new(Vec3::new(0., 0., -0.1), 0.01));
|
world.push(Sphere::new(Vec3::new(0., 0., -0.1), 0.01));
|
||||||
objects.push(Sphere::new(Vec3::new(0., -100.5, -1.), 100.));
|
world.push(Sphere::new(Vec3::new(0., -100.5, -1.), 100.));
|
||||||
|
|
||||||
let aspect_ratio = 16. / 9.;
|
let c = Camera::new(16. / 9., 400);
|
||||||
let image_width = 400;
|
c.render(&world);
|
||||||
let image_height = max(1, (image_width as f32 / aspect_ratio) as u32);
|
|
||||||
|
|
||||||
//camera
|
|
||||||
let focal_length = 1.;
|
|
||||||
let viewport_height = 2.;
|
|
||||||
let viewport_width = viewport_height * (image_width as f32 / image_height as f32);
|
|
||||||
let camera_center = Vec3::nil();
|
|
||||||
|
|
||||||
//viewport
|
|
||||||
let viewport_u = Vec3::new(viewport_width as f32, 0., 0.);
|
|
||||||
let viewport_v = Vec3::new(0., -viewport_height as f32, 0.);
|
|
||||||
|
|
||||||
let pixel_delta_u = viewport_u / image_width as f32;
|
|
||||||
let pixel_delta_v = viewport_v / image_height as f32;
|
|
||||||
|
|
||||||
let viewport_upper_left =
|
|
||||||
camera_center - Vec3::new(0., 0., focal_length) - viewport_u / 2 - viewport_v / 2;
|
|
||||||
let pixel00_loc = viewport_upper_left + 0.5 * (pixel_delta_u + pixel_delta_v);
|
|
||||||
|
|
||||||
let mut imgbuf = image::ImageBuffer::new(image_width, image_height);
|
|
||||||
|
|
||||||
// render
|
|
||||||
for j in 0..image_height {
|
|
||||||
info!("{}\tScanlines remaining.", (image_height - j));
|
|
||||||
for i in 0..image_width {
|
|
||||||
let pixel_center = pixel00_loc + (i * pixel_delta_u) + (j * pixel_delta_v);
|
|
||||||
let ray_dir = pixel_center - camera_center;
|
|
||||||
let r = Ray::new(camera_center, ray_dir);
|
|
||||||
|
|
||||||
let pixel = imgbuf.get_pixel_mut(i, j);
|
|
||||||
*pixel = ray_colour(&objects, &r).output();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("Writing image file...");
|
|
||||||
imgbuf.save("output.png").unwrap();
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user