dimforge / dimforge/nalgebra

Planes and Culling Frustums

Open
#1,337 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
4.8k
Forks
565
PR merge metrics
No merged PRs in 30d

Description

Any thoughts about adding in planes and culling frustums (or just frustums with the right functions.) I'm using nalgebra for a game I'm working on and planes + frustums are nice for optimizations, so others might desire them.

I basically made my own and if you think this is something useful, feel free to use my code if it's up to your standards, at least as a start. Otherwise, it's not hard to create, just something that could get wrapped into your lib and be one less piece of code I'm maintaining.

If you already have this and I somehow missed it, I apologize for the issue!

Plane:

`
use num_traits::real::Real;
use nalgebra::*;

pub struct Plane {
pub a: T,
pub b: T,
pub c: T,
pub d: T
}

impl Plane {
pub fn new(
a: T,
b: T,
c: T,
d: T
) -> Self {
Self {
a,
b,
c,
d
}
}

pub fn normalize(
&mut self
) {
let f = ((self.a * self.a) + (self.b * self.b) + (self.c * self.c)).sqrt();
if f != num_traits::zero() {
self.a = self.a / f;
self.b = self.b / f;
self.c = self.c / f;
self.d = self.d / f;
}
}

pub fn bound_box_outside_plane(
&mut self,
min: &Point3,
max: &Point3
) -> bool {
if (self.a * min.x) + (self.b * min.y) + (self.c * min.z) + self.d > num_traits::zero() {
return true;
}
if (self.a * max.x) + (self.b * min.y) + (self.c * min.z) + self.d > num_traits::zero() {
return true;
}
if (self.a * min.x) + (self.b * max.y) + (self.c * min.z) + self.d > num_traits::zero() {
return true;
}
if (self.a * max.x) + (self.b * max.y) + (self.c * min.z) + self.d > num_traits::zero() {
return true;
}
if (self.a * min.x) + (self.b * min.y) + (self.c * max.z) + self.d > num_traits::zero() {
return true;
}
if (self.a * max.x) + (self.b * min.y) + (self.c * max.z) + self.d > num_traits::zero() {
return true;
}
if (self.a * min.x) + (self.b * max.y) + (self.c * max.z) + self.d > num_traits::zero() {
return true;
}
(self.a * max.x) + (self.b * max.y) + (self.c * max.z) + self.d > num_traits::zero()
}

}

impl Default for Plane {
fn default() -> Self {
Self {
a: num_traits::zero(),
b: num_traits::zero(),
c: num_traits::zero(),
d: num_traits::zero()
}
}
}
`

Culling Frustum:

`
use num_traits::real::Real;
use nalgebra::*;

use crate::game::view_plane::Plane;
pub struct CullingFrustum {
pub left: Plane,
pub right: Plane,
pub top: Plane,
pub bottom: Plane,
pub near: Plane,
pub far: Plane,
}

impl CullingFrustum {
pub fn new(
perspective_matrix: &Matrix4,
view_matrix: &Matrix4
) -> Self {
let mut clip_plane: [T; 16] = [num_traits::zero(); 16];

clip_plane[0]=(view_matrix[(0,0)]*perspective_matrix[(0,0)])+(view_matrix[(1,0)]*perspective_matrix[(0,1)])+(view_matrix[(2,0)]*perspective_matrix[(0,2)])+(view_matrix[(3,0)]*perspective_matrix[(0,3)]);
clip_plane[1]=(view_matrix[(0,0)]*perspective_matrix[(1,0)])+(view_matrix[(1,0)]*perspective_matrix[(1,1)])+(view_matrix[(2,0)]*perspective_matrix[(1,2)])+(view_matrix[(3,0)]*perspective_matrix[(1,3)]);
clip_plane[2]=(view_matrix[(0,0)]*perspective_matrix[(2,0)])+(view_matrix[(1,0)]*perspective_matrix[(2,1)])+(view_matrix[(2,0)]*perspective_matrix[(2,2)])+(view_matrix[(3,0)]*perspective_matrix[(2,3)]);
clip_plane[3]=(view_matrix[(0,0)]*perspective_matrix[(3,0)])+(view_matrix[(1,0)]*perspective_matrix[(3,1)])+(view_matrix[(2,0)]*perspective_matrix[(3,2)])+(view_matrix[(3,0)]*perspective_matrix[(3,3)]);

clip_plane[4]=(view_matrix[(0,1)]*perspective_matrix[(0,0)])+(view_matrix[(1,1)]*perspective_matrix[(0,1)])+(view_matrix[(2,1)]*perspective_matrix[(0,2)])+(view_matrix[(3,1)]*perspective_matrix[(0,3)]);
clip_plane[5]=(view_matrix[(0,1)]*perspective_matrix[(1,0)])+(view_matrix[(1,1)]*perspective_matrix[(1,1)])+(view_matrix[(2,1)]*perspective_matrix[(1,2)])+(view_matrix[(3,1)]*perspective_matrix[(1,3)]);
clip_plane[6]=(view_matrix[(0,1)]*perspective_matrix[(2,0)])+(view_matrix[(1,1)]*perspective_matrix[(2,1)])+(view_matrix[(2,1)]*perspective_matrix[(2,2)])+(view_matrix[(3,1)]*perspective_matrix[(2,3)]);
clip_plane[7]=(view_matrix[(0,1)]*perspective_matrix[(3,0)])+(view_matrix[(1,1)]*perspective_matrix[(3,1)])+(view_matrix[(2,1)]*perspective_matrix[(3,2)])+(view_matrix[(3,1)]*perspective_matrix[(3,3)]);

clip_plane[8]=(view_matrix[(0,2)]*perspective_matrix[(0,0)])+(view_matrix[(1,2)]*perspective_matrix[(0,1)])+(view_matrix[(2,2)]*perspective_matrix[(0,2)])+(view_matrix[(3,2)]*perspective_matrix[(0,3)]);
clip_plane[9]=(view_matrix[(0,2)]*perspective_matrix[(1,0)])+(view_matrix[(1,2)]*perspective_matrix[(1,1)])+(view_matrix[(2,2)]*perspective_matrix[(1,2)])+(view_matrix[(3,2)]*perspective_matrix[(1,3)]);
clip_plane[10]=(view_matrix[(0,2)]*perspective_matrix[(2,0)])+(view_matrix[(1,2)]*perspective_matrix[(2,1)])+(view_matrix[(2,2)]*perspective_matrix[(2,2)])+(view_matrix[(3,2)]*perspective_matrix[(2,3)]);
clip_plane[11]=(view_matrix[(0,2)]*perspective_matrix[(3,0)])+(view_matrix[(1,2)]*perspective_matrix[(3,1)])+(view_matrix[(2,2)]*perspective_matrix[(3,2)])+(view_matrix[(3,2)]*perspective_matrix[(3,3)]);

clip_plane[12]=(view_matrix[(0,3)]*perspective_matrix[(0,0)])+(view_matrix[(1,3)]*perspective_matrix[(0,1)])+(view_matrix[(2,3)]*perspective_matrix[(0,2)])+(view_matrix[(3,3)]*perspective_matrix[(0,3)]);
clip_plane[13]=(view_matrix[(0,3)]*perspective_matrix[(1,0)])+(view_matrix[(1,3)]*perspective_matrix[(1,1)])+(view_matrix[(2,3)]*perspective_matrix[(1,2)])+(view_matrix[(3,3)]*perspective_matrix[(1,3)]);
clip_plane[14]=(view_matrix[(0,3)]*perspective_matrix[(2,0)])+(view_matrix[(1,3)]*perspective_matrix[(2,1)])+(view_matrix[(2,3)]*perspective_matrix[(2,2)])+(view_matrix[(3,3)]*perspective_matrix[(2,3)]);
clip_plane[15]=(view_matrix[(0,3)]*perspective_matrix[(3,0)])+(view_matrix[(1,3)]*perspective_matrix[(3,1)])+(view_matrix[(2,3)]*perspective_matrix[(3,2)])+(view_matrix[(3,3)]*perspective_matrix[(3,3)]);

// left plane
let mut left: Plane = Plane::new(
clip_plane[3]+clip_plane[0],
clip_plane[7]+clip_plane[4],
clip_plane[11]+clip_plane[8],
clip_plane[15]+clip_plane[12]
);
left.normalize();

// right plane
let mut right: Plane = Plane::new(
clip_plane[3]-clip_plane[0],
clip_plane[7]-clip_plane[4],
clip_plane[11]-clip_plane[8],
clip_plane[15]-clip_plane[12]
);
right.normalize();

// top plane
let mut top: Plane = Plane::new(
clip_plane[3]-clip_plane[1],
clip_plane[7]-clip_plane[5],
clip_plane[11]-clip_plane[9],
clip_plane[15]-clip_plane[13]
);
top.normalize();

// bottom plane
let mut bottom: Plane = Plane::new(
clip_plane[3]+clip_plane[1],
clip_plane[7]+clip_plane[5],
clip_plane[11]+clip_plane[9],
clip_plane[15]+clip_plane[13]
);
bottom.normalize();

// near plane
let mut near: Plane = Plane::new(
clip_plane[3]+clip_plane[2],
clip_plane[7]+clip_plane[6],
clip_plane[11]+clip_plane[10],
clip_plane[15]+clip_plane[14]
);
near.normalize();

// far plane
let mut far: Plane = Plane::new(
clip_plane[3]-clip_plane[2],
clip_plane[7]-clip_plane[6],
clip_plane[11]-clip_plane[10],
clip_plane[15]-clip_plane[14]
);
far.normalize();

Self {
left,
right,
top,
bottom,
near,
far
}
}

pub fn bound_box_in_frustum(
&mut self,
min: &Point3,
max: &Point3
) -> bool {
// check if outside the plane, if it is,
// then it's considered outside the bounds
if !self.left.bound_box_outside_plane(min, max) {
return false;
}
if !self.right.bound_box_outside_plane(min, max) {
return false;
}
if !self.top.bound_box_outside_plane(min, max) {
return false;
}
if !self.bottom.bound_box_outside_plane(min, max) {
return false;
}
if !self.near.bound_box_outside_plane(min, max) {
return false;
}
self.far.bound_box_outside_plane(min, max)
}

}

impl Default for CullingFrustum {
fn default() -> Self {
Self {
left: Plane::default(),
right: Plane::default(),
top: Plane::default(),
bottom: Plane::default(),
near: Plane::default(),
far: Plane::default(),
}
}
}
`

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.