From cddec468dea75804e19dcc9c067ecb31e4a18b96 Mon Sep 17 00:00:00 2001 From: bijan2005 Date: Sat, 5 Dec 2020 23:22:19 -0500 Subject: [PATCH] Realize the triangle struct doesn't work and completely refactor it --- README.md | 9 +-- src/camera.rs | 10 ++-- src/main.rs | 9 +-- src/object.rs | 2 +- src/object/triangle.rs | 128 ++++++++++++++++++++++++++++------------- src/types.rs | 20 +------ 6 files changed, 107 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index 227dca4..f3f351c 100644 --- a/README.md +++ b/README.md @@ -20,10 +20,11 @@ This list may be changed or extended in the future. - [x] Color mapping on planes - [ ] Triangle objects - [x] Triangle struct - - [ ] Triangle intersection test - - [ ] Triangle normal generation - - [ ] Color mapping on triangles - - [ ] Triangle meshes + - [x] Triangle intersection test + - [x] Triangle normal generation + - [x] Color mapping on triangles + - [x] Triangle mesh struct + - [ ] Triangle mesh intersection test - [ ] Bounding boxes - [ ] Direct lighting - [ ] Point light sources diff --git a/src/camera.rs b/src/camera.rs index ad82583..2c14c0d 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -20,21 +20,21 @@ impl Camera { // Constructs a new camera from a position and viewing direction. pub fn new_(pos: Point3, dir: Vector3, up: Vector3, - focal_length: f32, aspect_ratio: f32, canvas_x: f32, image_x: u32) -> Self { + focal_length: f32, aspect_ratio: f32, canvas_y: f32, image_y: u32) -> Self { let iso = Isometry3::face_towards(&pos, &(pos + dir), &up); Camera { matrix: iso, focal_length: focal_length, - canvas_size: Vector2::new(canvas_x, canvas_x * aspect_ratio), - image_size: Vector2::new(image_x, (image_x as f32 * aspect_ratio) as u32) + canvas_size: Vector2::new(canvas_y * aspect_ratio, canvas_y), + image_size: Vector2::new((image_y as f32 * aspect_ratio) as u32, image_y) } } // Constructs a new camera from a position and viewing direction // (assuming the camera is oriented upright). pub fn new(pos: Point3, dir: Vector3, - focal_length: f32, aspect_ratio: f32, canvas_x: f32, image_x: u32) -> Self - { Camera::new_(pos, dir, Vector3::y(), focal_length, aspect_ratio, canvas_x, image_x) } + focal_length: f32, aspect_ratio: f32, canvas_y: f32, image_y: u32) -> Self + { Camera::new_(pos, dir, Vector3::y(), focal_length, aspect_ratio, canvas_y, image_y) } pub fn pos(&self) -> Point3 { Point3::from(self.matrix.translation.vector) } diff --git a/src/main.rs b/src/main.rs index 2ac682f..723e92f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -52,12 +52,13 @@ fn render(camera: &Camera, scene: &Scene, filename: &str) -> std::io::Result<()> fn main() -> std::io::Result<()> { - let camera = Camera::new(Point3::new(0.0,1.0,0.0), Vector3::new(0.0,0.0,1.0), 1.0, 1.0, 2.0, 500); + let camera = Camera::new(Point3::new(0.0,1.0,0.0), Vector3::new(0.0,0.0,1.0), 1.0, 16.0 / 9.0, 2.0, 720); let scene = vec![ - Object::new(Plane::xz(|x, y| Color::new(y.sin(), x.cos(), 0.0))), - Object::new(Plane::new(Point3::new(0.0, 2.0, 0.0), Vector3::z(), Vector3::x(), |x, y| Color::new(x.sin(), y.cos(), 0.0))) - // Object::new(Sphere::new_solid(0.0, 0.0, 0.0, 3.0, Color::white())) + Object::new(Plane::new(Point3::new(0.0, 0.0, -1.0), Vector3::x(), Vector3::z(), + |x, y| Color::gray(y / 30.0) + )), + Object::new(Sphere::new(0.0, 1.0, 4.0, 1.0, |x, y| Color::new(0.0, x, y))) ]; render(&camera, &scene, "out.ppm") diff --git a/src/object.rs b/src/object.rs index e45ef28..7be17e2 100644 --- a/src/object.rs +++ b/src/object.rs @@ -29,7 +29,7 @@ pub struct Object { } impl Object { - pub fn new(surface: S) -> Self { + pub fn new(surface: impl 'static + Surface) -> Self { Object { surface: Box::new(surface) } } diff --git a/src/object/triangle.rs b/src/object/triangle.rs index 14d54c8..898fc28 100644 --- a/src/object/triangle.rs +++ b/src/object/triangle.rs @@ -6,10 +6,10 @@ use na::geometry::Point3; use crate::types::*; use super::Surface; -pub struct Triangle<'a> { - pub vertex1: &'a Point3, // References to 3 vertices. - pub vertex2: &'a Point3, - pub vertex3: &'a Point3, +pub struct Triangle { + pub v1: usize, // Handles to 3 vertices. + pub v2: usize, + pub v3: usize, area: f32, // Precalculated area for barycentric calculations. @@ -17,9 +17,9 @@ pub struct Triangle<'a> { // Uses barycentric coordinates as input. } -pub struct TriangleMesh<'a> { - pub points: Vec>>, - pub tris: Vec> +pub struct TriangleMesh { + pub points: Vec>, + pub tris: Vec } fn tri_area(a: &Point3, b: &Point3, c: &Point3) -> f32 { @@ -27,48 +27,96 @@ fn tri_area(a: &Point3, b: &Point3, c: &Point3) -> f32 { prlg_area / 2.0 } -impl<'a> Triangle<'a> { - pub fn new(vertex1: &'a Point3, - vertex2: &'a Point3, - vertex3: &'a Point3, - texture: F) -> Self - where F: Fn(f32, f32, f32) -> Color - { - Triangle { - vertex1: vertex1, - vertex2: vertex2, - vertex3: vertex3, - area: tri_area(vertex1, vertex2, vertex3), - texture: Box::new(texture) - } - } - - pub fn new_solid(vertex1: &'a Point3, - vertex2: &'a Point3, - vertex3: &'a Point3, color: Color) -> Self - { Triangle::new(vertex1, vertex2, vertex3, move |_, _, _| color) } +impl Triangle { + fn vertex1<'a>(&self, vertices: &'a Vec>) -> &'a Point3 { &vertices[self.v1] } + fn vertex2<'a>(&self, vertices: &'a Vec>) -> &'a Point3 { &vertices[self.v2] } + fn vertex3<'a>(&self, vertices: &'a Vec>) -> &'a Point3 { &vertices[self.v3] } // Conversion of barycentric coordinates to // a point on the triangle. - pub fn from_bary(&self, t: f32, u: f32, v: f32) -> Point3 { - Point::from(t * self.vertex1.coords + u * self.vertex2.coords + v * self.vertex3.coords) + fn from_bary(&self, vertices: &Vec>, t: f32, u: f32, v: f32) -> Point3 { + Point::from(t * self.vertex1(vertices).coords + u * self.vertex2(vertices).coords + v * self.vertex3(vertices).coords) } // Conversion of a point to barycentric coordinates. - pub fn to_bary(&self, point: Point3) -> (f32, f32, f32) { - let t = tri_area(self.vertex2, self.vertex3, &point) / self.area; - let u = tri_area(self.vertex1, self.vertex3, &point) / self.area; - let v = tri_area(self.vertex1, self.vertex2, &point) / self.area; + fn to_bary(&self, vertices: &Vec>, point: Point3) -> (f32, f32, f32) { + let t = tri_area(self.vertex2(vertices), self.vertex3(vertices), &point) / self.area; + let u = tri_area(self.vertex1(vertices), self.vertex3(vertices), &point) / self.area; + let v = tri_area(self.vertex1(vertices), self.vertex2(vertices), &point) / self.area; (t, u, v) } -} -impl<'a> TriangleMesh<'a> { - pub fn new(points: Vec>>, tris: Vec>) -> Self { - TriangleMesh { - points: points, - tris: tris - } + fn intersect(&self, vertices: &Vec>, ray: Ray) -> Option { + let vect2_1 = self.vertex2(vertices) - self.vertex1(vertices); + let vect3_1 = self.vertex3(vertices) - self.vertex1(vertices); + + let p_vect = ray.direction.cross(&vect3_1); + let det = p_vect.dot(&vect2_1); + + if det.abs() < 1e-5 { return None; } + + let t_vect = ray.origin - self.vertex1(vertices); + let u = t_vect.dot(&p_vect) / det; + + if u < 0.0 || u > 1.0 { return None; } + + let q_vect = t_vect.cross(&vect2_1); + let v = ray.direction.dot(&q_vect) / det; + + if v < 0.0 || (u + v) > 1.0 { return None; } + + let t = vect3_1.dot(&q_vect) / det; + + // Convert from barycentric coordinates + Some(distance(&ray.origin, &self.from_bary(vertices, t, u, v))) + } + + fn normal(&self, vertices: &Vec>, _point: Point3) -> Unit> { + Unit::new_normalize((self.vertex2(vertices) - self.vertex1(vertices)).cross(&(self.vertex3(vertices) - self.vertex1(vertices)))) + } + + fn getcolor(&self, vertices: &Vec>, point: Point3) -> Color { + // Converting back and forth between barycentric coordinates + // like this is terrible, but it's necessary for this object to + // match the interface the other objects use. + let (t, u, v) = self.to_bary(vertices, point); + + (*self.texture)(t, u, v) } } + +impl TriangleMesh { + pub fn new(points: Vec>, tris: Vec<(usize, usize, usize, Box Color>)>) -> Self { + let triangles = tris.into_iter() + .map(|(v1, v2, v3, f)| Triangle { + v1: v1, + v2: v2, + v3: v3, + area: tri_area(&points[v1], &points[v2], &points[v3]), + texture: f + }).collect(); + TriangleMesh { + points: points, + tris: triangles + } + } + + pub fn new_solid(points: Vec>, tris: Vec<(usize, usize, usize)>, color: Color) -> Self { + let triangles = tris.into_iter() + .map(|(v1, v2, v3)| Triangle { + v1: v1, + v2: v2, + v3: v3, + area: tri_area(&points[v1], &points[v2], &points[v3]), + texture: Box::new(move |_, _, _| color) + }).collect(); + TriangleMesh { + points: points, + tris: triangles + } + } + + pub fn singleton(vertex1: Point3, vertex2: Point3, vertex3: Point3, texture: F) -> Self + where F: Fn(f32, f32, f32) -> Color + { TriangleMesh::new(vec![vertex1, vertex2, vertex3], vec![(0, 1, 2, Box::new(texture))]) } diff --git a/src/types.rs b/src/types.rs index 9e14623..5ebc7be 100644 --- a/src/types.rs +++ b/src/types.rs @@ -48,22 +48,8 @@ impl Color { [red, green, blue] } - pub fn black() -> Self { - Color { - red: 0.0, - green: 0.0, - blue: 0.0, + pub fn gray(brightness: f32) -> Self { Color::new(brightness, brightness, brightness) } - _private: () - } - } - pub fn white() -> Self { - Color { - red: 1.0, - green: 1.0, - blue: 1.0, - - _private: () - } - } + pub fn black() -> Self { Color::gray(0.0) } + pub fn white() -> Self { Color::gray(1.0) } }