add Camera
This commit is contained in:
parent
5a77b92d9e
commit
59b169507c
|
@ -0,0 +1,86 @@
|
|||
use crate::hittable::HittableList;
|
||||
use crate::types_defined::{Camera, Color, Point, Ray, Vec3};
|
||||
|
||||
impl Camera {
|
||||
pub fn new(
|
||||
image_width: i32,
|
||||
aspect_ratio: f32,
|
||||
viewport_height: f32,
|
||||
camera_center: Point,
|
||||
focal_length: Vec3,
|
||||
) -> Self {
|
||||
let image_height = ((image_width as f32 / aspect_ratio) as i32).max(1);
|
||||
let viewport_width = viewport_height * (image_width as f32 / image_height as f32);
|
||||
|
||||
Camera {
|
||||
image_width,
|
||||
image_height,
|
||||
aspect_ratio,
|
||||
viewport_width,
|
||||
viewport_height,
|
||||
camera_center,
|
||||
focal_length,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(&self, world: &HittableList) -> String {
|
||||
let viewport_u = Vec3::new(self.viewport_width, 0.0, 0.0);
|
||||
// image x--> right
|
||||
// |
|
||||
// y
|
||||
// space: y up , x right , z back, -z front
|
||||
let viewport_v = Vec3::new(0.0, -self.viewport_height, 0.0);
|
||||
// width per pix
|
||||
let viewport_u_delta = viewport_u / (self.image_width as f32);
|
||||
// height per pix
|
||||
let viewport_v_delta = viewport_v / (self.image_height as f32);
|
||||
let viewport_top_left_pixel =
|
||||
self.camera_center + self.focal_length - viewport_u / 2.0 - viewport_v / 2.0;
|
||||
// padding 0.5* delta u/v
|
||||
let viewport_top_left_pixel_center =
|
||||
viewport_top_left_pixel - viewport_u_delta / 2.0 - viewport_v_delta / 2.0;
|
||||
|
||||
let mut img_content = format!("P3\n{} {}\n255\n", self.image_width, self.image_height);
|
||||
|
||||
for j in 0..self.image_height {
|
||||
if j % 10 == 0 {
|
||||
println!("scan line {}/{} ", j + 1, self.image_height);
|
||||
}
|
||||
|
||||
for i in 0..self.image_width {
|
||||
// every pixcel's position
|
||||
let pixel_center = viewport_top_left_pixel_center
|
||||
+ (i as f32 * viewport_u_delta)
|
||||
+ (j as f32 * viewport_v_delta);
|
||||
// Vector(camera, pixcel)
|
||||
let ray_direction = pixel_center - self.camera_center;
|
||||
// ray
|
||||
let r = Ray::new(self.camera_center, ray_direction);
|
||||
// determind color
|
||||
let color = self.ray_color(&r, world);
|
||||
// content
|
||||
img_content.push_str(color.to_color().as_str());
|
||||
img_content.push('\n');
|
||||
}
|
||||
}
|
||||
|
||||
img_content
|
||||
}
|
||||
|
||||
fn ray_color(&self, ray: &Ray, world: &HittableList) -> Vec3 {
|
||||
let hr = world.hit(&ray, 0.0, f32::MAX);
|
||||
if hr.t >= 0.0 {
|
||||
let normal_color = 0.5 * (hr.normal + Point::new(1.0, 1.0, 1.0));
|
||||
return if hr.front_face {
|
||||
normal_color
|
||||
} else {
|
||||
Color::new(1.0, 1.0, 1.0) - normal_color
|
||||
};
|
||||
}
|
||||
// v / |v|
|
||||
let unit_direction = ray.direction / ray.direction.length();
|
||||
let a = 0.5 * (unit_direction.y + 1.0);
|
||||
// return background color.
|
||||
(1.0 - a) * Color::new(1.0, 1.0, 1.0) + a * Color::new(0.5, 0.7, 1.0)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use crate::types_defined::{HitRecord, Ray};
|
||||
use crate::types_defined::{HitRecord, Ray, Vec3};
|
||||
|
||||
pub trait Hittable {
|
||||
fn hit(&self, r: &Ray, t_min: f32, t_max: f32) -> HitRecord;
|
||||
|
@ -8,13 +8,33 @@ pub trait Hittable {
|
|||
pub struct HittableList {
|
||||
pub objects: Vec<Box<dyn Hittable>>
|
||||
}
|
||||
|
||||
|
||||
impl HittableList {
|
||||
pub fn hit(&self, r: &Ray, t_min: f32, t_max: f32) -> Vec<HitRecord> {
|
||||
let mut records = vec![];
|
||||
for object in &self.objects {
|
||||
records.push(object.hit(r, t_min, t_max));
|
||||
pub fn new() -> Self {
|
||||
HittableList { objects: vec![] }
|
||||
}
|
||||
|
||||
pub fn put(&mut self, object: Box<dyn Hittable>) {
|
||||
let _ = &self.objects.push(object);
|
||||
}
|
||||
|
||||
pub fn hit(&self, r: &Ray, t_min: f32, t_max: f32) -> HitRecord {
|
||||
for object in &self.objects {
|
||||
let temp = object.hit(r, t_min, t_max);
|
||||
if temp.t >= 0.0 {
|
||||
return temp
|
||||
}
|
||||
}
|
||||
HitRecord {
|
||||
t: -1.0,
|
||||
normal: Vec3 {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
},
|
||||
front_face: false,
|
||||
}
|
||||
records
|
||||
}
|
||||
}
|
||||
|
||||
|
|
58
src/image.rs
58
src/image.rs
|
@ -1,58 +0,0 @@
|
|||
use crate::hittable::Hittable;
|
||||
use crate::types_defined::{Color, Point, Ray, Sphere, Vec3};
|
||||
|
||||
|
||||
|
||||
pub fn gen_ray_sphere_normal_ppm_p3(width: i32, height: i32, camera_center: Vec3, viewport_top_left_pixel_center: Vec3, viewport_u_delta: Vec3, viewport_v_delta: Vec3) -> String {
|
||||
let mut img_content = format!("P3\n{} {}\n255\n", width, height);
|
||||
|
||||
for j in 0..height {
|
||||
|
||||
if j % 10 == 0 {
|
||||
println!("scan line {}/{} ", j + 1, height);
|
||||
}
|
||||
|
||||
for i in 0..width {
|
||||
// every pixcel's position
|
||||
let pixel_center = viewport_top_left_pixel_center + (i as f32 * viewport_u_delta) + (j as f32 * viewport_v_delta);
|
||||
// Vector(camera, pixcel)
|
||||
let ray_direction = pixel_center - camera_center;
|
||||
// ray
|
||||
let r = Ray::new(camera_center, ray_direction);
|
||||
/*
|
||||
球
|
||||
*/
|
||||
let _sphere_center = Point::new(0.0, 0.0, -1.0);
|
||||
let sphere_radius = -0.5;
|
||||
let sphere = Sphere::new(_sphere_center, sphere_radius);
|
||||
|
||||
// determind color
|
||||
let color = ray_color(&r, sphere);
|
||||
// content
|
||||
img_content.push_str(color.to_color().as_str());
|
||||
img_content.push('\n');
|
||||
}
|
||||
}
|
||||
|
||||
img_content
|
||||
}
|
||||
|
||||
/*
|
||||
ray color functions
|
||||
*/
|
||||
fn ray_color<H: Hittable>(r: &Ray, h: H) -> Color {
|
||||
let hr = h.hit(&r, 0.0, f32::MAX);
|
||||
if hr.t >= 0.0 {
|
||||
let normal_color = 0.5 * (hr.normal + Point::new(1.0, 1.0, 1.0));
|
||||
return if hr.front_face {
|
||||
normal_color
|
||||
} else {
|
||||
Color::new(1.0, 1.0, 1.0) - normal_color
|
||||
}
|
||||
}
|
||||
// v / |v|
|
||||
let unit_direction = r.direction / r.direction.length();
|
||||
let a = 0.5*(unit_direction.y + 1.0);
|
||||
// return background color.
|
||||
(1.0-a)*Color::new(1.0, 1.0, 1.0) + a*Color::new(0.5, 0.7, 1.0)
|
||||
}
|
72
src/main.rs
72
src/main.rs
|
@ -1,53 +1,37 @@
|
|||
use write_file_util::{write_image};
|
||||
|
||||
use crate::image::{gen_ray_sphere_normal_ppm_p3};
|
||||
use crate::types_defined::{Point, Vec3};
|
||||
mod image;
|
||||
mod write_file_util;
|
||||
mod vec3;
|
||||
mod ray;
|
||||
use crate::hittable::HittableList;
|
||||
use crate::types_defined::{Camera, Point, Sphere, Vec3};
|
||||
use write_file_util::write_image;
|
||||
mod camera;
|
||||
mod color;
|
||||
mod hittable;
|
||||
mod ray;
|
||||
mod sphere;
|
||||
mod types_defined;
|
||||
mod color;
|
||||
mod vec3;
|
||||
mod write_file_util;
|
||||
|
||||
fn main() {
|
||||
ray_sphere_normal_scene_render();
|
||||
camera_render();
|
||||
}
|
||||
|
||||
fn camera_render() {
|
||||
let camera = Camera::new(
|
||||
800,
|
||||
16.0 / 9.0,
|
||||
2.0,
|
||||
Point::new(0.0, 0.0, 0.0),
|
||||
Vec3::new(0.0, 0.0, -1.0),
|
||||
);
|
||||
// world
|
||||
// world objects(spheres)
|
||||
let mut world = HittableList::new();
|
||||
world.put(Box::new(Sphere::new(Point::new(0.0, 0.0, -1.0), 0.5)));
|
||||
world.put(Box::new(Sphere::new(Point::new(0.1, -100.0, -0.0), 100.0)));
|
||||
world.put(Box::new(Sphere::new(Point::new(-0.5, 0.2, -0.5), 0.2)));
|
||||
|
||||
fn ray_sphere_normal_scene_render() {
|
||||
let aspect_ratio = 16.0/9.0;
|
||||
let image_width = 400;
|
||||
// aleast 1px
|
||||
let image_height = ((image_width as f32 / aspect_ratio) as i32).max(1);
|
||||
|
||||
let viewport_height = 2.0;
|
||||
let viewport_width = viewport_height * (image_width as f32 / image_height as f32);
|
||||
|
||||
println!("set image({},{}), viewport({},{})", image_width, image_height, viewport_width, viewport_height);
|
||||
let viewport_u = Vec3::new(viewport_width, 0.0, 0.0);
|
||||
// image x--> right
|
||||
// |
|
||||
// y
|
||||
// space: y up , x right , z back, -z front
|
||||
let viewport_v = Vec3::new(0.0, -viewport_height, 0.0);
|
||||
|
||||
// width per pix
|
||||
let viewport_u_delta = viewport_u / (image_width as f32);
|
||||
// height per pix
|
||||
let viewport_v_delta = viewport_v / (image_height as f32);
|
||||
|
||||
// camerea position
|
||||
let camera_center = Point::new(0.0, 0.0, 0.0);
|
||||
// -z 1.0 viewport to camera
|
||||
let focal_length = Vec3::new(0.0, 0.0, -1.0);
|
||||
// camera position --> viewport center ---> top center --> top left
|
||||
let viewport_top_left_pixel = camera_center + focal_length - viewport_u / 2.0 - viewport_v / 2.0;
|
||||
// padding 0.5* delta u/v
|
||||
let viewport_top_left_pixel_center = viewport_top_left_pixel - viewport_u_delta / 2.0 - viewport_v_delta / 2.0;
|
||||
|
||||
let ppm_content = gen_ray_sphere_normal_ppm_p3(image_width, image_height, camera_center, viewport_top_left_pixel_center, viewport_u_delta, viewport_v_delta);
|
||||
|
||||
write_image(ppm_content, "./target/ray_sphere_normal_scene_render.ppm".to_string())
|
||||
let ppm_content = camera.render(&world);
|
||||
write_image(
|
||||
ppm_content,
|
||||
"./target/ray_sphere_normal_scene_render.ppm".to_string(),
|
||||
)
|
||||
}
|
|
@ -43,3 +43,4 @@ impl hittable::Hittable for Sphere {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ fn: P(t) = t*b
|
|||
#[derive(Debug)]
|
||||
pub struct Ray {
|
||||
pub point: Point,
|
||||
pub direction: Vec3
|
||||
pub direction: Vec3,
|
||||
}
|
||||
|
||||
pub struct HitRecord {
|
||||
|
@ -28,7 +28,15 @@ pub struct HitRecord {
|
|||
pub front_face: bool,
|
||||
}
|
||||
|
||||
|
||||
pub struct Camera {
|
||||
pub image_width: i32,
|
||||
pub image_height: i32,
|
||||
pub aspect_ratio: f32,
|
||||
pub viewport_width: f32,
|
||||
pub viewport_height: f32,
|
||||
pub camera_center: Point,
|
||||
pub focal_length: Vec3,
|
||||
}
|
||||
|
||||
/*
|
||||
/////////////
|
||||
|
|
Loading…
Reference in New Issue