6.1/6.1.Shading with Surface Normals
This commit is contained in:
parent
dca286296c
commit
3d835bcf63
79
src/image.rs
79
src/image.rs
|
@ -10,6 +10,41 @@ impl Color {
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// determind color
|
||||
let color = ray_color_at_sphere_normal(&r, _sphere_center, sphere_radius);
|
||||
// content
|
||||
img_content.push_str(color.to_color().as_str());
|
||||
img_content.push('\n');
|
||||
}
|
||||
}
|
||||
|
||||
img_content
|
||||
}
|
||||
|
||||
|
||||
pub fn gen_ray_sphere_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);
|
||||
|
||||
|
@ -85,9 +120,51 @@ fn hit_sphere(r: &Ray, sphere_center: Point, sphere_radius: f32) -> bool {
|
|||
}
|
||||
|
||||
|
||||
fn hit_sphere_normal(r: &Ray, sphere_center: Point, sphere_radius: f32) -> f32 {
|
||||
let a: f32 = r.direction.length_squared();
|
||||
let h = r.direction.dot(sphere_center - r.point);
|
||||
// let b = -2.0 * r.direction.dot(sphere_center - r.point);
|
||||
let c = (sphere_center - r.point).length_squared() - sphere_radius * sphere_radius;
|
||||
|
||||
let discriminant = h*h - a*c;
|
||||
|
||||
// // 两个焦点
|
||||
let disc_sqrt = discriminant.sqrt();
|
||||
let near = (h - disc_sqrt) / a;
|
||||
let far = (h + disc_sqrt) / a;
|
||||
|
||||
// 射线起点可能在球内的情况
|
||||
if near >= 0.0 && far >= 0.0 {
|
||||
return near.min(far);
|
||||
} else if near > 0.0 {
|
||||
return near;
|
||||
} else if far > 0.0 {
|
||||
return far;
|
||||
} else {
|
||||
return -1.0
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
get color of this ray; background
|
||||
ray color functions
|
||||
*/
|
||||
fn ray_color_at_sphere_normal(r: &Ray, sphere_center: Point, sphere_radius: f32) -> Color {
|
||||
|
||||
let t = hit_sphere_normal(r, sphere_center, sphere_radius);
|
||||
if t >= 0.0 {
|
||||
let inter_point = r.at(t);
|
||||
// 单位向量
|
||||
let n = inter_point / inter_point.dot(inter_point);
|
||||
// 法向量也是 -1~1 +1再x0.5让他落到颜色的区间
|
||||
return 0.5 * (n - sphere_center + Point::new(1.0, 1.0, 1.0))
|
||||
}
|
||||
|
||||
// v / |v|
|
||||
let unit_direction = r.direction / r.direction.length();
|
||||
let a = 0.5*(unit_direction.y + 1.0);
|
||||
return (1.0-a)*Color::new(1.0, 1.0, 1.0) + a*Color::new(0.5, 0.7, 1.0);
|
||||
}
|
||||
|
||||
fn ray_color_at_sphere(r: &Ray, sphere_center: Point, sphere_radius: f32) -> Color {
|
||||
|
||||
// return RED if hit sphere
|
||||
|
|
40
src/main.rs
40
src/main.rs
|
@ -4,7 +4,7 @@ use vec3::{Vec3};
|
|||
use point::{Point};
|
||||
use ray::{Ray};
|
||||
|
||||
use crate::image::gen_ray_sphere_ppm_p3;
|
||||
use crate::image::{gen_ray_sphere_normal_ppm_p3, gen_ray_sphere_ppm_p3};
|
||||
|
||||
mod image;
|
||||
mod write_file_util;
|
||||
|
@ -19,9 +19,47 @@ fn main() {
|
|||
println!("==================================");
|
||||
ray_sphere_scene_render();
|
||||
println!("==================================");
|
||||
ray_sphere_normal_scene_render();
|
||||
println!("==================================");
|
||||
}
|
||||
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
fn ray_sphere_scene_render() {
|
||||
let aspect_ratio = 16.0/9.0;
|
||||
let image_width = 400;
|
||||
|
|
Loading…
Reference in New Issue