From 17b7ebfa69b0bf5b0d476b0fa393ff6f6186e187 Mon Sep 17 00:00:00 2001 From: fremag Date: Sun, 28 Jan 2024 11:57:46 +0100 Subject: [PATCH] Chap 15: triangles --- README.md | 7 ++++ img/clover_triangle.png | Bin 0 -> 31902 bytes src/main.rs | 5 ++- src/ray_tracer.rs | 39 ++++++++++++++++++ src/scenes/clover_triangles_scene.rs | 57 +++++++++++++++++++++++++++ src/scenes/mod.rs | 1 + 6 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 img/clover_triangle.png create mode 100644 src/scenes/clover_triangles_scene.rs diff --git a/README.md b/README.md index 2980902..fc63909 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,13 @@ This is a personal project. I'm learning Rust while working my way through Jamis Buck's [The Ray Tracer Challenge](http://raytracerchallenge.com/) +
+Chapter 15: triangles + +![clover_triangles](https://raw.githubusercontent.com/fremag/ray_tracer_rust/main/img/clover_triangles.png) + +
+
Demo #1 diff --git a/img/clover_triangle.png b/img/clover_triangle.png new file mode 100644 index 0000000000000000000000000000000000000000..44f55cbd4081dba568ee720634d022edc5fcaa30 GIT binary patch literal 31902 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 Ag#Z8m literal 0 HcmV?d00001 diff --git a/src/main.rs b/src/main.rs index 765cd61..c3b7a2a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,6 +19,7 @@ use scenes::clover_scene::CloverScene; use scene::Scene; use crate::patterns::pattern::Pattern; use crate::scenes::basic_refraction_scene::BasicRefractionScene; +use crate::scenes::clover_triangles_scene::CloverTriangleScene; use crate::scenes::cone_scene::ConeScene; use crate::scenes::cube_scene::CubeScene; use crate::scenes::cylinder_scene::CylinderScene; @@ -37,8 +38,8 @@ fn main() { } println!("Start..."); - let scene = CloverScene::new(0.0, 0.0, -9.0); - scene.render(800, 600, "e:\\tmp\\clover.ppm"); + let scene = CloverTriangleScene::new(0.0, 0.0, -9.0); + scene.render(800, 600, "e:\\tmp\\clover_triangle.ppm"); println!("Done.") } diff --git a/src/ray_tracer.rs b/src/ray_tracer.rs index 24fbd7f..0709a32 100644 --- a/src/ray_tracer.rs +++ b/src/ray_tracer.rs @@ -3,6 +3,8 @@ use crate::object::{build_cylinder, Object}; use crate::shapes::group::Group; use crate::core::transform::{scaling, translation}; use crate::core::tuple::{point, Tuple, vector}; +use crate::shapes::shape::Shape; +use crate::shapes::triangle::Triangle; pub fn make_cylinder(p1: Tuple, p2: Tuple, radius: Float) -> Object { let v = p2 - p1; @@ -94,3 +96,40 @@ pub fn build_mesh(mesh: &Mesh, r: Float, close_u: bool, close_v: bool) -> Object Object::new_group(group) } + +pub fn build_mesh_tri(mesh: &Mesh, close_u: bool, close_v: bool) -> Object +{ + let mut group = Group::new(); + let mut m = mesh.m; + let mut n = mesh.n; + if !close_u + { + m -= 1; + } + + if ! close_v + { + n -= 1; + } + + for i in 0..n + { + let mut sub_group = Group::new(); + for j in 0..m + { + let p0 = mesh.points[i][j]; + let next_i = (i + 1) % mesh.n; + let next_j = (j + 1) % mesh.m; + let p1 = mesh.points[next_i][next_j]; + let tri1 = Triangle::new(p0, p1, mesh.points[i][next_j]); + let tri2 = Triangle::new(p0, p1, mesh.points[next_i][j]); + let object = Object::new(Shape::Triangle(tri1)); + sub_group.add(object); + let object1 = Object::new(Shape::Triangle(tri2)); + sub_group.add(object1); + } + + group.add( Object::new_group(sub_group)); + } + Object::new_group(group) +} diff --git a/src/scenes/clover_triangles_scene.rs b/src/scenes/clover_triangles_scene.rs new file mode 100644 index 0000000..920c7fc --- /dev/null +++ b/src/scenes/clover_triangles_scene.rs @@ -0,0 +1,57 @@ +use crate::camera::Camera; +use crate::core::math::{Float, PI}; +use crate::core::transform::view_transform; +use crate::core::tuple::{point, Tuple, vector}; +use crate::ray_tracer::{build_mesh_tri, curve_sweep_mesh}; +use crate::scene::Scene; +use crate::world::World; + +pub struct CloverTriangleScene { + from_x: Float, + from_y: Float, + from_z: Float, +} + +impl CloverTriangleScene { + pub fn new(from_x: Float, from_y: Float, from_z: Float + ) -> Self { + Self { + from_x, + from_y, + from_z + } + } +} + +impl Scene for CloverTriangleScene { + fn get_world(&self) -> World { + const R1: Float = 1.0; + const R2: Float = 0.25; + let mut world = Self::init_world(false); + fn path_clover(t: Float) -> Tuple { + let x = R1 * ((2.0 * PI * t).cos() + 2.0 * (2.0 * PI * 2.0 * t).cos()); + let y = R1 * ((2.0 * PI * t).sin() - 2.0 * (2.0 * PI * 2.0 * t).sin()); + let z = 2.0 * R2 * (2.0 * PI * 3.0 * t).sin(); + point(x, y, z) + } + + fn curve_circle(_u: Float, v: Float) -> (Float, Float) { + let x = R2 * (2.0 * PI * v).cos(); + let y = R2 * (2.0 * PI * v).sin(); + (x, y) + } + + let mesh = curve_sweep_mesh(80, 8, path_clover, curve_circle); + let mesh_obj = build_mesh_tri(&mesh, true, true); + world.objects.push(mesh_obj); + world + } + + fn get_camera(&self, h_size: usize, v_size: usize) -> Camera { + let mut camera = Camera::new(h_size, v_size, PI / 3.0); + camera.set_transform(view_transform(point(self.from_x, self.from_y, self.from_z), + point(0.0, 0.0 ,0.0 ), + vector(0.0, 1.0, 0.0))); + camera + } +} diff --git a/src/scenes/mod.rs b/src/scenes/mod.rs index 39c1d67..3346ebd 100644 --- a/src/scenes/mod.rs +++ b/src/scenes/mod.rs @@ -7,3 +7,4 @@ pub mod basic_refraction_scene; pub mod refraction_sphere_scene; pub mod patterns_scene; pub mod stripe_pattern_scene; +pub mod clover_triangles_scene;