//! This module contains everything to deal with cameras. use math::vector::Vector3; /// The trait that a render camera should implement. /// /// It allows the renderer to use it. pub trait RenderCamera { /// Returns the view matrix of the camera. fn get_view_matrix(&self) -> [[f32; 4]; 4]; /// Returns the perspective matrix of the camera. fn get_perspective_matrix(&self, dimensions: (u32, u32)) -> [[f32; 4]; 4] { let (width, height) = dimensions; let aspect_ratio = height as f32 / width as f32; let fov = 3.141592 / 3.0; let zfar = 1024.0; let znear = 0.1; use num::Float; let f = 1.0 / (fov / 2.0).tan(); [ [f * aspect_ratio , 0.0, 0.0 , 0.0], [ 0.0 , f , 0.0 , 0.0], [ 0.0 , 0.0, (zfar+znear)/(zfar-znear) , 1.0], [ 0.0 , 0.0, -(2.0*zfar*znear)/(zfar-znear), 0.0], ] } } /// 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]) -> [[f32; 4]; 4] { 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] }; 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]]; [ [-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], ] } /// A simple camera with its position, target and up vector. pub struct Camera { /// The position of the center of the camera. pub position: Vector3, /// The 3D point the camera is targetting. pub target: Vector3, /// The up vector of the camera. pub up: Vector3, } impl Camera { /// Creates a new camera from its attributes. pub fn new(position: Vector3, target: Vector3, up: Vector3) -> Camera { Camera { position: position, target: target, up: up, } } } impl RenderCamera for Camera { fn get_view_matrix(&self) -> [[f32; 4]; 4] { look_at_matrix(self.position.into(), self.target.into(), self.up.into()) } }