From 98d5b3c5e41e6b60413b5125e34a3737712c0eef Mon Sep 17 00:00:00 2001 From: Thomas Forgione Date: Mon, 2 Jul 2018 11:35:12 +0200 Subject: [PATCH 1/5] Cleaner verbosity set --- src/programs/viewer.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/programs/viewer.rs b/src/programs/viewer.rs index 76add46..f040fb6 100644 --- a/src/programs/viewer.rs +++ b/src/programs/viewer.rs @@ -53,9 +53,7 @@ fn main() { .get_matches(); // Set verbose flag - verbose_log::log::VERBOSE.with(|verbose| { - *verbose.borrow_mut() = matches.occurrences_of("verbose") > 0; - }); + verbose_log::set(matches.occurrences_of("verbose") > 0); use std::f64::{MIN, MAX}; let mut bbox = BoundingBox3::new( From 3172a0c58e635a11e8517466e51565857da542ef Mon Sep 17 00:00:00 2001 From: Thomas Forgione Date: Tue, 10 Jul 2018 17:43:37 +0200 Subject: [PATCH 2/5] Press enter to log the camera position --- src/programs/viewer.rs | 45 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/src/programs/viewer.rs b/src/programs/viewer.rs index f040fb6..c9843f7 100644 --- a/src/programs/viewer.rs +++ b/src/programs/viewer.rs @@ -14,9 +14,12 @@ use glium::Display; use glium::glutin; use glium::glutin::{EventsLoop, WindowBuilder}; -use glium::glutin::Event; -use glium::glutin::WindowEvent; -use glium::glutin::VirtualKeyCode; +use glium::glutin::{ + Event, + WindowEvent, + VirtualKeyCode, + ElementState, +}; use model_converter::scene::Scene; use model_converter::math::bounding_box::BoundingBox3; @@ -78,6 +81,10 @@ fn main() { } } + let center = (bbox.min() + bbox.max()) / 2.0; + let center = Vector3::new(center.x() as f32, center.y() as f32, center.z() as f32); + let size = (bbox.max() - bbox.min()).norm() as f32; + let mut events_loop = EventsLoop::new(); let window = WindowBuilder::new().with_visibility(false); let context = glutin::ContextBuilder::new().with_depth_buffer(24); @@ -151,11 +158,41 @@ fn main() { Event::WindowEvent { event: WindowEvent::KeyboardInput { input: glutin::KeyboardInput { - virtual_keycode: Some(VirtualKeyCode::Escape), .. + virtual_keycode: Some(VirtualKeyCode::Escape), + state: ElementState::Pressed, .. }, .. }, .. } => closed = true, + // Enter key + Event::WindowEvent { + event: WindowEvent::KeyboardInput { + input: glutin::KeyboardInput { + virtual_keycode: Some(VirtualKeyCode::Return), + state: ElementState::Pressed, .. + }, .. + }, .. + } => { + + // Go back in world coordinates + let position = camera.position * size as f32; + let position = position + center; + + let target = camera.target * size as f32; + let target = target + center; + + let up = camera.up; + + println!("Camera:"); + + println!("\tPosition: ({}, {}, {})", + position.x(), position.y(), position.z()); + println!("\tTarget: ({}, {}, {})", + target.x(), target.y(), target.z()); + println!("\tUp: ({}, {}, {})", + up.x(), up.y(), up.z()); + } + _ => (), } }); From 674b49430fd0f1f89facab0ae2b840ee24bfca8b Mon Sep 17 00:00:00 2001 From: Thomas Forgione Date: Thu, 19 Jul 2018 14:24:54 +0200 Subject: [PATCH 3/5] Fixed frustum culling --- src/camera.rs | 158 +++++++++++++++++++++++++-------------- src/math/bounding_box.rs | 27 +++++++ src/math/frustum.rs | 43 ++++++----- src/math/vector.rs | 8 ++ src/programs/viewer.rs | 24 +++--- src/renderer.rs | 4 +- 6 files changed, 179 insertions(+), 85 deletions(-) diff --git a/src/camera.rs b/src/camera.rs index d18518e..3ea88a5 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,8 +1,9 @@ //! This module contains everything to deal with cameras. use nalgebra::Matrix4; +use nalgebra::Vector4; -use math::vector::Vector3; +use math::vector::{Vector2, Vector3}; use math::frustum::Frustum; /// The trait that a render camera should implement. @@ -11,76 +12,87 @@ use math::frustum::Frustum; pub trait RenderCamera { /// Returns the view matrix of the camera. - fn get_view_matrix(&self) -> Matrix4; + fn view(&self) -> Matrix4; /// Returns the perspective matrix of the camera. - fn get_perspective_matrix(&self) -> Matrix4; + fn perspective(&self) -> Matrix4; /// Returns the product of the perspective matrix and the view matrix. - fn get_model_view_matrix(&self) -> Matrix4 { - self.get_perspective_matrix() * self.get_view_matrix().try_inverse().unwrap() + fn model_view(&self) -> Matrix4 { + self.perspective() * self.view() } /// Returns the frustum of the camera. fn frustum(&self) -> Frustum { - Frustum::from_matrix(&self.get_model_view_matrix()) + panic!(); } } -/// Creates a look at matrix from the center, the target pointed by the camera and the up vector. -pub fn look_at_matrix(position: [f32; 3], target: [f32; 3], up: [f32; 3]) -> Matrix4 { - let f = { - let f = [ - target[0] - position[0], - target[1] - position[1], - target[2] - position[2], - ]; - let len = f[0] * f[0] + f[1] * f[1] + f[2] * f[2]; - let len = len.sqrt(); - [f[0] / len, f[1] / len, f[2] / len] - }; +/// Creates the pose matrix, inverse of the look at matrix. +pub fn pose(position: Vector3, target: Vector3, up: Vector3) -> Matrix4 { + // This is the right way to do things + let e3 = (position - target).normalized(); - let s = [up[1] * f[2] - up[2] * f[1], - up[2] * f[0] - up[0] * f[2], - up[0] * f[1] - up[1] * f[0]]; - - let s_norm = { - let len = s[0] * s[0] + s[1] * s[1] + s[2] * s[2]; - let len = len.sqrt(); - [s[0] / len, s[1] / len, s[2] / len] - }; - - let u = [f[1] * s_norm[2] - f[2] * s_norm[1], - f[2] * s_norm[0] - f[0] * s_norm[2], - f[0] * s_norm[1] - f[1] * s_norm[0]]; - - let p = [-position[0] * s_norm[0] - position[1] * s_norm[1] - position[2] * s_norm[2], - -position[0] * u[0] - position[1] * u[1] - position[2] * u[2], - -position[0] * f[0] - position[1] * f[1] - position[2] * f[2]]; + // Well, ok, maybe this is not the right way, but it works + let e1 = up.cross_product(e3).normalized(); + let e2 = e3.cross_product(e1); [ - [-s_norm[0], u[0], f[0], 0.0], - [-s_norm[1], u[1], f[1], 0.0], - [-s_norm[2], u[2], f[2], 0.0], - [-p[0], p[1], p[2], 1.0], + [e1[0], e1[1], e1[2], 0.0], + [e2[0], e2[1], e2[2], 0.0], + [e3[0], e3[1], e3[2], 0.0], + [position[0], position[1], position[2], 1.0], ].into() +} +/// Creates a look at matrix from the center, the target pointed by the camera and the up vector. +pub fn look_at(position: Vector3, target: Vector3, up: Vector3) -> Matrix4 { + pose(position, target, up).try_inverse().unwrap() } /// Creates a perspective matrix of a camera. -pub fn perspective_matrix(aspect_ratio: f32, z_near: f32, z_far: f32) -> Matrix4 { - let fov = 3.141592 / 3.0; +pub fn perspective(fov: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Matrix4 { - use num::Float; - let f = 1.0 / (fov / 2.0).tan(); + let top = z_near * (fov / 2.0).tan(); + let height = 2.0 * top; + let width = aspect_ratio * height; + + let x = 2.0 * z_near / width; + let y = 2.0 * z_near / height; + + let c = - (z_far + z_near) / (z_far - z_near); + let d = - 2.0 * z_far * z_near / (z_far - z_near); + + Matrix4::new( + x, 0.0, 0.0, 0.0, + 0.0, y, 0.0, 0.0, + 0.0, 0.0, c, d, + 0.0, 0.0, -1.0, 0.0, + ) + +} + +/// Returns the inverse of the perspective matrix. +pub fn perspective_inverse(fov: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Matrix4 { + + let top = z_near * (fov / 2.0).tan(); + let height = 2.0 * top; + let width = aspect_ratio * height; + + let x = 2.0 * z_near / width; + let y = 2.0 * z_near / height; + + let c = - (z_far + z_near) / (z_far - z_near); + let d = - 2.0 * z_far * z_near / (z_far - z_near); + + Matrix4::new( + 1.0 / x, 0.0, 0.0, 0.0, + 0.0, 1.0 / y, 0.0, 0.0, + 0.0, 0.0, 0.0, -1.0, + 0.0, 0.0, 1.0 / d, c / d, + ) - [ - [f / aspect_ratio , 0.0, 0.0 , 0.0], - [ 0.0 , f , 0.0 , 0.0], - [ 0.0 , 0.0, (z_far+z_near)/(z_far-z_near) , 1.0], - [ 0.0 , 0.0, -(2.0*z_far*z_near)/(z_far-z_near), 0.0], - ].into() } /// A simple camera with its position, target and up vector. @@ -95,6 +107,9 @@ pub struct Camera { /// The up vector of the camera. pub up: Vector3, + /// The field of view of the camera. + pub fov: f32, + /// The minimum depth for visible things. pub z_near: f32, @@ -109,29 +124,62 @@ pub struct Camera { impl Camera { /// Creates a new camera from its attributes. pub fn new(position: Vector3, target: Vector3, up: Vector3) -> Camera { + use std::f32::consts::PI; + Camera { position: position, target: target, up: up, z_near: 0.0001, z_far: 1000.0, - aspect_ratio: 16.0 / 9.0 + aspect_ratio: 16.0 / 9.0, + fov: PI / 3.0, } } + /// Returns the pose matrix of the camera. + pub fn pose(&self) -> Matrix4 { + pose(self.position, self.target, self.up) + } + + /// Returns the view matrix of the camera, inverse of the pose. + pub fn view(&self) -> Matrix4 { + look_at(self.position, self.target, self.up) + } + + /// Returns the perspective matrix of the camera. + pub fn perspective(&self) -> Matrix4 { + perspective(self.fov, self.aspect_ratio, self.z_near, self.z_far) + } + + /// Returns the inverse of the perspective matrix of the camera. + pub fn perspective_inverse(&self) -> Matrix4 { + perspective_inverse(self.fov, self.aspect_ratio, self.z_near, self.z_far) + } + /// Returns the frustum of the camera. pub fn frustum(&self) -> Frustum { - RenderCamera::frustum(self) + Frustum::from_matrix(&(self.perspective() * self.view())) + } + + /// Unprojects a 2D point (x, y) in the 3D world. + /// + /// The coordinates must be in [-1.0, 1.0] + pub fn unproject(&self, point: Vector2) -> Vector3 { + + let point = Vector4::new(point[0], point[1], 0.5, 1.0); + let v = self.pose() * self.perspective_inverse() * point; + Vector3::new(v[0] / v[3], v[1] / v[3], v[2] / v[3]) } } impl RenderCamera for Camera { - fn get_view_matrix(&self) -> Matrix4 { - look_at_matrix(self.position.into(), self.target.into(), self.up.into()) + fn view(&self) -> Matrix4 { + self.view() } - fn get_perspective_matrix(&self) -> Matrix4 { - perspective_matrix(self.aspect_ratio, self.z_near, self.z_far) + fn perspective(&self) -> Matrix4 { + self.perspective() } } diff --git a/src/math/bounding_box.rs b/src/math/bounding_box.rs index d89b332..83a2e64 100644 --- a/src/math/bounding_box.rs +++ b/src/math/bounding_box.rs @@ -95,6 +95,16 @@ macro_rules! make_bounding_box { ret } + /// Returns true if the point is inside the bounding box. + pub fn contains_point(&self, point: $vector) -> bool { + for i in 0 .. $size { + if self.min()[i] > point[i] || point[i] > self.max()[i] { + return false; + } + } + true + } + } } @@ -183,4 +193,21 @@ mod tests { let bb2 = b2.intersection(&b1); assert_eq!(bb1, bb2); } + + #[test] + fn contains_point() { + let b1 = BoundingBox3::new( + Vector3::new(0.0, 0.0, 0.0), + Vector3::new(2.0, 2.0, 2.0), + ); + + assert_eq!(b1.contains_point(Vector3::new(1.0, 1.0, 1.0)), true); + assert_eq!(b1.contains_point(Vector3::new(1.5, 0.5, 1.0)), true); + assert_eq!(b1.contains_point(Vector3::new(1.5, -0.5, 1.0)), false); + assert_eq!(b1.contains_point(Vector3::new(1.5, 0.5, -1.0)), false); + assert_eq!(b1.contains_point(Vector3::new(-0.5, 0.5, 1.0)), false); + assert_eq!(b1.contains_point(Vector3::new(2.5, 0.5, 1.0)), false); + assert_eq!(b1.contains_point(Vector3::new(0.5, 2.5, 1.0)), false); + + } } diff --git a/src/math/frustum.rs b/src/math/frustum.rs index be2a872..228d16d 100644 --- a/src/math/frustum.rs +++ b/src/math/frustum.rs @@ -17,15 +17,27 @@ pub struct Frustum { } impl Frustum { - /// Creates a frustum from the matrix of a camera. - /// - /// This is *ahem...* slightly inspired from THREE.js Frustum + + /// Creates a frustum from its four planes. + pub fn new(planes: [Plane; 6]) -> Frustum { + Frustum { + planes: planes, + } + } + + /// Creates a frustum for a camera matrix. pub fn from_matrix(m: &Matrix4) -> Frustum { - let m0 = m[(0, 0)]; let m1 = m[(0, 1)]; let m2 = m[(0, 2)]; let m3 = m[(0, 3)]; - let m4 = m[(1, 0)]; let m5 = m[(1, 1)]; let m6 = m[(1, 2)]; let m7 = m[(1, 3)]; - let m8 = m[(2, 0)]; let m9 = m[(2, 1)]; let m10 = m[(2, 2)]; let m11 = m[(2, 3)]; - let m12 = m[(3, 0)]; let m13 = m[(3, 1)]; let m14 = m[(3, 2)]; let m15 = m[(3, 3)]; + // let m0 = m[(0, 0)]; let m1 = m[(0, 1)]; let m2 = m[(0, 2)]; let m3 = m[(0, 3)]; + // let m4 = m[(1, 0)]; let m5 = m[(1, 1)]; let m6 = m[(1, 2)]; let m7 = m[(1, 3)]; + // let m8 = m[(2, 0)]; let m9 = m[(2, 1)]; let m10 = m[(2, 2)]; let m11 = m[(2, 3)]; + // let m12 = m[(3, 0)]; let m13 = m[(3, 1)]; let m14 = m[(3, 2)]; let m15 = m[(3, 3)]; + + // Swapped version... + let m0 = m[(0, 0)]; let m1 = m[(1, 0)]; let m2 = m[(2, 0)]; let m3 = m[(3, 0)]; + let m4 = m[(0, 1)]; let m5 = m[(1, 1)]; let m6 = m[(2, 1)]; let m7 = m[(3, 1)]; + let m8 = m[(0, 2)]; let m9 = m[(1, 2)]; let m10 = m[(2, 2)]; let m11 = m[(3, 2)]; + let m12 = m[(0, 3)]; let m13 = m[(1, 3)]; let m14 = m[(2, 3)]; let m15 = m[(3, 3)]; Frustum { planes: [ @@ -44,22 +56,15 @@ impl Frustum { use num::Zero; - let mut p1 = Vector3::::zero(); - let mut p2 = Vector3::::zero(); + let mut p = Vector3::::zero(); for plane in &self.planes { - p1[0] = if plane.normal().x() > 0.0 { bbox.min().x() } else { bbox.max().x() }; - p2[0] = if plane.normal().x() > 0.0 { bbox.max().x() } else { bbox.min().x() }; - p1[1] = if plane.normal().y() > 0.0 { bbox.min().y() } else { bbox.max().y() }; - p2[1] = if plane.normal().y() > 0.0 { bbox.max().y() } else { bbox.min().y() }; - p1[2] = if plane.normal().z() > 0.0 { bbox.min().z() } else { bbox.max().z() }; - p2[2] = if plane.normal().z() > 0.0 { bbox.max().z() } else { bbox.min().z() }; + p[0] = if plane.normal().x() > 0.0 { bbox.max().x() } else { bbox.min().x() }; + p[1] = if plane.normal().y() > 0.0 { bbox.max().y() } else { bbox.min().y() }; + p[2] = if plane.normal().z() > 0.0 { bbox.max().z() } else { bbox.min().z() }; - let d1 = plane.distance_to_point(p1); - let d2 = plane.distance_to_point(p2); - - if d1 < 0.0 && d2 < 2.0 { + if plane.distance_to_point(p) < 0.0 { return false; } } diff --git a/src/math/vector.rs b/src/math/vector.rs index 7fdc9fe..f181429 100644 --- a/src/math/vector.rs +++ b/src/math/vector.rs @@ -39,6 +39,14 @@ macro_rules! make_vector { } } + impl From<[T; $number]> for $name { + fn from(data: [T; $number]) -> $name { + $name { + data: data, + } + } + } + impl Into<($( $t ) ,* )> for $name { fn into(self) -> ($( $t ) ,* ) { ( $( self.data[$y] ), *) diff --git a/src/programs/viewer.rs b/src/programs/viewer.rs index c9843f7..5f49443 100644 --- a/src/programs/viewer.rs +++ b/src/programs/viewer.rs @@ -3,6 +3,7 @@ extern crate glium; #[macro_use] extern crate verbose_log; extern crate model_converter; +extern crate nalgebra as na; use std::process::exit; use std::time::{Instant, Duration}; @@ -97,7 +98,7 @@ fn main() { for (name, mut model) in models { log!("Scaling model {}...", name); - model.center_and_scale_from_box(&bbox); + // model.center_and_scale_from_box(&bbox); log!("\nBuilding textures for model {}...", name); @@ -119,19 +120,21 @@ fn main() { let mut closed = false; let mut camera = Camera::new( - Vector3::new( 0.0, 0.0, 0.0), - Vector3::new( 0.0, 0.0, 0.0), - Vector3::new( 0.0, 1.0, 0.0), + Vector3::new(1.0, 0.0, 0.0), + Vector3::new(0.0, 0.0, 0.0), + Vector3::new(0.0, 1.0, 0.0), ); camera.z_near = 0.0001; + use model_converter::camera::RenderCamera; + let mut controls: Box = if matches.is_present("first person") { Box::new(FirstPersonControls::new()) } else { Box::new(OrbitControls::new( Vector3::new(0.0, 0.0, 0.0), - 1.0, + 2.0, &mut camera )) }; @@ -175,11 +178,11 @@ fn main() { } => { // Go back in world coordinates - let position = camera.position * size as f32; - let position = position + center; + let position = camera.position; + // let position = position + center; - let target = camera.target * size as f32; - let target = target + center; + let target = camera.target; + // let target = target + center; let up = camera.up; @@ -191,12 +194,15 @@ fn main() { target.x(), target.y(), target.z()); println!("\tUp: ({}, {}, {})", up.x(), up.y(), up.z()); + } _ => (), } }); + + controls.update(&mut camera, &renderer); renderer.render(&scene, &camera); let elapsed = as_millis(Instant::now().duration_since(before)); diff --git a/src/renderer.rs b/src/renderer.rs index 5659d74..1a01cc7 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -124,8 +124,8 @@ impl Renderer { let mut target = self.draw(); target.clear_color_srgb_and_depth(self.clear_color, 1.0); - let perspective = camera.get_perspective_matrix(); - let view = camera.get_view_matrix(); + let perspective = camera.perspective(); + let view = camera.view(); let params = DrawParameters { depth: Depth { From 6807773b3853caf3f3e8821d9a64293330b1eaed Mon Sep 17 00:00:00 2001 From: Thomas Forgione Date: Mon, 23 Jul 2018 10:12:37 +0200 Subject: [PATCH 4/5] Work on back projection, f32 -> f64 --- src/camera.rs | 46 ++++++++++++++++++------------------ src/controls.rs | 50 ++++++++++++++++++++-------------------- src/math/bounding_box.rs | 4 ++-- src/math/frustum.rs | 6 ++--- src/math/plane.rs | 18 +++++++-------- src/math/vector.rs | 8 +++---- src/model/material.rs | 4 ++-- src/parser/mod.rs | 4 ++-- src/parser/mtl.rs | 12 +++++----- src/programs/viewer.rs | 36 +++++++---------------------- src/renderer.rs | 10 ++++---- 11 files changed, 89 insertions(+), 109 deletions(-) diff --git a/src/camera.rs b/src/camera.rs index 3ea88a5..1c84885 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -12,13 +12,13 @@ use math::frustum::Frustum; pub trait RenderCamera { /// Returns the view matrix of the camera. - fn view(&self) -> Matrix4; + fn view(&self) -> Matrix4; /// Returns the perspective matrix of the camera. - fn perspective(&self) -> Matrix4; + fn perspective(&self) -> Matrix4; /// Returns the product of the perspective matrix and the view matrix. - fn model_view(&self) -> Matrix4 { + fn model_view(&self) -> Matrix4 { self.perspective() * self.view() } @@ -30,7 +30,7 @@ pub trait RenderCamera { } /// Creates the pose matrix, inverse of the look at matrix. -pub fn pose(position: Vector3, target: Vector3, up: Vector3) -> Matrix4 { +pub fn pose(position: Vector3, target: Vector3, up: Vector3) -> Matrix4 { // This is the right way to do things let e3 = (position - target).normalized(); @@ -47,12 +47,12 @@ pub fn pose(position: Vector3, target: Vector3, up: Vector3) -> M } /// Creates a look at matrix from the center, the target pointed by the camera and the up vector. -pub fn look_at(position: Vector3, target: Vector3, up: Vector3) -> Matrix4 { +pub fn look_at(position: Vector3, target: Vector3, up: Vector3) -> Matrix4 { pose(position, target, up).try_inverse().unwrap() } /// Creates a perspective matrix of a camera. -pub fn perspective(fov: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Matrix4 { +pub fn perspective(fov: f64, aspect_ratio: f64, z_near: f64, z_far: f64) -> Matrix4 { let top = z_near * (fov / 2.0).tan(); let height = 2.0 * top; @@ -74,7 +74,7 @@ pub fn perspective(fov: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Matr } /// Returns the inverse of the perspective matrix. -pub fn perspective_inverse(fov: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Matrix4 { +pub fn perspective_inverse(fov: f64, aspect_ratio: f64, z_near: f64, z_far: f64) -> Matrix4 { let top = z_near * (fov / 2.0).tan(); let height = 2.0 * top; @@ -99,32 +99,32 @@ pub fn perspective_inverse(fov: f32, aspect_ratio: f32, z_near: f32, z_far: f32) #[derive(Clone, Debug)] pub struct Camera { /// The position of the center of the camera. - pub position: Vector3, + pub position: Vector3, /// The 3D point the camera is targetting. - pub target: Vector3, + pub target: Vector3, /// The up vector of the camera. - pub up: Vector3, + pub up: Vector3, /// The field of view of the camera. - pub fov: f32, + pub fov: f64, /// The minimum depth for visible things. - pub z_near: f32, + pub z_near: f64, /// The maximum depth for visible things. - pub z_far: f32, + pub z_far: f64, /// The aspect ratio of the camera. - pub aspect_ratio: f32, + pub aspect_ratio: f64, } impl Camera { /// Creates a new camera from its attributes. - pub fn new(position: Vector3, target: Vector3, up: Vector3) -> Camera { - use std::f32::consts::PI; + pub fn new(position: Vector3, target: Vector3, up: Vector3) -> Camera { + use std::f64::consts::PI; Camera { position: position, @@ -138,22 +138,22 @@ impl Camera { } /// Returns the pose matrix of the camera. - pub fn pose(&self) -> Matrix4 { + pub fn pose(&self) -> Matrix4 { pose(self.position, self.target, self.up) } /// Returns the view matrix of the camera, inverse of the pose. - pub fn view(&self) -> Matrix4 { + pub fn view(&self) -> Matrix4 { look_at(self.position, self.target, self.up) } /// Returns the perspective matrix of the camera. - pub fn perspective(&self) -> Matrix4 { + pub fn perspective(&self) -> Matrix4 { perspective(self.fov, self.aspect_ratio, self.z_near, self.z_far) } /// Returns the inverse of the perspective matrix of the camera. - pub fn perspective_inverse(&self) -> Matrix4 { + pub fn perspective_inverse(&self) -> Matrix4 { perspective_inverse(self.fov, self.aspect_ratio, self.z_near, self.z_far) } @@ -165,7 +165,7 @@ impl Camera { /// Unprojects a 2D point (x, y) in the 3D world. /// /// The coordinates must be in [-1.0, 1.0] - pub fn unproject(&self, point: Vector2) -> Vector3 { + pub fn unproject(&self, point: Vector2) -> Vector3 { let point = Vector4::new(point[0], point[1], 0.5, 1.0); let v = self.pose() * self.perspective_inverse() * point; @@ -174,11 +174,11 @@ impl Camera { } impl RenderCamera for Camera { - fn view(&self) -> Matrix4 { + fn view(&self) -> Matrix4 { self.view() } - fn perspective(&self) -> Matrix4 { + fn perspective(&self) -> Matrix4 { self.perspective() } } diff --git a/src/controls.rs b/src/controls.rs index 4a8f67e..8f51595 100644 --- a/src/controls.rs +++ b/src/controls.rs @@ -1,6 +1,6 @@ //! This models contains structs that help move the camera in a user-friendly way. -const EPSILON: f32 = 0.001; +const EPSILON: f64 = 0.001; use glium::glutin::{ Event, @@ -33,31 +33,31 @@ pub trait Controls { /// Only object centered are supported. pub struct OrbitControls { /// The last position of the mouse. - mouse_position: Vector2, + mouse_position: Vector2, /// Wether the left click of the mouse is pressed or not. pressed: bool, /// The theta angle of the position of the camera in spheric coordinates. - theta: f32, + theta: f64, /// The phi angle of the position of the camera in spheric coordinates. - phi: f32, + phi: f64, /// The distance between the camera and the origin. - distance: f32, + distance: f64, /// The sensitiviy of the rotation of the mouse. - sensitivity: f32, + sensitivity: f64, /// The center of the object. - center: Vector3, + center: Vector3, } impl OrbitControls { /// Creates a new orbit controls, and initializes the camera. - pub fn new(center: Vector3, distance: f32, camera: &mut Camera) -> OrbitControls { + pub fn new(center: Vector3, distance: f64, camera: &mut Camera) -> OrbitControls { let controls = OrbitControls { mouse_position: Vector2::new(0.0, 0.0), pressed: false, @@ -85,8 +85,8 @@ impl OrbitControls { let distance = (bounding_box.max() - bounding_box.min()).norm(); OrbitControls::new( - Vector3::new(center.x() as f32, center.y() as f32, center.z() as f32), - distance as f32, + Vector3::new(center.x() as f64, center.y() as f64, center.z() as f64), + distance as f64, camera ) @@ -109,7 +109,7 @@ impl Controls for OrbitControls { Event::WindowEvent { event: WindowEvent::Resized(width, height), .. } => { - camera.aspect_ratio = width as f32 / height as f32; + camera.aspect_ratio = width as f64 / height as f64; }, Event::WindowEvent { @@ -117,7 +117,7 @@ impl Controls for OrbitControls { delta: MouseScrollDelta::LineDelta(_, y), .. }, .. } => { - self.distance -= y / self.sensitivity; + self.distance -= y as f64 / self.sensitivity; *camera.position.x_mut() = self.distance * self.phi.cos() * self.theta.cos(); *camera.position.y_mut() = self.distance * self.phi.sin(); @@ -132,7 +132,7 @@ impl Controls for OrbitControls { position: (x, y), .. }, .. } => { - let current_position = Vector2::new(x as f32, y as f32); + let current_position = Vector2::new(x as f64, y as f64); if self.pressed { let difference = (current_position - self.mouse_position) / self.sensitivity; @@ -140,7 +140,7 @@ impl Controls for OrbitControls { self.theta += difference.x(); self.phi += difference.y(); - use std::f32::consts::PI; + use std::f64::consts::PI; self.phi = self.phi.max(- PI/2.0 + EPSILON); self.phi = self.phi.min( PI/2.0 - EPSILON); @@ -170,25 +170,25 @@ impl Controls for OrbitControls { pub struct FirstPersonControls { /// Theta angle of the spheric coordinates of the direction of the camera. - theta: f32, + theta: f64, /// Phi angle of the spheric coordinates of the direction of the camera. - phi: f32, + phi: f64, /// Current position of the camera. - position: Vector3, + position: Vector3, /// Vector indicating the direction of the camera. - forward: Vector3, + forward: Vector3, /// Vector indicating the left of the camera. - left: Vector3, + left: Vector3, /// Speed of the camera. - speed: f32, + speed: f64, /// Sensitivity of the mouse. - sensitivity: f32, + sensitivity: f64, /// Wether the forward button is pressed or not. forward_pressed: bool, @@ -241,7 +241,7 @@ impl Controls for FirstPersonControls { Event::WindowEvent { event: WindowEvent::Resized(width, height), .. } => { - camera.aspect_ratio = width as f32 / height as f32; + camera.aspect_ratio = width as f64 / height as f64; }, // On Z pressed @@ -307,14 +307,14 @@ impl Controls for FirstPersonControls { } => { let size = renderer.gl_window().window().get_inner_size().unwrap(); - let center = Vector2::new(size.0 as f32 / 2.0, size.1 as f32 / 2.0); - let current_position = Vector2::new(x as f32, y as f32); + let center = Vector2::new(size.0 as f64 / 2.0, size.1 as f64 / 2.0); + let current_position = Vector2::new(x as f64, y as f64); let difference = (current_position - center) / self.sensitivity; self.theta += difference.x(); self.phi -= difference.y(); - use std::f32::consts::PI; + use std::f64::consts::PI; self.phi = self.phi.max(- PI/2.0 + EPSILON); self.phi = self.phi.min( PI/2.0 - EPSILON); diff --git a/src/math/bounding_box.rs b/src/math/bounding_box.rs index 83a2e64..6ffb696 100644 --- a/src/math/bounding_box.rs +++ b/src/math/bounding_box.rs @@ -126,10 +126,10 @@ macro_rules! impl_center { } impl_center!(BoundingBox2, Vector2, f32); -impl_center!(BoundingBox2, Vector2, f64); impl_center!(BoundingBox3, Vector3, f32); -impl_center!(BoundingBox3, Vector3, f64); impl_center!(BoundingBox4, Vector4, f32); +impl_center!(BoundingBox2, Vector2, f64); +impl_center!(BoundingBox3, Vector3, f64); impl_center!(BoundingBox4, Vector4, f64); diff --git a/src/math/frustum.rs b/src/math/frustum.rs index 228d16d..cd76015 100644 --- a/src/math/frustum.rs +++ b/src/math/frustum.rs @@ -26,7 +26,7 @@ impl Frustum { } /// Creates a frustum for a camera matrix. - pub fn from_matrix(m: &Matrix4) -> Frustum { + pub fn from_matrix(m: &Matrix4) -> Frustum { // let m0 = m[(0, 0)]; let m1 = m[(0, 1)]; let m2 = m[(0, 2)]; let m3 = m[(0, 3)]; // let m4 = m[(1, 0)]; let m5 = m[(1, 1)]; let m6 = m[(1, 2)]; let m7 = m[(1, 3)]; @@ -52,11 +52,11 @@ impl Frustum { } /// Returns true if the intersection of the frustum and the bounding box is not empty. - pub fn intersects_box(&self, bbox: BoundingBox3) -> bool { + pub fn intersects_box(&self, bbox: BoundingBox3) -> bool { use num::Zero; - let mut p = Vector3::::zero(); + let mut p = Vector3::::zero(); for plane in &self.planes { diff --git a/src/math/plane.rs b/src/math/plane.rs index a0ae38c..618aace 100644 --- a/src/math/plane.rs +++ b/src/math/plane.rs @@ -6,15 +6,15 @@ use math::vector::Vector3; #[derive(Copy, Clone)] pub struct Plane { /// The normal of the plane. - normal: Vector3, + normal: Vector3, /// The constant, offset of the plane from the origin. - constant: f32, + constant: f64, } impl Plane { /// Creates a new plane from its normal and its constant. - pub fn from_coordinates(a: f32, b: f32, c: f32, w: f32) -> Plane { + pub fn from_coordinates(a: f64, b: f64, c: f64, w: f64) -> Plane { let mut p = Plane { normal: Vector3::new(a, b, c), constant: w, @@ -24,18 +24,18 @@ impl Plane { } /// Creates a new plane from its normal and its constant. - pub fn from_normal_and_constant(normal: Vector3, constant: f32) -> Plane { + pub fn from_normal_and_constant(normal: Vector3, constant: f64) -> Plane { Plane::from_coordinates(normal.x(), normal.y(), normal.z(), constant) } /// Creates a new plane from its normal and a point of the plane. - pub fn from_normal_and_point(normal: Vector3, point: Vector3) -> Plane { + pub fn from_normal_and_point(normal: Vector3, point: Vector3) -> Plane { Plane::from_normal_and_constant(normal, - point.dot(normal)) } /// Creates a new plane from three points. - pub fn from_points(p1: Vector3, p2: Vector3, p3: Vector3) -> Plane { + pub fn from_points(p1: Vector3, p2: Vector3, p3: Vector3) -> Plane { let p1p2 = p2 - p1; let p1p3 = p3 - p1; Plane::from_normal_and_point(p1p2.cross_product(p1p3), p1) @@ -49,17 +49,17 @@ impl Plane { } /// Returns the normal of the plane. - pub fn normal(&self) -> Vector3 { + pub fn normal(&self) -> Vector3 { self.normal } /// Returns the constant of the plane. - pub fn constant(&self) -> f32 { + pub fn constant(&self) -> f64 { self.constant } /// Returns the distance between the plane and the point. - pub fn distance_to_point(&self, point: Vector3) -> f32 { + pub fn distance_to_point(&self, point: Vector3) -> f64 { self.normal.dot(point) + self.constant } } diff --git a/src/math/vector.rs b/src/math/vector.rs index f181429..a740f6b 100644 --- a/src/math/vector.rs +++ b/src/math/vector.rs @@ -247,9 +247,9 @@ make_vector!(Vector2, 2, (T, T), (x, x_mut, 0), (y, y_mut, 1)); make_vector!(Vector3, 3, (T, T, T), (x, x_mut, 0), (y, y_mut, 1), (z, z_mut, 2)); make_vector!(Vector4, 4, (T, T, T, T), (x, x_mut, 0), (y, y_mut, 1), (z, z_mut, 2), (t, t_mut, 3)); -impl Vector2 { +impl Vector2 { /// Returns a orthogonal vector to the one passed as parameter. - pub fn orthogonal(&self) -> Vector2 { + pub fn orthogonal(&self) -> Vector2 { Vector2::new( self.y(), self.x() * -1.0, @@ -291,10 +291,10 @@ impl Vector3 { } type Vector2f32 = Vector2; implement_vertex!(Vector2f32, data); -type Vector2f64 = Vector2; implement_vertex!(Vector2f64, data); type Vector3f32 = Vector3; implement_vertex!(Vector3f32, data); -type Vector3f64 = Vector3; implement_vertex!(Vector3f64, data); type Vector4f32 = Vector4; implement_vertex!(Vector4f32, data); +type Vector2f64 = Vector2; implement_vertex!(Vector2f64, data); +type Vector3f64 = Vector3; implement_vertex!(Vector3f64, data); type Vector4f64 = Vector4; implement_vertex!(Vector4f64, data); #[cfg(test)] diff --git a/src/model/material.rs b/src/model/material.rs index c49b0ad..ca1602d 100644 --- a/src/model/material.rs +++ b/src/model/material.rs @@ -11,10 +11,10 @@ pub struct Material { pub name: String, /// The diffuse color of the material. - pub diffuse: Vector3, + pub diffuse: Vector3, /// Map linking each texture map to its file path. - pub textures: HashMap)>, + pub textures: HashMap)>, /// Instructions that are unknown. /// diff --git a/src/parser/mod.rs b/src/parser/mod.rs index c0f3d8b..41729ff 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -47,10 +47,10 @@ pub enum Element { /// First string is the name of the map. /// Second string is the path to the image file. /// Vector3 is the size of the texture. - Texture(String, String, Vector3), + Texture(String, String, Vector3), /// Change the main color of the current material. - Diffuse(Vector3), + Diffuse(Vector3), /// An unknown material instruction that will be copied into the mtl file. UnknownMaterialInstruction(String), diff --git a/src/parser/mtl.rs b/src/parser/mtl.rs index 287fdcf..61b69db 100644 --- a/src/parser/mtl.rs +++ b/src/parser/mtl.rs @@ -46,9 +46,9 @@ impl LineParser for MtlParser { "Kd" => { let values = parse_values(line_number, line, path, 3)?; Ok(Element::Diffuse(Vector3::new( - values[0] as f32, - values[1] as f32, - values[2] as f32, + values[0] as f64, + values[1] as f64, + values[2] as f64, ))) }, @@ -63,9 +63,9 @@ impl LineParser for MtlParser { Ok(Element::Texture(first.to_owned(), full_path.to_str().unwrap().to_owned(), Vector3::new(1.0, 1.0, 1.0))) } else if split[0] == "-s" { let size = Vector3::new( - if let Ok(f) = split[1].parse::() { f } else { return Err(ParserError::ParseNumberError(path.to_owned(), line_number, split[1].to_owned())); }, - if let Ok(f) = split[2].parse::() { f } else { return Err(ParserError::ParseNumberError(path.to_owned(), line_number, split[2].to_owned())); }, - if let Ok(f) = split[3].parse::() { f } else { return Err(ParserError::ParseNumberError(path.to_owned(), line_number, split[3].to_owned())); }, + if let Ok(f) = split[1].parse::() { f } else { return Err(ParserError::ParseNumberError(path.to_owned(), line_number, split[1].to_owned())); }, + if let Ok(f) = split[2].parse::() { f } else { return Err(ParserError::ParseNumberError(path.to_owned(), line_number, split[2].to_owned())); }, + if let Ok(f) = split[3].parse::() { f } else { return Err(ParserError::ParseNumberError(path.to_owned(), line_number, split[3].to_owned())); }, ); let mut full_path = root.clone(); full_path.push(split[4].to_owned()); diff --git a/src/programs/viewer.rs b/src/programs/viewer.rs index 5f49443..bd134e9 100644 --- a/src/programs/viewer.rs +++ b/src/programs/viewer.rs @@ -3,7 +3,6 @@ extern crate glium; #[macro_use] extern crate verbose_log; extern crate model_converter; -extern crate nalgebra as na; use std::process::exit; use std::time::{Instant, Duration}; @@ -82,10 +81,6 @@ fn main() { } } - let center = (bbox.min() + bbox.max()) / 2.0; - let center = Vector3::new(center.x() as f32, center.y() as f32, center.z() as f32); - let size = (bbox.max() - bbox.min()).norm() as f32; - let mut events_loop = EventsLoop::new(); let window = WindowBuilder::new().with_visibility(false); let context = glutin::ContextBuilder::new().with_depth_buffer(24); @@ -98,7 +93,7 @@ fn main() { for (name, mut model) in models { log!("Scaling model {}...", name); - // model.center_and_scale_from_box(&bbox); + model.center_and_scale_from_box(&bbox); log!("\nBuilding textures for model {}...", name); @@ -120,21 +115,19 @@ fn main() { let mut closed = false; let mut camera = Camera::new( - Vector3::new(1.0, 0.0, 0.0), - Vector3::new(0.0, 0.0, 0.0), - Vector3::new(0.0, 1.0, 0.0), + Vector3::new( 0.0, 0.0, 0.0), + Vector3::new( 0.0, 0.0, 0.0), + Vector3::new( 0.0, 1.0, 0.0), ); camera.z_near = 0.0001; - use model_converter::camera::RenderCamera; - let mut controls: Box = if matches.is_present("first person") { Box::new(FirstPersonControls::new()) } else { Box::new(OrbitControls::new( Vector3::new(0.0, 0.0, 0.0), - 2.0, + 1.0, &mut camera )) }; @@ -176,33 +169,20 @@ fn main() { }, .. }, .. } => { - - // Go back in world coordinates - let position = camera.position; - // let position = position + center; - - let target = camera.target; - // let target = target + center; - - let up = camera.up; - println!("Camera:"); println!("\tPosition: ({}, {}, {})", - position.x(), position.y(), position.z()); + camera.position.x(), camera.position.y(), camera.position.z()); println!("\tTarget: ({}, {}, {})", - target.x(), target.y(), target.z()); + camera.target.x(), camera.target.y(), camera.target.z()); println!("\tUp: ({}, {}, {})", - up.x(), up.y(), up.z()); - + camera.up.x(), camera.up.y(), camera.up.z()); } _ => (), } }); - - controls.update(&mut camera, &renderer); renderer.render(&scene, &camera); let elapsed = as_millis(Instant::now().duration_since(before)); diff --git a/src/renderer.rs b/src/renderer.rs index 1a01cc7..28b0a1f 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -162,11 +162,11 @@ impl Renderer { NoIndices(PrimitiveType::TrianglesList), &self.program, &uniform!( - diffuse: Into::<[f32; 3]>::into(diffuse), + diffuse: Into::<[f64; 3]>::into(diffuse), tex: texture, - perspective: Into::<[[f32; 4]; 4]>::into(perspective), - view: Into::<[[f32; 4]; 4]>::into(view), - texture_size: Into::<[f32; 3]>::into(size), + perspective: Into::<[[f64; 4]; 4]>::into(perspective), + view: Into::<[[f64; 4]; 4]>::into(view), + texture_size: Into::<[f64; 3]>::into(size), ), ¶ms, ).unwrap(); @@ -178,7 +178,7 @@ impl Renderer { } /// Renders a part of a model. - fn get_texture_of_part<'a>(&self, model: &'a Model, part: &Part) -> Option<(&'a SrgbTexture2d, Vector3)> { + fn get_texture_of_part<'a>(&self, model: &'a Model, part: &Part) -> Option<(&'a SrgbTexture2d, Vector3)> { if let Some(ref material_name) = part.material_name { if let Some(ref material) = model.materials.get(material_name) { if let Some((texture, size)) = material.textures.get("map_Kd") { From 30c4bf5c3a55f34e5b1e34267309ce64d3f7676f Mon Sep 17 00:00:00 2001 From: Thomas Forgione Date: Mon, 23 Jul 2018 11:43:34 +0200 Subject: [PATCH 5/5] f32 in renderer --- src/camera.rs | 5 +++++ src/renderer.rs | 19 ++++++++++--------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/camera.rs b/src/camera.rs index 1c84885..1b4e9cb 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -6,6 +6,11 @@ use nalgebra::Vector4; use math::vector::{Vector2, Vector3}; use math::frustum::Frustum; +/// Converts a Matrix4 into a Matrix4 +pub fn mat_to_f32(mat: Matrix4) -> Matrix4 { + mat.map(|x| x as f32) +} + /// The trait that a render camera should implement. /// /// It allows the renderer to use it. diff --git a/src/renderer.rs b/src/renderer.rs index 28b0a1f..d9cef6c 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -16,7 +16,7 @@ use glium::index::{NoIndices, PrimitiveType}; use glium::glutin::GlWindow; use scene::Scene; -use camera::RenderCamera; +use camera::{RenderCamera, mat_to_f32}; use model::{Vertex, Part, Model}; use math::vector::Vector3; @@ -124,8 +124,8 @@ impl Renderer { let mut target = self.draw(); target.clear_color_srgb_and_depth(self.clear_color, 1.0); - let perspective = camera.perspective(); - let view = camera.view(); + let perspective = mat_to_f32(camera.perspective()); + let view = mat_to_f32(camera.view()); let params = DrawParameters { depth: Depth { @@ -144,7 +144,8 @@ impl Renderer { if let &Some(ref buffer) = part.vertex_buffer() { let diffuse = if let Some(ref name) = part.material_name { - model.materials.get(name).unwrap().diffuse + let t = model.materials.get(name).unwrap().diffuse; + Vector3::new(t[0] as f32, t[1] as f32, t[2] as f32) } else { Vector3::new(1.0, 1.0, 1.0) }; @@ -152,7 +153,7 @@ impl Renderer { let texture = self.get_texture_of_part(&model, part); let (texture, size) = if let Some((texture, size)) = texture { - (texture, size) + (texture, Vector3::new(size[0] as f32, size[1] as f32, size[2] as f32)) } else { (&self.default_texture, Vector3::new(1.0, 1.0, 1.0)) }; @@ -162,11 +163,11 @@ impl Renderer { NoIndices(PrimitiveType::TrianglesList), &self.program, &uniform!( - diffuse: Into::<[f64; 3]>::into(diffuse), + diffuse: Into::<[f32; 3]>::into(diffuse), tex: texture, - perspective: Into::<[[f64; 4]; 4]>::into(perspective), - view: Into::<[[f64; 4]; 4]>::into(view), - texture_size: Into::<[f64; 3]>::into(size), + perspective: Into::<[[f32; 4]; 4]>::into(perspective), + view: Into::<[[f32; 4]; 4]>::into(view), + texture_size: Into::<[f32; 3]>::into(size), ), ¶ms, ).unwrap();