diff --git a/src/camera.rs b/src/camera.rs index 38b3426..e9c0538 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,10 +1,14 @@ +use std::fs::File; +use std::io::{BufWriter}; + use crate::hittable::HittableList; use crate::math_utils::clamp; +use crate::ppm_writer::PPMWriter; use crate::types_defined::{Camera, Color, Point, Ray, Vec3}; use rand::rngs::ThreadRng; use rand::{Rng, thread_rng}; -impl Camera { +impl<'a> Camera<'a> { pub fn new( image_width: i32, aspect_ratio: f32, @@ -12,7 +16,8 @@ impl Camera { camera_center: Point, focal_length: Vec3, sample_times: i8, - reflect_depth: i8 + reflect_depth: i8, + ppm_file_writer: &'a mut PPMWriter> ) -> 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); @@ -48,11 +53,12 @@ impl Camera { viewport_top_left_pixel_center, sample_times, reflect_depth, + ppm_file_writer } } - pub fn render(&self, world: &HittableList) -> String { - let mut img_content = format!("P3\n{} {}\n255\n", self.image_width, self.image_height); + pub fn render(&mut self, world: &HittableList) { + // 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 { @@ -63,7 +69,7 @@ impl Camera { // color let mut color = Color::new(0.0, 0.0, 0.0); let rng = &mut thread_rng(); - for s in 0..self.sample_times { + for _ in 0..self.sample_times { let bias = self.random_square(rng); let pix_sample = self.viewport_top_left_pixel_center + (i as f32 + bias.x) * self.viewport_u_delta @@ -82,13 +88,16 @@ impl Camera { clamp(color.z, 0.0, 1.0), ); + self.ppm_file_writer.write(color.to_color()); + + // content - img_content.push_str(color_clamped.to_color().as_str()); - img_content.push('\n'); + // img_content.push_str(&color_clamped.to_color_str().as_str()); + // img_content.push('\n'); } } - img_content + // img_content } fn ray_color(&self, ray: &Ray, depth: i8, world: &HittableList) -> Vec3 { diff --git a/src/color.rs b/src/color.rs index 5f7a8be..251199d 100644 --- a/src/color.rs +++ b/src/color.rs @@ -1,7 +1,10 @@ use crate::types_defined::Color; impl Color { - pub fn to_color(self) -> String { + pub fn to_color(self) -> Self { + return Color::new(self.x * 256.0 , self.y * 256.0, self.z * 256.0); + } + pub fn to_color_str(self) -> String { return format!("{} {} {}\n", (self.x * 256.0) as u8, (self.y * 256.0) as u8, (self.z * 256.0) as u8); } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 88871a3..9cd0a09 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,9 @@ +use std::fs::File; +use std::io::BufWriter; + use crate::hittable::HittableList; +use crate::ppm_writer::PPMWriter; use crate::types_defined::{Camera, Point, Sphere, Vec3}; -use write_file_util::write_image; mod camera; mod color; mod hittable; @@ -10,20 +13,35 @@ mod types_defined; mod vec3; mod write_file_util; mod math_utils; +mod ppm_writer; fn main() { camera_render(); } fn camera_render() { - let camera = Camera::new( - 400, + + let width: i32 = 400; + let height: i32 = 200; + let pw_r = PPMWriter::new( + BufWriter::new(File::create("./target/ray_sphere_normal_scene_render.ppm").unwrap()), + width, height); + if let Err(e) = pw_r { + println!("创建文件报错:{}", e); + return; + } + let pw = &mut pw_r.unwrap(); + + + let mut camera: Camera = Camera::new( + width, 16.0 / 9.0, 2.0, Point::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, -1.0), - 100, - 50 + 50, + 50, + pw ); // world // world objects(spheres) @@ -34,9 +52,9 @@ fn camera_render() { world.put(Box::new(Sphere::new(Point::new(0.0, -100.0, -1.0), 100.0))); world.put(Box::new(Sphere::new(Point::new(-0.5, 0.2, -0.5), 0.4))); - let ppm_content = camera.render(&world); - write_image( - ppm_content, - "./target/ray_sphere_normal_scene_render.ppm".to_string(), - ) + camera.render(&world); + // write_image( + // ppm_content, + // "".to_string(), + // ) } diff --git a/src/ppm_writer.rs b/src/ppm_writer.rs new file mode 100644 index 0000000..5caee1f --- /dev/null +++ b/src/ppm_writer.rs @@ -0,0 +1,36 @@ +use std::io::{BufWriter, Write, Result}; + +use crate::types_defined::Color; + +pub struct PPMWriter { + writter: BufWriter +} + +impl PPMWriter { + /// 创建新的 PPM 写入器 + /// + /// 参数: + /// writer: 实现 Write 的目标 + /// width: 图像宽度 + /// height: 图像高度 + pub fn new(mut inner: W, width: i32, height: i32) -> Result { + // 写入 PPM 头 (P6 二进制格式) + let header = format!("P6\n{} {}\n255\n", width, height); + inner.write_all(header.as_bytes())?; + + Ok(PPMWriter { writter: BufWriter::new(inner) }) + } + + /// 写入单个像素 (高性能实现) + #[inline] + pub fn write(&mut self, color: Color) -> Result<()> { + // 直接写入字节数组避免额外内存分配 + let bytes = [color.x as u8, color.y as u8, color.z as u8]; + self.writter.write_all(&bytes) + } + + /// 完成写入并刷新缓冲区 + pub fn finish(mut self) -> Result<()> { + self.writter.flush() + } +} \ No newline at end of file diff --git a/src/types_defined.rs b/src/types_defined.rs index 01b784c..b51b585 100644 --- a/src/types_defined.rs +++ b/src/types_defined.rs @@ -1,8 +1,10 @@ +use std::{fs::File, io::{BufWriter, Write}}; + +use crate::ppm_writer::PPMWriter; + /* * [3] */ -use crate::hittable::Hittable; - #[derive(Debug, Clone, Copy, PartialEq)] pub struct Vec3 { pub x: f32, @@ -28,7 +30,7 @@ pub struct HitRecord { pub front_face: bool, } -pub struct Camera { +pub struct Camera<'a> { pub image_width: i32, pub image_height: i32, pub aspect_ratio: f32, @@ -44,7 +46,10 @@ pub struct Camera { // sample times pub sample_times: i8, - pub reflect_depth: i8 + pub reflect_depth: i8, + + // writer + pub ppm_file_writer: &'a mut PPMWriter> } /*