diff --git a/game/src/engine/math.rs b/game/src/engine/math.rs index cc358d3..36d6606 100644 --- a/game/src/engine/math.rs +++ b/game/src/engine/math.rs @@ -11,11 +11,13 @@ impl V3 { Self(v, v, v) } + /// See https://en.wikipedia.org/wiki/3D_projection#Mathematical_formula + /// for details on the implementation. pub fn project_2d(&self, camera_pos: V3) -> V2 { - // V2(self.0 / self.2, self.1 / self.2) + let a = *self; let c = camera_pos; - let d = *self - c; - let e = V3(0.0, 0.0, 0.0) - c; + let d = a - c; + let e = (camera_pos + V3(0.0, 0.0, 1.0)) - c; V2(e.2 / d.2 * d.0 + e.0, e.2 / d.2 * d.1 + e.1) } @@ -32,7 +34,7 @@ impl V3 { } pub fn len(&self) -> f64 { - f64::sqrt(self.0.powi(2) + self.1.powi(2) + self.2.powi(2)) + (self.0.powi(2) + self.1.powi(2) + self.2.powi(2)).sqrt() } pub fn unit(&self) -> Self { @@ -51,6 +53,10 @@ impl V3 { pub fn distance(&self, rhs: Self) -> f64 { (*self - rhs).len() } + + pub fn angle(&self, rhs: Self) -> f64 { + (self.dot(rhs) / (self.len() * rhs.len())).acos() + } } impl Add for V3 { diff --git a/game/src/engine/mod.rs b/game/src/engine/mod.rs index 91f2d3f..64c5ddf 100644 --- a/game/src/engine/mod.rs +++ b/game/src/engine/mod.rs @@ -3,7 +3,6 @@ mod error; mod game; mod math; -mod r3d; mod scene; mod sdl_io; mod shapes; @@ -11,7 +10,6 @@ mod shapes; pub use error::*; pub use game::*; pub use math::*; -pub use r3d::*; pub use scene::*; pub use sdl_io::*; pub use shapes::*; diff --git a/game/src/engine/r3d.rs b/game/src/engine/r3d.rs deleted file mode 100644 index 3ba07d4..0000000 --- a/game/src/engine/r3d.rs +++ /dev/null @@ -1,81 +0,0 @@ -use crate::engine::{game::Renderer, Color, Shape, Triangle2, Triangle3, V2, V3}; - -pub struct R3d<'r, R: Renderer> { - r: &'r mut R, - triangle_buffer: Vec, - camera_pos: V3, -} - -impl<'r, R: Renderer> R3d<'r, R> { - pub fn new(r: &'r mut R, camera_pos: V3) -> Self { - Self { - r, - triangle_buffer: Vec::new(), - camera_pos, - } - } - - pub fn draw_line(&mut self, from: V3, to: V3, color: Color) { - self.r.draw_line( - from.project_2d(self.camera_pos), - to.project_2d(self.camera_pos), - color, - ); - } - - pub fn draw_triangle(&mut self, triangle: Triangle3, color: Color) { - let triangle = triangle - .translate(self.camera_pos) - .project_2d(self.camera_pos); - - self.r.draw_line(triangle.0, triangle.1, color); - self.r.draw_line(triangle.1, triangle.2, color); - self.r.draw_line(triangle.2, triangle.0, color); - } - - pub fn draw_shape(&mut self, pos: V3, shape: &Shape, outline_color: Color, fill_color: Color) { - self.triangle_buffer.clear(); - self.triangle_buffer.extend( - shape - .faces() - .map(|tri| tri.translate(pos).project_2d(self.camera_pos)), - ); - - self.r.draw_triangles(&self.triangle_buffer, fill_color); - - for face in shape.faces() { - if face.normal().dot(face.0 - self.camera_pos + pos) >= 0.0 { - continue; - } - // let pxyz = face.middle() + face.normal(); - // self.draw_line( - // face.middle() + pos, - // face.middle() + (face.1 - face.0).unit() * 0.02 + pos, - // Color::HEX(0xffaa00), - // ); - // self.draw_line( - // face.middle() + pos, - // face.middle() + (face.2 - face.1).unit() * 0.02 + pos, - // Color::HEX(0x00ffaa), - // ); - // self.draw_line( - // face.middle() + pos, - // face.middle() + (face.0 - face.2).unit() * 0.02 + pos, - // Color::HEX(0xaa00ff), - // ); - // self.draw_line(face.middle() + pos, pxyz + pos, Color::HEX(0xffffff)); - - // self.draw_triangle(face.translate(pos - CAMERA_POS), outline_color); - self.r.draw_line( - (face.0 + pos).project_2d(self.camera_pos), - (face.1 + pos).project_2d(self.camera_pos), - outline_color, - ); - self.r.draw_line( - (face.2 + pos).project_2d(self.camera_pos), - (face.0 + pos).project_2d(self.camera_pos), - outline_color, - ); - } - } -} diff --git a/game/src/engine/scene.rs b/game/src/engine/scene.rs index dd0e460..b4fc035 100644 --- a/game/src/engine/scene.rs +++ b/game/src/engine/scene.rs @@ -1,72 +1,60 @@ +use std::f64::consts::PI; + use crate::engine::{Color, Renderer, Shape, Triangle3, V3}; -pub struct DrawnTriangle { - triangle: Triangle3, - outline_color: Color, - fill_color: Color, -} - pub struct Scene { - objects: Vec, + tris: Vec<(Triangle3, V3, Color, Color)>, } impl Scene { pub fn new() -> Self { - Self { - objects: Vec::new(), - } + Self { tris: Vec::new() } } - pub fn render(&mut self, r: &mut R, camera_pos: V3, camera_rot: V3) { + pub fn render(&mut self, r: &mut R, camera_pos: V3) { let mut indices_with_scores = self - .objects + .tris .iter() .enumerate() - .map(|(i, object)| { - let mut point_scores = object.triangle.points().map(|p| p.distance(camera_pos)); - point_scores.sort_by(|a, b| a.total_cmp(b)); + .map(|(i, (tri, ..))| { + let mut p_scores = [tri.0, tri.1, tri.2].map(|p| (camera_pos - p).len()); - (i, point_scores[0]) + p_scores.sort_by(|a, b| a.total_cmp(b)); + + let score = p_scores[0] * p_scores[1]; + (i, score) }) .rev() .collect::>(); indices_with_scores.sort_by(|a, b| b.1.total_cmp(&a.1)); - for (i, _) in indices_with_scores { - let object = &self.objects[i]; - let tri3 = object - .triangle - .translate(camera_pos * -1.0) - .rotate(camera_rot); + 'render_tri_loop: for (i, _) in indices_with_scores { + let (tri3, normal, outline_color, fill_color) = &self.tris[i]; - // check if behind camera - // TODO: doesn't take camera_pos or camera_rot into accout - if !(tri3.0 .2 >= 0.0 && tri3.1 .2 >= 0.0 && tri3.2 .2 >= 0.0) { + for v in [tri3.0, tri3.1, tri3.2] { + if v.2 < camera_pos.2 { + continue 'render_tri_loop; + } + } + + if normal.dot(camera_pos - tri3.0) < 0.0 { continue; } - if tri3.normal().dot(tri3.0 - camera_pos) >= 0.0 { - continue; - } + let tri2 = tri3.project_2d(camera_pos); - let tri2 = tri3 - .translate(V3(0.0, 0.0, -1.0)) - .project_2d(V3(0.0, 0.0, -1.0)); - - r.draw_triangle(tri2.clone(), object.fill_color); - r.draw_line(tri2.0, tri2.1, object.outline_color); - r.draw_line(tri2.0, tri2.2, object.outline_color); + r.draw_triangle(tri2.clone(), *fill_color); + r.draw_line(tri2.0, tri2.1, *outline_color); + r.draw_line(tri2.0, tri2.2, *outline_color); } } pub fn draw_shape(&mut self, pos: V3, shape: &Shape, outline_color: Color, fill_color: Color) { for triangle in shape.faces() { - self.objects.push(DrawnTriangle { - triangle: triangle.translate(pos), - outline_color, - fill_color, - }) + let tri = triangle.translate(pos); + let normal = tri.normal(); + self.tris.push((tri, normal, outline_color, fill_color)) } } } diff --git a/game/src/main.rs b/game/src/main.rs index 06843da..6667c69 100644 --- a/game/src/main.rs +++ b/game/src/main.rs @@ -231,7 +231,7 @@ impl engine::Game for Game { for object in &self.objects { object.render(&mut scene); } - scene.render(r, self.camera_pos, V3(0.0, 0.0, 0.0)); + scene.render(r, self.camera_pos); } fn event(&mut self, event: engine::Event) { diff --git a/simul/src/main.rs b/simul/src/main.rs index 44a4b6a..70e2cc7 100644 --- a/simul/src/main.rs +++ b/simul/src/main.rs @@ -220,7 +220,7 @@ impl MotionDevice { } fn main() { - let mut reader = csv::Reader::from_path("assets/inputs_moving.csv").unwrap(); + let mut reader = csv::Reader::from_path("assets/inputs_still.csv").unwrap(); let mut measurements = Vec::::new(); for entry in reader.deserialize::() { let entry: Measurement = entry.unwrap();