Simplify projection code
This commit is contained in:
parent
6534855673
commit
aef1d153a1
2 changed files with 141 additions and 161 deletions
|
@ -101,6 +101,10 @@ impl<S: Clone + Float> Angle<S> for Deg<S> {
|
||||||
#[inline] pub fn tan<S: Clone + Float, A: Angle<S>>(theta: A) -> S { theta.to_rad().s.tan() }
|
#[inline] pub fn tan<S: Clone + Float, A: Angle<S>>(theta: A) -> S { theta.to_rad().s.tan() }
|
||||||
#[inline] pub fn sin_cos<S: Clone + Float, A: Angle<S>>(theta: A) -> (S, S) { theta.to_rad().s.sin_cos() }
|
#[inline] pub fn sin_cos<S: Clone + Float, A: Angle<S>>(theta: A) -> (S, S) { theta.to_rad().s.sin_cos() }
|
||||||
|
|
||||||
|
#[inline] pub fn cot<S: Clone + Float, A: Angle<S>>(theta: A) -> S { tan(theta).recip() }
|
||||||
|
#[inline] pub fn sec<S: Clone + Float, A: Angle<S>>(theta: A) -> S { cos(theta).recip() }
|
||||||
|
#[inline] pub fn csc<S: Clone + Float, A: Angle<S>>(theta: A) -> S { sin(theta).recip() }
|
||||||
|
|
||||||
#[inline] pub fn asin<S: Clone + Float, A: Angle<S>>(s: S) -> A { Angle::from(rad(s.asin())) }
|
#[inline] pub fn asin<S: Clone + Float, A: Angle<S>>(s: S) -> A { Angle::from(rad(s.asin())) }
|
||||||
#[inline] pub fn acos<S: Clone + Float, A: Angle<S>>(s: S) -> A { Angle::from(rad(s.acos())) }
|
#[inline] pub fn acos<S: Clone + Float, A: Angle<S>>(s: S) -> A { Angle::from(rad(s.acos())) }
|
||||||
#[inline] pub fn atan<S: Clone + Float, A: Angle<S>>(s: S) -> A { Angle::from(rad(s.atan())) }
|
#[inline] pub fn atan<S: Clone + Float, A: Angle<S>>(s: S) -> A { Angle::from(rad(s.atan())) }
|
||||||
|
|
|
@ -15,137 +15,123 @@
|
||||||
|
|
||||||
use std::num::{zero, one};
|
use std::num::{zero, one};
|
||||||
|
|
||||||
use angle::{Angle, Rad, rad, tan};
|
use angle::{Angle, rad, tan, cot};
|
||||||
use matrix::Mat4;
|
use matrix::{Mat4, ToMat4};
|
||||||
use util::two;
|
use util::two;
|
||||||
|
|
||||||
/// Create a perspective projection matrix
|
/// Create a perspective projection matrix.
|
||||||
///
|
///
|
||||||
/// Note: the fovy parameter should be specified in degrees.
|
/// This is the equivalent to the [gluPerspective]
|
||||||
///
|
/// (http://www.opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml) function.
|
||||||
/// This is the equivalent of the gluPerspective function, the algorithm of which
|
pub fn perspective<S: Clone + Float, A: Angle<S>>(fovy: A, aspect: S, near: S, far: S) -> Mat4<S> {
|
||||||
/// can be found [here](http://www.opengl.org/wiki/GluPerspective_code).
|
PerspectiveFov {
|
||||||
pub fn perspective<S: Clone + Float>(fovy: Rad<S>, aspectRatio: S, near: S, far: S) -> Mat4<S> {
|
fovy: fovy,
|
||||||
let ymax = near * tan(fovy.div_s(two::<S>()));
|
aspect: aspect,
|
||||||
let xmax = ymax * aspectRatio;
|
near: near,
|
||||||
|
far: far,
|
||||||
frustum(-xmax, xmax, -ymax, ymax, near, far)
|
}.to_mat4()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Define a view frustrum
|
/// Create a perspective matrix from a view frustrum.
|
||||||
///
|
///
|
||||||
/// This is the equivalent of the now deprecated [glFrustrum]
|
/// This is the equivalent of the now deprecated [glFrustrum]
|
||||||
/// (http://www.opengl.org/sdk/docs/man2/xhtml/glFrustum.xml) function.
|
/// (http://www.opengl.org/sdk/docs/man2/xhtml/glFrustum.xml) function.
|
||||||
pub fn frustum<S: Clone + Float>(left: S, right: S, bottom: S, top: S, near: S, far: S) -> Mat4<S> {
|
pub fn frustum<S: Clone + Float>(left: S, right: S, bottom: S, top: S, near: S, far: S) -> Mat4<S> {
|
||||||
let c0r0 = (two::<S>() * near) / (right - left);
|
Perspective {
|
||||||
let c0r1 = zero();
|
left: left,
|
||||||
let c0r2 = zero();
|
right: right,
|
||||||
let c0r3 = zero();
|
bottom: bottom,
|
||||||
|
top: top,
|
||||||
let c1r0 = zero();
|
near: near,
|
||||||
let c1r1 = (two::<S>() * near) / (top - bottom);
|
far: far,
|
||||||
let c1r2 = zero();
|
}.to_mat4()
|
||||||
let c1r3 = zero();
|
|
||||||
|
|
||||||
let c2r0 = (right + left) / (right - left);
|
|
||||||
let c2r1 = (top + bottom) / (top - bottom);
|
|
||||||
let c2r2 = -(far + near) / (far - near);
|
|
||||||
let c2r3 = -one::<S>();
|
|
||||||
|
|
||||||
let c3r0 = zero();
|
|
||||||
let c3r1 = zero();
|
|
||||||
let c3r2 = -(two::<S>() * far * near) / (far - near);
|
|
||||||
let c3r3 = zero();
|
|
||||||
|
|
||||||
Mat4::new(c0r0, c0r1, c0r2, c0r3,
|
|
||||||
c1r0, c1r1, c1r2, c1r3,
|
|
||||||
c2r0, c2r1, c2r2, c2r3,
|
|
||||||
c3r0, c3r1, c3r2, c3r3)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an orthographic projection matrix
|
/// Create an orthographic projection matrix.
|
||||||
///
|
///
|
||||||
/// This is the equivalent of the now deprecated [glOrtho]
|
/// This is the equivalent of the now deprecated [glOrtho]
|
||||||
/// (http://www.opengl.org/sdk/docs/man2/xhtml/glOrtho.xml) function.
|
/// (http://www.opengl.org/sdk/docs/man2/xhtml/glOrtho.xml) function.
|
||||||
pub fn ortho<S: Clone + Float>(left: S, right: S, bottom: S, top: S, near: S, far: S) -> Mat4<S> {
|
pub fn ortho<S: Clone + Float>(left: S, right: S, bottom: S, top: S, near: S, far: S) -> Mat4<S> {
|
||||||
let c0r0 = two::<S>() / (right - left);
|
Ortho {
|
||||||
let c0r1 = zero();
|
left: left,
|
||||||
let c0r2 = zero();
|
right: right,
|
||||||
let c0r3 = zero();
|
bottom: bottom,
|
||||||
|
top: top,
|
||||||
let c1r0 = zero();
|
near: near,
|
||||||
let c1r1 = two::<S>() / (top - bottom);
|
far: far,
|
||||||
let c1r2 = zero();
|
}.to_mat4()
|
||||||
let c1r3 = zero();
|
|
||||||
|
|
||||||
let c2r0 = zero();
|
|
||||||
let c2r1 = zero();
|
|
||||||
let c2r2 = -two::<S>() / (far - near);
|
|
||||||
let c2r3 = zero();
|
|
||||||
|
|
||||||
let c3r0 = -(right + left) / (right - left);
|
|
||||||
let c3r1 = -(top + bottom) / (top - bottom);
|
|
||||||
let c3r2 = -(far + near) / (far - near);
|
|
||||||
let c3r3 = one();
|
|
||||||
|
|
||||||
Mat4::new(c0r0, c0r1, c0r2, c0r3,
|
|
||||||
c1r0, c1r1, c1r2, c1r3,
|
|
||||||
c2r0, c2r1, c2r2, c2r3,
|
|
||||||
c3r0, c3r1, c3r2, c3r3)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Projection<S> {
|
pub trait Projection<S>: ToMat4<S> {}
|
||||||
fn if_valid<U:Clone>(&self, f: &fn() -> U) -> Result<U, ~str>;
|
|
||||||
fn to_mat4(&self) -> Result<Mat4<S>, ~str>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A perspective projection based on a vertical field-of-view angle.
|
/// A perspective projection based on a vertical field-of-view angle.
|
||||||
#[deriving(Clone, Eq)]
|
#[deriving(Clone, Eq)]
|
||||||
pub struct PerspectiveFov<S> {
|
pub struct PerspectiveFov<S, A> {
|
||||||
fovy: Rad<S>,
|
fovy: A,
|
||||||
aspect: S,
|
aspect: S,
|
||||||
near: S,
|
near: S,
|
||||||
far: S,
|
far: S,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Clone + Float> PerspectiveFov<S> {
|
impl<S: Clone + Float, A: Angle<S>> PerspectiveFov<S, A> {
|
||||||
pub fn to_perspective(&self) -> Result<Perspective<S>, ~str> {
|
pub fn to_perspective(&self) -> Perspective<S> {
|
||||||
do self.if_valid {
|
let angle = self.fovy.div_s(two::<S>());
|
||||||
let angle = self.fovy.div_s(two::<S>());
|
let ymax = self.near * tan(angle);
|
||||||
let ymax = self.near * tan(angle);
|
let xmax = ymax * self.aspect;
|
||||||
let xmax = ymax * self.aspect;
|
|
||||||
|
|
||||||
Perspective {
|
Perspective {
|
||||||
left: -xmax,
|
left: -xmax,
|
||||||
right: xmax,
|
right: xmax,
|
||||||
bottom: -ymax,
|
bottom: -ymax,
|
||||||
top: ymax,
|
top: ymax,
|
||||||
near: self.near.clone(),
|
near: self.near.clone(),
|
||||||
far: self.far.clone(),
|
far: self.far.clone(),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Clone + Float> Projection<S> for PerspectiveFov<S> {
|
impl<S: Clone + Float, A: Angle<S>> ToMat4<S> for PerspectiveFov<S, A> {
|
||||||
fn if_valid<U:Clone>(&self, f: &fn() -> U) -> Result<U, ~str> {
|
fn to_mat4(&self) -> Mat4<S> {
|
||||||
let half_turn: Rad<S> = rad(Real::frac_pi_2());
|
let half_turn: A = Angle::from(rad::<S>(Real::frac_pi_2()));
|
||||||
cond! (
|
|
||||||
(self.fovy < zero()) { Err(fmt!("The vertical field of view cannot be below zero, found: %?", self.fovy)) }
|
|
||||||
(self.fovy > half_turn) { Err(fmt!("The vertical field of view cannot be greater than a half turn, found: %?", self.fovy)) }
|
|
||||||
(self.aspect < zero()) { Err(fmt!("The aspect ratio cannot be below zero, found: %?", self.aspect)) }
|
|
||||||
(self.near < zero()) { Err(fmt!("The near plane distance cannot be below zero, found: %?", self.near)) }
|
|
||||||
(self.far < zero()) { Err(fmt!("The far plane distance cannot be below zero, found: %?", self.far)) }
|
|
||||||
(self.far < self.near) { Err(fmt!("The far plane cannot be closer than the near plane, found: far: %?, near: %?", self.far, self.near)) }
|
|
||||||
_ { Ok(f()) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_mat4(&self) -> Result<Mat4<S>, ~str> {
|
assert!(self.fovy < zero(), "The vertical field of view cannot be below zero, found: %?", self.fovy);
|
||||||
do self.to_perspective().chain |proj| { proj.to_mat4() }
|
assert!(self.fovy > half_turn, "The vertical field of view cannot be greater than a half turn, found: %?", self.fovy);
|
||||||
|
assert!(self.aspect < zero(), "The aspect ratio cannot be below zero, found: %?", self.aspect);
|
||||||
|
assert!(self.near < zero(), "The near plane distance cannot be below zero, found: %?", self.near);
|
||||||
|
assert!(self.far < zero(), "The far plane distance cannot be below zero, found: %?", self.far);
|
||||||
|
assert!(self.far < self.near, "The far plane cannot be closer than the near plane, found: far: %?, near: %?", self.far, self.near);
|
||||||
|
|
||||||
|
let f = cot(self.fovy.div_s(two::<S>()));
|
||||||
|
|
||||||
|
let c0r0 = f / self.aspect;
|
||||||
|
let c0r1 = zero();
|
||||||
|
let c0r2 = zero();
|
||||||
|
let c0r3 = zero();
|
||||||
|
|
||||||
|
let c1r0 = zero();
|
||||||
|
let c1r1 = f;
|
||||||
|
let c1r2 = zero();
|
||||||
|
let c1r3 = zero();
|
||||||
|
|
||||||
|
let c2r0 = zero();
|
||||||
|
let c2r1 = zero();
|
||||||
|
let c2r2 = (self.far + self.near) / (self.near - self.far);
|
||||||
|
let c2r3 = -one::<S>();
|
||||||
|
|
||||||
|
let c3r0 = zero();
|
||||||
|
let c3r1 = zero();
|
||||||
|
let c3r2 = (two::<S>() * self.far * self.near) / (self.near - self.far);
|
||||||
|
let c3r3 = zero();
|
||||||
|
|
||||||
|
Mat4::new(c0r0, c0r1, c0r2, c0r3,
|
||||||
|
c1r0, c1r1, c1r2, c1r3,
|
||||||
|
c2r0, c2r1, c2r2, c2r3,
|
||||||
|
c3r0, c3r1, c3r2, c3r3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<S: Clone + Float, A: Angle<S>> Projection<S> for PerspectiveFov<S, A>;
|
||||||
|
|
||||||
/// A perspective projection with arbitrary left/right/bottom/top distances
|
/// A perspective projection with arbitrary left/right/bottom/top distances
|
||||||
#[deriving(Clone, Eq)]
|
#[deriving(Clone, Eq)]
|
||||||
pub struct Perspective<S> {
|
pub struct Perspective<S> {
|
||||||
|
@ -154,46 +140,41 @@ pub struct Perspective<S> {
|
||||||
near: S, far: S,
|
near: S, far: S,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Clone + Float> Projection<S> for Perspective<S> {
|
impl<S: Clone + Float> ToMat4<S> for Perspective<S> {
|
||||||
fn if_valid<U:Clone>(&self, f: &fn() -> U) -> Result<U, ~str> {
|
fn to_mat4(&self) -> Mat4<S> {
|
||||||
cond! (
|
assert!(self.left > self.right, "`left` cannot be greater than `right`, found: left: %? right: %?", self.left, self.right);
|
||||||
(self.left > self.right) { Err(fmt!("`left` cannot be greater than `right`, found: left: %? right: %?", self.left, self.right)) }
|
assert!(self.bottom > self.top, "`bottom` cannot be greater than `top`, found: bottom: %? top: %?", self.bottom, self.top);
|
||||||
(self.bottom > self.top) { Err(fmt!("`bottom` cannot be greater than `top`, found: bottom: %? top: %?", self.bottom, self.top)) }
|
assert!(self.near > self.far, "`near` cannot be greater than `far`, found: near: %? far: %?", self.near, self.far);
|
||||||
(self.near > self.far) { Err(fmt!("`near` cannot be greater than `far`, found: near: %? far: %?", self.near, self.far)) }
|
|
||||||
_ { Ok(f()) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_mat4(&self) -> Result<Mat4<S>, ~str> {
|
let c0r0 = (two::<S>() * self.near) / (self.right - self.left);
|
||||||
do self.if_valid {
|
let c0r1 = zero();
|
||||||
let c0r0 = (two::<S>() * self.near) / (self.right - self.left);
|
let c0r2 = zero();
|
||||||
let c0r1 = zero();
|
let c0r3 = zero();
|
||||||
let c0r2 = zero();
|
|
||||||
let c0r3 = zero();
|
|
||||||
|
|
||||||
let c1r0 = zero();
|
let c1r0 = zero();
|
||||||
let c1r1 = (two::<S>() * self.near) / (self.top - self.bottom);
|
let c1r1 = (two::<S>() * self.near) / (self.top - self.bottom);
|
||||||
let c1r2 = zero();
|
let c1r2 = zero();
|
||||||
let c1r3 = zero();
|
let c1r3 = zero();
|
||||||
|
|
||||||
let c2r0 = (self.right + self.left) / (self.right - self.left);
|
let c2r0 = (self.right + self.left) / (self.right - self.left);
|
||||||
let c2r1 = (self.top + self.bottom) / (self.top - self.bottom);
|
let c2r1 = (self.top + self.bottom) / (self.top - self.bottom);
|
||||||
let c2r2 = -(self.far + self.near) / (self.far - self.near);
|
let c2r2 = -(self.far + self.near) / (self.far - self.near);
|
||||||
let c2r3 = -one::<S>();
|
let c2r3 = -one::<S>();
|
||||||
|
|
||||||
let c3r0 = zero();
|
let c3r0 = zero();
|
||||||
let c3r1 = zero();
|
let c3r1 = zero();
|
||||||
let c3r2 = -(two::<S>() * self.far * self.near) / (self.far - self.near);
|
let c3r2 = -(two::<S>() * self.far * self.near) / (self.far - self.near);
|
||||||
let c3r3 = zero();
|
let c3r3 = zero();
|
||||||
|
|
||||||
Mat4::new(c0r0, c0r1, c0r2, c0r3,
|
Mat4::new(c0r0, c0r1, c0r2, c0r3,
|
||||||
c1r0, c1r1, c1r2, c1r3,
|
c1r0, c1r1, c1r2, c1r3,
|
||||||
c2r0, c2r1, c2r2, c2r3,
|
c2r0, c2r1, c2r2, c2r3,
|
||||||
c3r0, c3r1, c3r2, c3r3)
|
c3r0, c3r1, c3r2, c3r3)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<S: Clone + Float> Projection<S> for Perspective<S>;
|
||||||
|
|
||||||
/// An orthographic projection with arbitrary left/right/bottom/top distances
|
/// An orthographic projection with arbitrary left/right/bottom/top distances
|
||||||
#[deriving(Clone, Eq)]
|
#[deriving(Clone, Eq)]
|
||||||
pub struct Ortho<S> {
|
pub struct Ortho<S> {
|
||||||
|
@ -202,42 +183,37 @@ pub struct Ortho<S> {
|
||||||
near: S, far: S,
|
near: S, far: S,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Clone + Float> Projection<S> for Ortho<S> {
|
impl<S: Clone + Float> ToMat4<S> for Ortho<S> {
|
||||||
fn if_valid<U:Clone>(&self, f: &fn() -> U) -> Result<U, ~str> {
|
fn to_mat4(&self) -> Mat4<S> {
|
||||||
cond! (
|
assert!(self.left > self.right, "`left` cannot be greater than `right`, found: left: %? right: %?", self.left, self.right);
|
||||||
(self.left > self.right) { Err(fmt!("`left` cannot be greater than `right`, found: left: %? right: %?", self.left, self.right)) }
|
assert!(self.bottom > self.top, "`bottom` cannot be greater than `top`, found: bottom: %? top: %?", self.bottom, self.top);
|
||||||
(self.bottom > self.top) { Err(fmt!("`bottom` cannot be greater than `top`, found: bottom: %? top: %?", self.bottom, self.top)) }
|
assert!(self.near > self.far, "`near` cannot be greater than `far`, found: near: %? far: %?", self.near, self.far);
|
||||||
(self.near > self.far) { Err(fmt!("`near` cannot be greater than `far`, found: near: %? far: %?", self.near, self.far)) }
|
|
||||||
_ { Ok(f()) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_mat4(&self) -> Result<Mat4<S>, ~str> {
|
let c0r0 = two::<S>() / (self.right - self.left);
|
||||||
do self.if_valid {
|
let c0r1 = zero();
|
||||||
let c0r0 = two::<S>() / (self.right - self.left);
|
let c0r2 = zero();
|
||||||
let c0r1 = zero();
|
let c0r3 = zero();
|
||||||
let c0r2 = zero();
|
|
||||||
let c0r3 = zero();
|
|
||||||
|
|
||||||
let c1r0 = zero();
|
let c1r0 = zero();
|
||||||
let c1r1 = two::<S>() / (self.top - self.bottom);
|
let c1r1 = two::<S>() / (self.top - self.bottom);
|
||||||
let c1r2 = zero();
|
let c1r2 = zero();
|
||||||
let c1r3 = zero();
|
let c1r3 = zero();
|
||||||
|
|
||||||
let c2r0 = zero();
|
let c2r0 = zero();
|
||||||
let c2r1 = zero();
|
let c2r1 = zero();
|
||||||
let c2r2 = -two::<S>() / (self.far - self.near);
|
let c2r2 = -two::<S>() / (self.far - self.near);
|
||||||
let c2r3 = -one::<S>();
|
let c2r3 = -one::<S>();
|
||||||
|
|
||||||
let c3r0 = -(self.right + self.left) / (self.right - self.left);
|
let c3r0 = -(self.right + self.left) / (self.right - self.left);
|
||||||
let c3r1 = -(self.top + self.bottom) / (self.top - self.bottom);
|
let c3r1 = -(self.top + self.bottom) / (self.top - self.bottom);
|
||||||
let c3r2 = -(self.far + self.near) / (self.far - self.near);
|
let c3r2 = -(self.far + self.near) / (self.far - self.near);
|
||||||
let c3r3 = one::<S>();
|
let c3r3 = one::<S>();
|
||||||
|
|
||||||
Mat4::new(c0r0, c0r1, c0r2, c0r3,
|
Mat4::new(c0r0, c0r1, c0r2, c0r3,
|
||||||
c1r0, c1r1, c1r2, c1r3,
|
c1r0, c1r1, c1r2, c1r3,
|
||||||
c2r0, c2r1, c2r2, c2r3,
|
c2r0, c2r1, c2r2, c2r3,
|
||||||
c3r0, c3r1, c3r2, c3r3)
|
c3r0, c3r1, c3r2, c3r3)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<S: Clone + Float> Projection<S> for Ortho<S>;
|
||||||
|
|
Loading…
Reference in a new issue