Wip frustum code port

This commit is contained in:
griffi-gh 2023-01-27 04:02:27 +01:00
parent 783b6a1f84
commit 19fa7e67bc
3 changed files with 115 additions and 33 deletions

View file

@ -1,7 +1,11 @@
use glam::{Mat4, Vec3}; use glam::{Mat4, Vec3};
use shipyard::{Component, ViewMut, View, IntoIter, Workload, IntoWorkload}; use shipyard::{Component, Workload, IntoWorkload};
use std::f32::consts::PI; use std::f32::consts::PI;
use crate::{transform::Transform, events::WindowResizedEvent};
mod matrices;
mod frustum;
use matrices::update_matrices;
#[derive(Component)] #[derive(Component)]
pub struct Camera { pub struct Camera {
@ -29,36 +33,6 @@ impl Default for Camera {
pub fn compute_cameras() -> Workload { pub fn compute_cameras() -> Workload {
( (
update_perspective_matrix, update_matrices,
update_view_matrix,
).into_workload() ).into_workload()
} }
fn update_view_matrix(
mut vm_camera: ViewMut<Camera>,
v_transform: View<Transform>
) {
for (camera, transform) in (&mut vm_camera, v_transform.inserted_or_modified()).iter() {
let (_, rotation, translation) = transform.0.to_scale_rotation_translation();
let direction = rotation * Vec3::NEG_Z;
camera.view_matrix = Mat4::look_to_rh(translation, direction, camera.up);
}
}
fn update_perspective_matrix(
mut vm_camera: ViewMut<Camera>,
resize: View<WindowResizedEvent>,
) {
//TODO update on launch
let Some(&size) = resize.iter().next() else {
return
};
for camera in (&mut vm_camera).iter() {
camera.perspective_matrix = Mat4::perspective_rh_gl(
camera.fov,
size.0.x as f32 / size.0.y as f32,
camera.z_near,
camera.z_far,
)
}
}

66
src/camera/frustum.rs Normal file
View file

@ -0,0 +1,66 @@
// basically ported from c++
// - used as a reference:
// [ https://github.com/Beastwick18/gltest/blob/main/src/renderer/Frustum.cpp ]
// - original code:
// [ https://gist.github.com/podgorskiy/e698d18879588ada9014768e3e82a644 ]
// - which uses cube vs frustum intersection code from:
// [ http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm ]
// three layers of stolen code, yay!
use glam::{Vec3, Vec4, Vec4Swizzles};
use super::Camera;
#[repr(usize)]
enum FrustumPlane {
Left,
Right,
Bottom,
Top,
Near,
Far,
}
const PLANE_COUNT: usize = 6;
const PLANE_COMBINATIONS: usize = PLANE_COUNT * (PLANE_COUNT - 1) / 2;
struct Frustum {
planes: [Vec4; PLANE_COUNT],
crosses: [Vec3; PLANE_COMBINATIONS],
}
impl Frustum {
pub fn compute(camera: &Camera) -> Self {
//compute transposed view-projection matrix
let mat = (camera.perspective_matrix * camera.view_matrix).transpose();
// compute planes
let mut planes = [Vec4::default(); PLANE_COUNT];
planes[FrustumPlane::Left as usize] = mat.w_axis + mat.x_axis;
planes[FrustumPlane::Right as usize] = mat.w_axis - mat.x_axis;
planes[FrustumPlane::Bottom as usize] = mat.w_axis + mat.y_axis;
planes[FrustumPlane::Top as usize] = mat.w_axis - mat.y_axis;
planes[FrustumPlane::Near as usize] = mat.w_axis + mat.z_axis;
planes[FrustumPlane::Far as usize] = mat.w_axis - mat.z_axis;
//compute crosses
let crosses = [
planes[FrustumPlane::Left as usize].xyz().cross(planes[FrustumPlane::Right as usize].xyz()),
planes[FrustumPlane::Left as usize].xyz().cross(planes[FrustumPlane::Bottom as usize].xyz()),
planes[FrustumPlane::Left as usize].xyz().cross(planes[FrustumPlane::Top as usize].xyz()),
planes[FrustumPlane::Left as usize].xyz().cross(planes[FrustumPlane::Near as usize].xyz()),
planes[FrustumPlane::Left as usize].xyz().cross(planes[FrustumPlane::Far as usize].xyz()),
planes[FrustumPlane::Right as usize].xyz().cross(planes[FrustumPlane::Bottom as usize].xyz()),
planes[FrustumPlane::Right as usize].xyz().cross(planes[FrustumPlane::Top as usize].xyz()),
planes[FrustumPlane::Right as usize].xyz().cross(planes[FrustumPlane::Near as usize].xyz()),
planes[FrustumPlane::Right as usize].xyz().cross(planes[FrustumPlane::Far as usize].xyz()),
planes[FrustumPlane::Bottom as usize].xyz().cross(planes[FrustumPlane::Top as usize].xyz()),
planes[FrustumPlane::Bottom as usize].xyz().cross(planes[FrustumPlane::Near as usize].xyz()),
planes[FrustumPlane::Bottom as usize].xyz().cross(planes[FrustumPlane::Far as usize].xyz()),
planes[FrustumPlane::Top as usize].xyz().cross(planes[FrustumPlane::Near as usize].xyz()),
planes[FrustumPlane::Top as usize].xyz().cross(planes[FrustumPlane::Far as usize].xyz()),
planes[FrustumPlane::Near as usize].xyz().cross(planes[FrustumPlane::Far as usize].xyz()),
];
Self { planes, crosses }
}
}

42
src/camera/matrices.rs Normal file
View file

@ -0,0 +1,42 @@
use glam::{Vec3, Mat4};
use shipyard::{ViewMut, View, IntoIter, Workload, IntoWorkload};
use crate::{transform::Transform, events::WindowResizedEvent};
use super::Camera;
//maybe parallelize these two?
fn update_view_matrix(
mut vm_camera: ViewMut<Camera>,
v_transform: View<Transform>
) {
for (camera, transform) in (&mut vm_camera, v_transform.inserted_or_modified()).iter() {
let (_, rotation, translation) = transform.0.to_scale_rotation_translation();
let direction = rotation * Vec3::NEG_Z;
camera.view_matrix = Mat4::look_to_rh(translation, direction, camera.up);
}
}
fn update_perspective_matrix(
mut vm_camera: ViewMut<Camera>,
resize: View<WindowResizedEvent>,
) {
//TODO update on launch
let Some(&size) = resize.iter().next() else {
return
};
for camera in (&mut vm_camera).iter() {
camera.perspective_matrix = Mat4::perspective_rh_gl(
camera.fov,
size.0.x as f32 / size.0.y as f32,
camera.z_near,
camera.z_far,
)
}
}
pub fn update_matrices() -> Workload {
(
update_view_matrix,
update_perspective_matrix,
).into_workload()
}