model-converter/src/camera.rs

191 lines
5.2 KiB
Rust
Raw Permalink Normal View History

2018-04-10 15:25:01 +02:00
//! This module contains everything to deal with cameras.
2018-06-14 22:03:43 +02:00
use nalgebra::Matrix4;
2018-07-19 14:24:54 +02:00
use nalgebra::Vector4;
2018-06-14 22:03:43 +02:00
2018-07-19 14:24:54 +02:00
use math::vector::{Vector2, Vector3};
2018-06-12 17:22:16 +02:00
use math::frustum::Frustum;
2018-07-23 11:43:34 +02:00
/// Converts a Matrix4<f64> into a Matrix4<f32>
pub fn mat_to_f32(mat: Matrix4<f64>) -> Matrix4<f32> {
mat.map(|x| x as f32)
}
2018-04-10 15:25:01 +02:00
/// The trait that a render camera should implement.
///
/// It allows the renderer to use it.
2018-04-10 15:13:35 +02:00
pub trait RenderCamera {
2018-04-10 15:25:01 +02:00
/// Returns the view matrix of the camera.
2018-07-23 10:12:37 +02:00
fn view(&self) -> Matrix4<f64>;
2018-04-10 15:25:01 +02:00
/// Returns the perspective matrix of the camera.
2018-07-23 10:12:37 +02:00
fn perspective(&self) -> Matrix4<f64>;
2018-06-12 17:22:16 +02:00
/// Returns the product of the perspective matrix and the view matrix.
2018-07-23 10:12:37 +02:00
fn model_view(&self) -> Matrix4<f64> {
2018-07-19 14:24:54 +02:00
self.perspective() * self.view()
2018-06-12 17:22:16 +02:00
}
/// Returns the frustum of the camera.
fn frustum(&self) -> Frustum {
2018-07-19 14:24:54 +02:00
panic!();
2018-06-12 17:22:16 +02:00
}
2018-04-11 17:03:32 +02:00
2018-02-27 11:42:35 +01:00
}
2018-07-19 14:24:54 +02:00
/// Creates the pose matrix, inverse of the look at matrix.
2018-07-23 10:12:37 +02:00
pub fn pose(position: Vector3<f64>, target: Vector3<f64>, up: Vector3<f64>) -> Matrix4<f64> {
2018-07-19 14:24:54 +02:00
// This is the right way to do things
let e3 = (position - target).normalized();
// 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);
2018-02-27 11:42:35 +01:00
[
2018-07-19 14:24:54 +02:00
[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],
2018-06-14 22:03:43 +02:00
].into()
2018-07-19 14:24:54 +02:00
}
2018-02-27 11:42:35 +01:00
2018-07-19 14:24:54 +02:00
/// Creates a look at matrix from the center, the target pointed by the camera and the up vector.
2018-07-23 10:12:37 +02:00
pub fn look_at(position: Vector3<f64>, target: Vector3<f64>, up: Vector3<f64>) -> Matrix4<f64> {
2018-07-19 14:24:54 +02:00
pose(position, target, up).try_inverse().unwrap()
2018-02-27 11:42:35 +01:00
}
2018-04-11 17:03:32 +02:00
/// Creates a perspective matrix of a camera.
2018-07-23 10:12:37 +02:00
pub fn perspective(fov: f64, aspect_ratio: f64, z_near: f64, z_far: f64) -> Matrix4<f64> {
2018-04-11 17:03:32 +02:00
2018-07-19 14:24:54 +02:00
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.
2018-07-23 10:12:37 +02:00
pub fn perspective_inverse(fov: f64, aspect_ratio: f64, z_near: f64, z_far: f64) -> Matrix4<f64> {
2018-07-19 14:24:54 +02:00
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,
)
2018-04-11 17:03:32 +02:00
}
2018-04-10 15:25:01 +02:00
/// A simple camera with its position, target and up vector.
2018-06-15 14:49:54 +02:00
#[derive(Clone, Debug)]
2018-04-10 15:13:35 +02:00
pub struct Camera {
2018-04-10 15:25:01 +02:00
/// The position of the center of the camera.
2018-07-23 10:12:37 +02:00
pub position: Vector3<f64>,
2018-04-10 15:25:01 +02:00
/// The 3D point the camera is targetting.
2018-07-23 10:12:37 +02:00
pub target: Vector3<f64>,
2018-04-10 15:25:01 +02:00
/// The up vector of the camera.
2018-07-23 10:12:37 +02:00
pub up: Vector3<f64>,
2018-04-11 17:03:32 +02:00
2018-07-19 14:24:54 +02:00
/// The field of view of the camera.
2018-07-23 10:12:37 +02:00
pub fov: f64,
2018-07-19 14:24:54 +02:00
2018-04-11 17:03:32 +02:00
/// The minimum depth for visible things.
2018-07-23 10:12:37 +02:00
pub z_near: f64,
2018-04-11 17:03:32 +02:00
/// The maximum depth for visible things.
2018-07-23 10:12:37 +02:00
pub z_far: f64,
2018-04-11 17:03:32 +02:00
/// The aspect ratio of the camera.
2018-07-23 10:12:37 +02:00
pub aspect_ratio: f64,
2018-04-11 17:03:32 +02:00
2018-02-27 11:42:35 +01:00
}
2018-04-10 15:13:35 +02:00
impl Camera {
2018-04-10 15:25:01 +02:00
/// Creates a new camera from its attributes.
2018-07-23 10:12:37 +02:00
pub fn new(position: Vector3<f64>, target: Vector3<f64>, up: Vector3<f64>) -> Camera {
use std::f64::consts::PI;
2018-07-19 14:24:54 +02:00
2018-04-10 15:13:35 +02:00
Camera {
2018-02-27 11:42:35 +01:00
position: position,
target: target,
up: up,
2018-04-24 11:08:32 +02:00
z_near: 0.0001,
2018-04-11 17:03:32 +02:00
z_far: 1000.0,
2018-07-19 14:24:54 +02:00
aspect_ratio: 16.0 / 9.0,
fov: PI / 3.0,
2018-02-27 11:42:35 +01:00
}
}
2018-06-13 14:55:41 +02:00
2018-07-19 14:24:54 +02:00
/// Returns the pose matrix of the camera.
2018-07-23 10:12:37 +02:00
pub fn pose(&self) -> Matrix4<f64> {
2018-07-19 14:24:54 +02:00
pose(self.position, self.target, self.up)
}
/// Returns the view matrix of the camera, inverse of the pose.
2018-07-23 10:12:37 +02:00
pub fn view(&self) -> Matrix4<f64> {
2018-07-19 14:24:54 +02:00
look_at(self.position, self.target, self.up)
}
/// Returns the perspective matrix of the camera.
2018-07-23 10:12:37 +02:00
pub fn perspective(&self) -> Matrix4<f64> {
2018-07-19 14:24:54 +02:00
perspective(self.fov, self.aspect_ratio, self.z_near, self.z_far)
}
/// Returns the inverse of the perspective matrix of the camera.
2018-07-23 10:12:37 +02:00
pub fn perspective_inverse(&self) -> Matrix4<f64> {
2018-07-19 14:24:54 +02:00
perspective_inverse(self.fov, self.aspect_ratio, self.z_near, self.z_far)
}
2018-06-13 14:55:41 +02:00
/// Returns the frustum of the camera.
pub fn frustum(&self) -> Frustum {
2018-07-19 14:24:54 +02:00
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]
2018-07-23 10:12:37 +02:00
pub fn unproject(&self, point: Vector2<f64>) -> Vector3<f64> {
2018-07-19 14:24:54 +02:00
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])
2018-06-13 14:55:41 +02:00
}
2018-02-27 11:42:35 +01:00
}
2018-04-10 15:13:35 +02:00
impl RenderCamera for Camera {
2018-07-23 10:12:37 +02:00
fn view(&self) -> Matrix4<f64> {
2018-07-19 14:24:54 +02:00
self.view()
2018-02-27 11:42:35 +01:00
}
2018-04-11 17:03:32 +02:00
2018-07-23 10:12:37 +02:00
fn perspective(&self) -> Matrix4<f64> {
2018-07-19 14:24:54 +02:00
self.perspective()
2018-04-11 17:03:32 +02:00
}
2018-02-27 11:42:35 +01:00
}