//! 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 the matrix of a camera. /// /// This is *ahem...* slightly inspired from THREE.js Frustum pub fn from_matrix(m: &Matrix4) -> 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)]; 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) -> bool { use num::Zero; let mut p1 = Vector3::::zero(); let mut p2 = Vector3::::zero(); for plane in &self.planes { p1[0] = if plane.normal().x() > 0.0 { bbox.min().x() } else { bbox.max().x() }; p2[0] = if plane.normal().x() > 0.0 { bbox.max().x() } else { bbox.min().x() }; p1[1] = if plane.normal().y() > 0.0 { bbox.min().y() } else { bbox.max().y() }; p2[1] = if plane.normal().y() > 0.0 { bbox.max().y() } else { bbox.min().y() }; p1[2] = if plane.normal().z() > 0.0 { bbox.min().z() } else { bbox.max().z() }; p2[2] = if plane.normal().z() > 0.0 { bbox.max().z() } else { bbox.min().z() }; let d1 = plane.distance_to_point(p1); let d2 = plane.distance_to_point(p2); if d1 < 0.0 && d2 < 2.0 { return false; } } true } }