model-converter/src/math/frustum.rs

75 lines
2.7 KiB
Rust

//! Module containing the frustum struct.
//!
//! The frustum is the field of view of a camera. It allows you to make computation to know what is
//! visible or not in an efficient manner, though it doesn't take occlusions into account.
use nalgebra::Matrix4;
use math::vector::Vector3;
use math::plane::Plane;
use math::bounding_box::BoundingBox3;
/// Struct containing the 6 planes of a 3D camera.
#[derive(Copy, Clone)]
pub struct Frustum {
/// The planes of the frustum.
planes: [Plane; 6],
}
impl Frustum {
/// Creates a frustum from its four planes.
pub fn new(planes: [Plane; 6]) -> Frustum {
Frustum {
planes: planes,
}
}
/// Creates a frustum for a camera matrix.
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)];
// 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 {
planes: [
Plane::from_coordinates(m3 - m0, m7 - m4, m11 - m8, m15 - m12),
Plane::from_coordinates(m3 + m0, m7 + m4, m11 + m8, m15 + m12),
Plane::from_coordinates(m3 + m1, m7 + m5, m11 + m9, m15 + m13),
Plane::from_coordinates(m3 - m1, m7 - m5, m11 - m9, m15 - m13),
Plane::from_coordinates(m3 - m2, m7 - m6, m11 - m10, m15 - m14),
Plane::from_coordinates(m3 + m2, m7 + m6, m11 + m10, m15 + m14),
],
}
}
/// Returns true if the intersection of the frustum and the bounding box is not empty.
pub fn intersects_box(&self, bbox: BoundingBox3<f32>) -> bool {
use num::Zero;
let mut p = Vector3::<f32>::zero();
for plane in &self.planes {
p[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() };
p[2] = if plane.normal().z() > 0.0 { bbox.max().z() } else { bbox.min().z() };
if plane.distance_to_point(p) < 0.0 {
return false;
}
}
true
}
}