From dca286296c64d566f2418e2826a9be27b22cf771 Mon Sep 17 00:00:00 2001 From: dengqn Date: Fri, 1 Aug 2025 21:50:43 +0800 Subject: [PATCH] 5.Adding a Sphere --- src/image.rs | 76 +++++++++++++++++++++++++++++++++++++++++++++++----- src/main.rs | 41 ++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 6 deletions(-) diff --git a/src/image.rs b/src/image.rs index f18b0bf..cb0df1f 100644 --- a/src/image.rs +++ b/src/image.rs @@ -1,4 +1,4 @@ -use crate::{ray::Ray, vec3::{self, Vec3}}; +use crate::{point::Point, ray::Ray, vec3::{self, Vec3}}; pub type Color = vec3::Vec3; @@ -10,11 +10,15 @@ impl Color { } } -pub fn gen_ray_ppm_p3(width: i32, height: i32, camera_center: Vec3, viewport_top_left_pixel_center: Vec3, viewport_u_delta: Vec3, viewport_v_delta: Vec3) -> String { +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); for j in 0..height { - println!("scan line {}/{} ", j + 1, 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); @@ -22,9 +26,15 @@ pub fn gen_ray_ppm_p3(width: i32, height: i32, camera_center: Vec3, viewport_top let ray_direction = pixel_center - camera_center; // ray let r = Ray::new(camera_center, ray_direction); - // determind color - let color = ray_color(r); + /* + 球 + */ + let _sphere_center = Point::new(0.0, 0.0, -1.0); + let sphere_radius = 0.5; + + // determind color + let color = ray_color_at_sphere(&r, _sphere_center, sphere_radius); // content img_content.push_str(color.to_color().as_str()); img_content.push('\n'); @@ -34,10 +44,64 @@ pub fn gen_ray_ppm_p3(width: i32, height: i32, camera_center: Vec3, viewport_top img_content } + +pub fn gen_ray_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); + // determind color + let color = ray_color(&r); + // content + img_content.push_str(color.to_color().as_str()); + img_content.push('\n'); + } + } + + img_content +} + + +/* +b^ - 4ac > 0 : 2 交点; = 0:1交点;< 0 : 无交点 +*/ +fn hit_sphere(r: &Ray, sphere_center: Point, sphere_radius: f32) -> bool { + let a = r.direction.dot(r.direction); + let b_sqrt = (-2.0 * (r.direction.dot(sphere_center - r.point))).powi(2); + let c = (sphere_center - r.point).dot(sphere_center - r.point) - sphere_radius.powi(2); + + return b_sqrt - 4.0 * a * c >= 0.0; +} + + /* get color of this ray; background */ -fn ray_color(r: Ray) -> Color { +fn ray_color_at_sphere(r: &Ray, sphere_center: Point, sphere_radius: f32) -> Color { + + // return RED if hit sphere + if hit_sphere(r, sphere_center, sphere_radius) { + return Color::new(0.4, 0.4, 0.2); + } + + // 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(r: &Ray) -> Color { // v / |v| let unit_direction = r.direction / r.direction.length(); let a = 0.5*(unit_direction.y + 1.0); diff --git a/src/main.rs b/src/main.rs index 1a15395..1f63241 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,8 @@ use vec3::{Vec3}; use point::{Point}; use ray::{Ray}; +use crate::image::gen_ray_sphere_ppm_p3; + mod image; mod write_file_util; mod vec3; @@ -15,6 +17,45 @@ fn main() { println!("=================================="); ray_scene_render(); println!("=================================="); + ray_sphere_scene_render(); + println!("=================================="); +} + + +fn ray_sphere_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_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_scene_render.ppm".to_string()) }