Starting to work on frustums

This commit is contained in:
2018-06-12 17:22:16 +02:00
parent 66001b2f71
commit 4544acad88
7 changed files with 182 additions and 15 deletions
+67
View File
@@ -0,0 +1,67 @@
//! 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 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: &[[f32; 4]; 4]) -> 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<f32>) -> bool {
use num::Zero;
let mut p1 = Vector3::<f32>::zero();
let mut p2 = Vector3::<f32>::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
}
}
+2
View File
@@ -2,6 +2,8 @@
pub mod vector;
pub mod bounding_box;
pub mod plane;
pub mod frustum;
use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign};
use num::{Zero, One};
+65
View File
@@ -0,0 +1,65 @@
//! Module containing the plane struct.
use math::vector::Vector3;
/// A 3D plane.
#[derive(Copy, Clone)]
pub struct Plane {
/// The normal of the plane.
normal: Vector3<f32>,
/// The constant, offset of the plane from the origin.
constant: f32,
}
impl Plane {
/// Creates a new plane from its normal and its constant.
pub fn from_coordinates(a: f32, b: f32, c: f32, w: f32) -> Plane {
let mut p = Plane {
normal: Vector3::new(a, b, c),
constant: w,
};
p.normalize();
p
}
/// Creates a new plane from its normal and its constant.
pub fn from_normal_and_constant(normal: Vector3<f32>, constant: f32) -> Plane {
Plane::from_coordinates(normal.x(), normal.y(), normal.z(), constant)
}
/// Creates a new plane from its normal and a point of the plane.
pub fn from_normal_and_point(normal: Vector3<f32>, point: Vector3<f32>) -> Plane {
Plane::from_normal_and_constant(normal, - point.dot(normal))
}
/// Creates a new plane from three points.
pub fn from_points(p1: Vector3<f32>, p2: Vector3<f32>, p3: Vector3<f32>) -> Plane {
let p1p2 = p2 - p1;
let p1p3 = p3 - p1;
Plane::from_normal_and_point(p1p2.cross_product(p1p3), p1)
}
/// Normalizes the plane.
pub fn normalize(&mut self) {
let normal_inverse = 1.0 / self.normal.norm();
self.normal *= normal_inverse;
self.constant *= normal_inverse;
}
/// Returns the normal of the plane.
pub fn normal(&self) -> Vector3<f32> {
self.normal
}
/// Returns the constant of the plane.
pub fn constant(&self) -> f32 {
self.constant
}
/// Returns the distance between the plane and the point.
pub fn distance_to_point(&self, point: Vector3<f32>) -> f32 {
self.normal.dot(point) + self.constant
}
}