Merge branch 'master' of gitea.tforgione.fr:dash-3d/model-converter

This commit is contained in:
Thomas Forgione 2018-07-26 11:09:51 +02:00
commit e19ae639e4
No known key found for this signature in database
GPG Key ID: 3B8FC64F5BBFE109
11 changed files with 261 additions and 146 deletions

View File

@ -1,137 +1,190 @@
//! This module contains everything to deal with cameras. //! This module contains everything to deal with cameras.
use nalgebra::Matrix4; use nalgebra::Matrix4;
use nalgebra::Vector4;
use math::vector::Vector3; use math::vector::{Vector2, Vector3};
use math::frustum::Frustum; use math::frustum::Frustum;
/// Converts a Matrix4<f64> into a Matrix4<f32>
pub fn mat_to_f32(mat: Matrix4<f64>) -> Matrix4<f32> {
mat.map(|x| x as f32)
}
/// The trait that a render camera should implement. /// The trait that a render camera should implement.
/// ///
/// It allows the renderer to use it. /// It allows the renderer to use it.
pub trait RenderCamera { pub trait RenderCamera {
/// Returns the view matrix of the camera. /// Returns the view matrix of the camera.
fn get_view_matrix(&self) -> Matrix4<f32>; fn view(&self) -> Matrix4<f64>;
/// Returns the perspective matrix of the camera. /// Returns the perspective matrix of the camera.
fn get_perspective_matrix(&self) -> Matrix4<f32>; fn perspective(&self) -> Matrix4<f64>;
/// Returns the product of the perspective matrix and the view matrix. /// Returns the product of the perspective matrix and the view matrix.
fn get_model_view_matrix(&self) -> Matrix4<f32> { fn model_view(&self) -> Matrix4<f64> {
self.get_perspective_matrix() * self.get_view_matrix().try_inverse().unwrap() self.perspective() * self.view()
} }
/// Returns the frustum of the camera. /// Returns the frustum of the camera.
fn frustum(&self) -> Frustum { 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. /// Creates the pose matrix, inverse of the look at matrix.
pub fn look_at_matrix(position: [f32; 3], target: [f32; 3], up: [f32; 3]) -> Matrix4<f32> { pub fn pose(position: Vector3<f64>, target: Vector3<f64>, up: Vector3<f64>) -> Matrix4<f64> {
let f = { // This is the right way to do things
let f = [ let e3 = (position - target).normalized();
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]
};
let s = [up[1] * f[2] - up[2] * f[1], // Well, ok, maybe this is not the right way, but it works
up[2] * f[0] - up[0] * f[2], let e1 = up.cross_product(e3).normalized();
up[0] * f[1] - up[1] * f[0]]; let e2 = e3.cross_product(e1);
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]];
[ [
[-s_norm[0], u[0], f[0], 0.0], [e1[0], e1[1], e1[2], 0.0],
[-s_norm[1], u[1], f[1], 0.0], [e2[0], e2[1], e2[2], 0.0],
[-s_norm[2], u[2], f[2], 0.0], [e3[0], e3[1], e3[2], 0.0],
[-p[0], p[1], p[2], 1.0], [position[0], position[1], position[2], 1.0],
].into() ].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<f64>, target: Vector3<f64>, up: Vector3<f64>) -> Matrix4<f64> {
pose(position, target, up).try_inverse().unwrap()
} }
/// Creates a perspective matrix of a camera. /// Creates a perspective matrix of a camera.
pub fn perspective_matrix(aspect_ratio: f32, z_near: f32, z_far: f32) -> Matrix4<f32> { pub fn perspective(fov: f64, aspect_ratio: f64, z_near: f64, z_far: f64) -> Matrix4<f64> {
let fov = 3.141592 / 3.0;
use num::Float; let top = z_near * (fov / 2.0).tan();
let f = 1.0 / (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: f64, aspect_ratio: f64, z_near: f64, z_far: f64) -> Matrix4<f64> {
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. /// A simple camera with its position, target and up vector.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Camera { pub struct Camera {
/// The position of the center of the camera. /// The position of the center of the camera.
pub position: Vector3<f32>, pub position: Vector3<f64>,
/// The 3D point the camera is targetting. /// The 3D point the camera is targetting.
pub target: Vector3<f32>, pub target: Vector3<f64>,
/// The up vector of the camera. /// The up vector of the camera.
pub up: Vector3<f32>, pub up: Vector3<f64>,
/// The field of view of the camera.
pub fov: f64,
/// The minimum depth for visible things. /// The minimum depth for visible things.
pub z_near: f32, pub z_near: f64,
/// The maximum depth for visible things. /// The maximum depth for visible things.
pub z_far: f32, pub z_far: f64,
/// The aspect ratio of the camera. /// The aspect ratio of the camera.
pub aspect_ratio: f32, pub aspect_ratio: f64,
} }
impl Camera { impl Camera {
/// Creates a new camera from its attributes. /// Creates a new camera from its attributes.
pub fn new(position: Vector3<f32>, target: Vector3<f32>, up: Vector3<f32>) -> Camera { pub fn new(position: Vector3<f64>, target: Vector3<f64>, up: Vector3<f64>) -> Camera {
use std::f64::consts::PI;
Camera { Camera {
position: position, position: position,
target: target, target: target,
up: up, up: up,
z_near: 0.0001, z_near: 0.0001,
z_far: 1000.0, 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<f64> {
pose(self.position, self.target, self.up)
}
/// Returns the view matrix of the camera, inverse of the pose.
pub fn view(&self) -> Matrix4<f64> {
look_at(self.position, self.target, self.up)
}
/// Returns the perspective matrix of the camera.
pub fn perspective(&self) -> Matrix4<f64> {
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<f64> {
perspective_inverse(self.fov, self.aspect_ratio, self.z_near, self.z_far)
}
/// Returns the frustum of the camera. /// Returns the frustum of the camera.
pub fn frustum(&self) -> Frustum { 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<f64>) -> Vector3<f64> {
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 { impl RenderCamera for Camera {
fn get_view_matrix(&self) -> Matrix4<f32> { fn view(&self) -> Matrix4<f64> {
look_at_matrix(self.position.into(), self.target.into(), self.up.into()) self.view()
} }
fn get_perspective_matrix(&self) -> Matrix4<f32> { fn perspective(&self) -> Matrix4<f64> {
perspective_matrix(self.aspect_ratio, self.z_near, self.z_far) self.perspective()
} }
} }

View File

@ -1,6 +1,6 @@
//! This models contains structs that help move the camera in a user-friendly way. //! 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::{ use glium::glutin::{
Event, Event,
@ -33,31 +33,31 @@ pub trait Controls {
/// Only object centered are supported. /// Only object centered are supported.
pub struct OrbitControls { pub struct OrbitControls {
/// The last position of the mouse. /// The last position of the mouse.
mouse_position: Vector2<f32>, mouse_position: Vector2<f64>,
/// Wether the left click of the mouse is pressed or not. /// Wether the left click of the mouse is pressed or not.
pressed: bool, pressed: bool,
/// The theta angle of the position of the camera in spheric coordinates. /// 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. /// The phi angle of the position of the camera in spheric coordinates.
phi: f32, phi: f64,
/// The distance between the camera and the origin. /// The distance between the camera and the origin.
distance: f32, distance: f64,
/// The sensitiviy of the rotation of the mouse. /// The sensitiviy of the rotation of the mouse.
sensitivity: f32, sensitivity: f64,
/// The center of the object. /// The center of the object.
center: Vector3<f32>, center: Vector3<f64>,
} }
impl OrbitControls { impl OrbitControls {
/// Creates a new orbit controls, and initializes the camera. /// Creates a new orbit controls, and initializes the camera.
pub fn new(center: Vector3<f32>, distance: f32, camera: &mut Camera) -> OrbitControls { pub fn new(center: Vector3<f64>, distance: f64, camera: &mut Camera) -> OrbitControls {
let controls = OrbitControls { let controls = OrbitControls {
mouse_position: Vector2::new(0.0, 0.0), mouse_position: Vector2::new(0.0, 0.0),
pressed: false, pressed: false,
@ -85,8 +85,8 @@ impl OrbitControls {
let distance = (bounding_box.max() - bounding_box.min()).norm(); let distance = (bounding_box.max() - bounding_box.min()).norm();
OrbitControls::new( OrbitControls::new(
Vector3::new(center.x() as f32, center.y() as f32, center.z() as f32), Vector3::new(center.x() as f64, center.y() as f64, center.z() as f64),
distance as f32, distance as f64,
camera camera
) )
@ -109,7 +109,7 @@ impl Controls for OrbitControls {
Event::WindowEvent { Event::WindowEvent {
event: WindowEvent::Resized(width, height), .. 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 { Event::WindowEvent {
@ -117,7 +117,7 @@ impl Controls for OrbitControls {
delta: MouseScrollDelta::LineDelta(_, y), .. 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.x_mut() = self.distance * self.phi.cos() * self.theta.cos();
*camera.position.y_mut() = self.distance * self.phi.sin(); *camera.position.y_mut() = self.distance * self.phi.sin();
@ -132,7 +132,7 @@ impl Controls for OrbitControls {
position: (x, y), .. 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 { if self.pressed {
let difference = (current_position - self.mouse_position) / self.sensitivity; let difference = (current_position - self.mouse_position) / self.sensitivity;
@ -140,7 +140,7 @@ impl Controls for OrbitControls {
self.theta += difference.x(); self.theta += difference.x();
self.phi += difference.y(); 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.max(- PI/2.0 + EPSILON);
self.phi = self.phi.min( PI/2.0 - EPSILON); self.phi = self.phi.min( PI/2.0 - EPSILON);
@ -170,25 +170,25 @@ impl Controls for OrbitControls {
pub struct FirstPersonControls { pub struct FirstPersonControls {
/// Theta angle of the spheric coordinates of the direction of the camera. /// 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 angle of the spheric coordinates of the direction of the camera.
phi: f32, phi: f64,
/// Current position of the camera. /// Current position of the camera.
position: Vector3<f32>, position: Vector3<f64>,
/// Vector indicating the direction of the camera. /// Vector indicating the direction of the camera.
forward: Vector3<f32>, forward: Vector3<f64>,
/// Vector indicating the left of the camera. /// Vector indicating the left of the camera.
left: Vector3<f32>, left: Vector3<f64>,
/// Speed of the camera. /// Speed of the camera.
speed: f32, speed: f64,
/// Sensitivity of the mouse. /// Sensitivity of the mouse.
sensitivity: f32, sensitivity: f64,
/// Wether the forward button is pressed or not. /// Wether the forward button is pressed or not.
forward_pressed: bool, forward_pressed: bool,
@ -241,7 +241,7 @@ impl Controls for FirstPersonControls {
Event::WindowEvent { Event::WindowEvent {
event: WindowEvent::Resized(width, height), .. 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 // On Z pressed
@ -307,14 +307,14 @@ impl Controls for FirstPersonControls {
} => { } => {
let size = renderer.gl_window().window().get_inner_size().unwrap(); 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 center = Vector2::new(size.0 as f64 / 2.0, size.1 as f64 / 2.0);
let current_position = Vector2::new(x as f32, y as f32); let current_position = Vector2::new(x as f64, y as f64);
let difference = (current_position - center) / self.sensitivity; let difference = (current_position - center) / self.sensitivity;
self.theta += difference.x(); self.theta += difference.x();
self.phi -= difference.y(); 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.max(- PI/2.0 + EPSILON);
self.phi = self.phi.min( PI/2.0 - EPSILON); self.phi = self.phi.min( PI/2.0 - EPSILON);

View File

@ -95,6 +95,16 @@ macro_rules! make_bounding_box {
ret ret
} }
/// Returns true if the point is inside the bounding box.
pub fn contains_point(&self, point: $vector<T>) -> bool {
for i in 0 .. $size {
if self.min()[i] > point[i] || point[i] > self.max()[i] {
return false;
}
}
true
}
} }
} }
@ -116,10 +126,10 @@ macro_rules! impl_center {
} }
impl_center!(BoundingBox2, Vector2, f32); impl_center!(BoundingBox2, Vector2, f32);
impl_center!(BoundingBox2, Vector2, f64);
impl_center!(BoundingBox3, Vector3, f32); impl_center!(BoundingBox3, Vector3, f32);
impl_center!(BoundingBox3, Vector3, f64);
impl_center!(BoundingBox4, Vector4, f32); impl_center!(BoundingBox4, Vector4, f32);
impl_center!(BoundingBox2, Vector2, f64);
impl_center!(BoundingBox3, Vector3, f64);
impl_center!(BoundingBox4, Vector4, f64); impl_center!(BoundingBox4, Vector4, f64);
@ -183,4 +193,21 @@ mod tests {
let bb2 = b2.intersection(&b1); let bb2 = b2.intersection(&b1);
assert_eq!(bb1, bb2); 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);
}
} }

View File

@ -17,15 +17,27 @@ pub struct Frustum {
} }
impl Frustum { impl Frustum {
/// Creates a frustum from the matrix of a camera.
///
/// This is *ahem...* slightly inspired from THREE.js Frustum
pub fn from_matrix(m: &Matrix4<f32>) -> Frustum {
let m0 = m[(0, 0)]; let m1 = m[(0, 1)]; let m2 = m[(0, 2)]; let m3 = m[(0, 3)]; /// Creates a frustum from its four planes.
let m4 = m[(1, 0)]; let m5 = m[(1, 1)]; let m6 = m[(1, 2)]; let m7 = m[(1, 3)]; pub fn new(planes: [Plane; 6]) -> Frustum {
let m8 = m[(2, 0)]; let m9 = m[(2, 1)]; let m10 = m[(2, 2)]; let m11 = m[(2, 3)]; Frustum {
let m12 = m[(3, 0)]; let m13 = m[(3, 1)]; let m14 = m[(3, 2)]; let m15 = m[(3, 3)]; planes: planes,
}
}
/// Creates a frustum for a camera matrix.
pub fn from_matrix(m: &Matrix4<f64>) -> 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)];
// 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 { Frustum {
planes: [ planes: [
@ -40,26 +52,19 @@ impl Frustum {
} }
/// Returns true if the intersection of the frustum and the bounding box is not empty. /// Returns true if the intersection of the frustum and the bounding box is not empty.
pub fn intersects_box(&self, bbox: BoundingBox3<f32>) -> bool { pub fn intersects_box(&self, bbox: BoundingBox3<f64>) -> bool {
use num::Zero; use num::Zero;
let mut p1 = Vector3::<f32>::zero(); let mut p = Vector3::<f64>::zero();
let mut p2 = Vector3::<f32>::zero();
for plane in &self.planes { for plane in &self.planes {
p1[0] = if plane.normal().x() > 0.0 { bbox.min().x() } else { bbox.max().x() }; p[0] = if plane.normal().x() > 0.0 { bbox.max().x() } else { bbox.min().x() };
p2[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() };
p1[1] = if plane.normal().y() > 0.0 { bbox.min().y() } else { bbox.max().y() }; p[2] = if plane.normal().z() > 0.0 { bbox.max().z() } else { bbox.min().z() };
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() };
let d1 = plane.distance_to_point(p1); if plane.distance_to_point(p) < 0.0 {
let d2 = plane.distance_to_point(p2);
if d1 < 0.0 && d2 < 2.0 {
return false; return false;
} }
} }

View File

@ -6,15 +6,15 @@ use math::vector::Vector3;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Plane { pub struct Plane {
/// The normal of the plane. /// The normal of the plane.
normal: Vector3<f32>, normal: Vector3<f64>,
/// The constant, offset of the plane from the origin. /// The constant, offset of the plane from the origin.
constant: f32, constant: f64,
} }
impl Plane { impl Plane {
/// Creates a new plane from its normal and its constant. /// 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 { let mut p = Plane {
normal: Vector3::new(a, b, c), normal: Vector3::new(a, b, c),
constant: w, constant: w,
@ -24,18 +24,18 @@ impl Plane {
} }
/// Creates a new plane from its normal and its constant. /// Creates a new plane from its normal and its constant.
pub fn from_normal_and_constant(normal: Vector3<f32>, constant: f32) -> Plane { pub fn from_normal_and_constant(normal: Vector3<f64>, constant: f64) -> Plane {
Plane::from_coordinates(normal.x(), normal.y(), normal.z(), constant) Plane::from_coordinates(normal.x(), normal.y(), normal.z(), constant)
} }
/// Creates a new plane from its normal and a point of the plane. /// Creates a new plane from its normal and a point of the plane.
pub fn from_normal_and_point(normal: Vector3<f32>, point: Vector3<f32>) -> Plane { pub fn from_normal_and_point(normal: Vector3<f64>, point: Vector3<f64>) -> Plane {
Plane::from_normal_and_constant(normal, - point.dot(normal)) Plane::from_normal_and_constant(normal, - point.dot(normal))
} }
/// Creates a new plane from three points. /// Creates a new plane from three points.
pub fn from_points(p1: Vector3<f32>, p2: Vector3<f32>, p3: Vector3<f32>) -> Plane { pub fn from_points(p1: Vector3<f64>, p2: Vector3<f64>, p3: Vector3<f64>) -> Plane {
let p1p2 = p2 - p1; let p1p2 = p2 - p1;
let p1p3 = p3 - p1; let p1p3 = p3 - p1;
Plane::from_normal_and_point(p1p2.cross_product(p1p3), p1) Plane::from_normal_and_point(p1p2.cross_product(p1p3), p1)
@ -49,17 +49,17 @@ impl Plane {
} }
/// Returns the normal of the plane. /// Returns the normal of the plane.
pub fn normal(&self) -> Vector3<f32> { pub fn normal(&self) -> Vector3<f64> {
self.normal self.normal
} }
/// Returns the constant of the plane. /// Returns the constant of the plane.
pub fn constant(&self) -> f32 { pub fn constant(&self) -> f64 {
self.constant self.constant
} }
/// Returns the distance between the plane and the point. /// Returns the distance between the plane and the point.
pub fn distance_to_point(&self, point: Vector3<f32>) -> f32 { pub fn distance_to_point(&self, point: Vector3<f64>) -> f64 {
self.normal.dot(point) + self.constant self.normal.dot(point) + self.constant
} }
} }

View File

@ -39,6 +39,14 @@ macro_rules! make_vector {
} }
} }
impl<T> From<[T; $number]> for $name<T> {
fn from(data: [T; $number]) -> $name<T> {
$name {
data: data,
}
}
}
impl<T: Copy + Clone> Into<($( $t ) ,* )> for $name<T> { impl<T: Copy + Clone> Into<($( $t ) ,* )> for $name<T> {
fn into(self) -> ($( $t ) ,* ) { fn into(self) -> ($( $t ) ,* ) {
( $( self.data[$y] ), *) ( $( self.data[$y] ), *)
@ -239,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!(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)); 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<f32> { impl Vector2<f64> {
/// Returns a orthogonal vector to the one passed as parameter. /// Returns a orthogonal vector to the one passed as parameter.
pub fn orthogonal(&self) -> Vector2<f32> { pub fn orthogonal(&self) -> Vector2<f64> {
Vector2::new( Vector2::new(
self.y(), self.y(),
self.x() * -1.0, self.x() * -1.0,
@ -283,10 +291,10 @@ impl Vector3<f64> {
} }
type Vector2f32 = Vector2<f32>; implement_vertex!(Vector2f32, data); type Vector2f32 = Vector2<f32>; implement_vertex!(Vector2f32, data);
type Vector2f64 = Vector2<f64>; implement_vertex!(Vector2f64, data);
type Vector3f32 = Vector3<f32>; implement_vertex!(Vector3f32, data); type Vector3f32 = Vector3<f32>; implement_vertex!(Vector3f32, data);
type Vector3f64 = Vector3<f64>; implement_vertex!(Vector3f64, data);
type Vector4f32 = Vector4<f32>; implement_vertex!(Vector4f32, data); type Vector4f32 = Vector4<f32>; implement_vertex!(Vector4f32, data);
type Vector2f64 = Vector2<f64>; implement_vertex!(Vector2f64, data);
type Vector3f64 = Vector3<f64>; implement_vertex!(Vector3f64, data);
type Vector4f64 = Vector4<f64>; implement_vertex!(Vector4f64, data); type Vector4f64 = Vector4<f64>; implement_vertex!(Vector4f64, data);
#[cfg(test)] #[cfg(test)]

View File

@ -11,10 +11,10 @@ pub struct Material {
pub name: String, pub name: String,
/// The diffuse color of the material. /// The diffuse color of the material.
pub diffuse: Vector3<f32>, pub diffuse: Vector3<f64>,
/// Map linking each texture map to its file path. /// Map linking each texture map to its file path.
pub textures: HashMap<String, (String, Vector3<f32>)>, pub textures: HashMap<String, (String, Vector3<f64>)>,
/// Instructions that are unknown. /// Instructions that are unknown.
/// ///

View File

@ -47,10 +47,10 @@ pub enum Element {
/// First string is the name of the map. /// First string is the name of the map.
/// Second string is the path to the image file. /// Second string is the path to the image file.
/// Vector3 is the size of the texture. /// Vector3 is the size of the texture.
Texture(String, String, Vector3<f32>), Texture(String, String, Vector3<f64>),
/// Change the main color of the current material. /// Change the main color of the current material.
Diffuse(Vector3<f32>), Diffuse(Vector3<f64>),
/// An unknown material instruction that will be copied into the mtl file. /// An unknown material instruction that will be copied into the mtl file.
UnknownMaterialInstruction(String), UnknownMaterialInstruction(String),

View File

@ -46,9 +46,9 @@ impl LineParser for MtlParser {
"Kd" => { "Kd" => {
let values = parse_values(line_number, line, path, 3)?; let values = parse_values(line_number, line, path, 3)?;
Ok(Element::Diffuse(Vector3::new( Ok(Element::Diffuse(Vector3::new(
values[0] as f32, values[0] as f64,
values[1] as f32, values[1] as f64,
values[2] as f32, 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))) 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" { } else if split[0] == "-s" {
let size = Vector3::new( let size = Vector3::new(
if let Ok(f) = split[1].parse::<f32>() { f } else { return Err(ParserError::ParseNumberError(path.to_owned(), line_number, split[1].to_owned())); }, if let Ok(f) = split[1].parse::<f64>() { f } else { return Err(ParserError::ParseNumberError(path.to_owned(), line_number, split[1].to_owned())); },
if let Ok(f) = split[2].parse::<f32>() { f } else { return Err(ParserError::ParseNumberError(path.to_owned(), line_number, split[2].to_owned())); }, if let Ok(f) = split[2].parse::<f64>() { f } else { return Err(ParserError::ParseNumberError(path.to_owned(), line_number, split[2].to_owned())); },
if let Ok(f) = split[3].parse::<f32>() { f } else { return Err(ParserError::ParseNumberError(path.to_owned(), line_number, split[3].to_owned())); }, if let Ok(f) = split[3].parse::<f64>() { f } else { return Err(ParserError::ParseNumberError(path.to_owned(), line_number, split[3].to_owned())); },
); );
let mut full_path = root.clone(); let mut full_path = root.clone();
full_path.push(split[4].to_owned()); full_path.push(split[4].to_owned());

View File

@ -14,9 +14,12 @@ use glium::Display;
use glium::glutin; use glium::glutin;
use glium::glutin::{EventsLoop, WindowBuilder}; use glium::glutin::{EventsLoop, WindowBuilder};
use glium::glutin::Event; use glium::glutin::{
use glium::glutin::WindowEvent; Event,
use glium::glutin::VirtualKeyCode; WindowEvent,
VirtualKeyCode,
ElementState,
};
use model_converter::scene::Scene; use model_converter::scene::Scene;
use model_converter::math::bounding_box::BoundingBox3; use model_converter::math::bounding_box::BoundingBox3;
@ -53,9 +56,7 @@ fn main() {
.get_matches(); .get_matches();
// Set verbose flag // Set verbose flag
verbose_log::log::VERBOSE.with(|verbose| { verbose_log::set(matches.occurrences_of("verbose") > 0);
*verbose.borrow_mut() = matches.occurrences_of("verbose") > 0;
});
use std::f64::{MIN, MAX}; use std::f64::{MIN, MAX};
let mut bbox = BoundingBox3::new( let mut bbox = BoundingBox3::new(
@ -153,11 +154,31 @@ fn main() {
Event::WindowEvent { Event::WindowEvent {
event: WindowEvent::KeyboardInput { event: WindowEvent::KeyboardInput {
input: glutin::KeyboardInput { input: glutin::KeyboardInput {
virtual_keycode: Some(VirtualKeyCode::Escape), .. virtual_keycode: Some(VirtualKeyCode::Escape),
state: ElementState::Pressed, ..
}, .. }, ..
}, .. }, ..
} => closed = true, } => closed = true,
// Enter key
Event::WindowEvent {
event: WindowEvent::KeyboardInput {
input: glutin::KeyboardInput {
virtual_keycode: Some(VirtualKeyCode::Return),
state: ElementState::Pressed, ..
}, ..
}, ..
} => {
println!("Camera:");
println!("\tPosition: ({}, {}, {})",
camera.position.x(), camera.position.y(), camera.position.z());
println!("\tTarget: ({}, {}, {})",
camera.target.x(), camera.target.y(), camera.target.z());
println!("\tUp: ({}, {}, {})",
camera.up.x(), camera.up.y(), camera.up.z());
}
_ => (), _ => (),
} }
}); });

View File

@ -16,7 +16,7 @@ use glium::index::{NoIndices, PrimitiveType};
use glium::glutin::GlWindow; use glium::glutin::GlWindow;
use scene::Scene; use scene::Scene;
use camera::RenderCamera; use camera::{RenderCamera, mat_to_f32};
use model::{Vertex, Part, Model}; use model::{Vertex, Part, Model};
use math::vector::Vector3; use math::vector::Vector3;
@ -124,8 +124,8 @@ impl Renderer {
let mut target = self.draw(); let mut target = self.draw();
target.clear_color_srgb_and_depth(self.clear_color, 1.0); target.clear_color_srgb_and_depth(self.clear_color, 1.0);
let perspective = camera.get_perspective_matrix(); let perspective = mat_to_f32(camera.perspective());
let view = camera.get_view_matrix(); let view = mat_to_f32(camera.view());
let params = DrawParameters { let params = DrawParameters {
depth: Depth { depth: Depth {
@ -144,7 +144,8 @@ impl Renderer {
if let &Some(ref buffer) = part.vertex_buffer() { if let &Some(ref buffer) = part.vertex_buffer() {
let diffuse = if let Some(ref name) = part.material_name { 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 { } else {
Vector3::new(1.0, 1.0, 1.0) 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 = self.get_texture_of_part(&model, part);
let (texture, size) = if let Some((texture, size)) = texture { 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 { } else {
(&self.default_texture, Vector3::new(1.0, 1.0, 1.0)) (&self.default_texture, Vector3::new(1.0, 1.0, 1.0))
}; };
@ -178,7 +179,7 @@ impl Renderer {
} }
/// Renders a part of a model. /// Renders a part of a model.
fn get_texture_of_part<'a>(&self, model: &'a Model, part: &Part) -> Option<(&'a SrgbTexture2d, Vector3<f32>)> { fn get_texture_of_part<'a>(&self, model: &'a Model, part: &Part) -> Option<(&'a SrgbTexture2d, Vector3<f64>)> {
if let Some(ref material_name) = part.material_name { if let Some(ref material_name) = part.material_name {
if let Some(ref material) = model.materials.get(material_name) { if let Some(ref material) = model.materials.get(material_name) {
if let Some((texture, size)) = material.textures.get("map_Kd") { if let Some((texture, size)) = material.textures.get("map_Kd") {