model-converter/src/renderer/camera.rs

118 lines
3.2 KiB
Rust

use math::vector::Vector3;
pub trait RenderCamera {
fn get_view_matrix(&self) -> [[f32; 4]; 4];
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],
]
}
}
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],
]
}
pub struct Camera {
pub position: Vector3<f32>,
pub target: Vector3<f32>,
pub up: Vector3<f32>,
}
impl Camera {
pub fn new(position: Vector3<f32>, target: Vector3<f32>, up: Vector3<f32>) -> 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())
}
}
pub struct RotatingCamera {
distance: f32,
theta: f32,
}
impl RotatingCamera {
pub fn new(distance: f32) -> RotatingCamera {
RotatingCamera {
distance: distance,
theta: 0.0,
}
}
pub fn increase_theta(&mut self, dt: f32) {
self.theta += dt;
}
}
impl RenderCamera for RotatingCamera {
fn get_view_matrix(&self) -> [[f32; 4]; 4] {
let position = Vector3::new(
self.distance * self.theta.cos(),
0.0,
self.distance * self.theta.sin(),
);
let target = Vector3::new(0.0, 0.0, 0.0);
let up = Vector3::new(0.0, 1.0, 0.0);
look_at_matrix(position.into(), target.into(), up.into())
}
}