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 {
|
pub trait Hittable {
|
||||||
fn hit(&self, r: &Ray, t_min: f32, t_max: f32) -> HitRecord;
|
fn hit(&self, r: &Ray, t_min: f32, t_max: f32) -> HitRecord;
|
||||||
|
@ -8,13 +8,33 @@ pub trait Hittable {
|
||||||
pub struct HittableList {
|
pub struct HittableList {
|
||||||
pub objects: Vec<Box<dyn Hittable>>
|
pub objects: Vec<Box<dyn Hittable>>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl HittableList {
|
impl HittableList {
|
||||||
pub fn hit(&self, r: &Ray, t_min: f32, t_max: f32) -> Vec<HitRecord> {
|
pub fn new() -> Self {
|
||||||
let mut records = vec![];
|
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 {
|
for object in &self.objects {
|
||||||
records.push(object.hit(r, t_min, t_max));
|
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::hittable::HittableList;
|
||||||
|
use crate::types_defined::{Camera, Point, Sphere, Vec3};
|
||||||
use crate::image::{gen_ray_sphere_normal_ppm_p3};
|
use write_file_util::write_image;
|
||||||
use crate::types_defined::{Point, Vec3};
|
mod camera;
|
||||||
mod image;
|
mod color;
|
||||||
mod write_file_util;
|
|
||||||
mod vec3;
|
|
||||||
mod ray;
|
|
||||||
mod hittable;
|
mod hittable;
|
||||||
|
mod ray;
|
||||||
mod sphere;
|
mod sphere;
|
||||||
mod types_defined;
|
mod types_defined;
|
||||||
mod color;
|
mod vec3;
|
||||||
|
mod write_file_util;
|
||||||
|
|
||||||
fn main() {
|
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 ppm_content = camera.render(&world);
|
||||||
let aspect_ratio = 16.0/9.0;
|
write_image(
|
||||||
let image_width = 400;
|
ppm_content,
|
||||||
// aleast 1px
|
"./target/ray_sphere_normal_scene_render.ppm".to_string(),
|
||||||
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())
|
|
||||||
}
|
}
|
|
@ -43,3 +43,4 @@ impl hittable::Hittable for Sphere {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ fn: P(t) = t*b
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Ray {
|
pub struct Ray {
|
||||||
pub point: Point,
|
pub point: Point,
|
||||||
pub direction: Vec3
|
pub direction: Vec3,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct HitRecord {
|
pub struct HitRecord {
|
||||||
|
@ -28,7 +28,15 @@ pub struct HitRecord {
|
||||||
pub front_face: bool,
|
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