From a7e92ba70ab3782970835f639729baaaaee0ba1c Mon Sep 17 00:00:00 2001 From: Hartmut Seichter Date: Fri, 9 Dec 2022 21:30:47 +0100 Subject: [PATCH] refactor projections into their own module --- src/main.rs | 2 + src/offaxis.rs | 100 ++-------------------------------------------- src/projection.rs | 94 +++++++++++++++++++++++++++++++++++++++++++ src/scene.rs | 76 +---------------------------------- src/screeninfo.rs | 15 ++++++- src/viewer.rs | 11 ++++- 6 files changed, 124 insertions(+), 174 deletions(-) create mode 100644 src/projection.rs diff --git a/src/main.rs b/src/main.rs index 1232584..bdfa01d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ use crate::scene::*; use crate::utils::*; use crate::viewer::*; + use bevy::{prelude::*, window::PresentMode, render::camera::CameraProjectionPlugin}; use offaxis::{offaxis_camera_setup, OffAxisProjection}; @@ -17,6 +18,7 @@ mod scene; mod screeninfo; mod utils; mod viewer; +mod projection; fn main() { App::new() diff --git a/src/offaxis.rs b/src/offaxis.rs index bc37354..8fc9ec1 100644 --- a/src/offaxis.rs +++ b/src/offaxis.rs @@ -7,6 +7,7 @@ use bevy::math::Mat4; use crate::screeninfo::ScreenInfo; use crate::viewer::*; +use crate::projection::*; #[derive(Component, Debug, Clone, Reflect)] #[reflect(Component, Default)] @@ -16,66 +17,10 @@ pub struct OffAxisProjection { aspect: f32, } - -pub fn make_projection_rh_from_frustum(left: f32, right: f32, bottom: f32, top: f32, near:f32, far:f32) -> Mat4 -{ - // based on OpenSceneGraph / glFrustum implementation - let a = (right + left) / (right - left); - let b: f32 = (top + bottom) / (top - bottom); - let c= if far.abs() > f32::MAX { -1.0 } else { -(far + near) / (far - near)}; - let d = if far.abs() > f32::MAX { -2.0 * near } else { -2.0 * far * near / (far - near) }; - - Mat4::from_cols( - Vec4::new(2.0 * near/(right-left),0.0,0.0,0.0), - Vec4::new(0.0,2.0*near/(top-bottom), 0.0,0.0), - Vec4::new(a, b, c, -1.0), - Vec4::new(0.0, 0.0, d, 0.0)) -} - - -pub fn make_projection_rh_from_frustum_reversed(left: f32, right: f32, bottom: f32, top: f32, near:f32, far:f32) -> Mat4 -{ - - assert!(near > 0.0); - - // - // reversed z 0..1 projection based on https://thxforthefish.com/posts/reverse_z/ - // - let a = (right + left) / (right - left); - let b: f32 = (top + bottom) / (top - bottom); - // let c= if far.abs() > f32::MAX { -1.0 } else { -(far + near) / (far - near)}; - // let d = if far.abs() > f32::MAX { -2.0 * near } else { -2.0 * far * near / (far - near) }; - - let c = near / (far - near); - let d = far * near / (far - near); - - - Mat4::from_cols( - Vec4::new(2.0 * near/(right-left),0.0,0.0,0.0), - Vec4::new(0.0,2.0*near/(top-bottom), 0.0,0.0), - Vec4::new(a, b, c, -1.0), - Vec4::new(0.0, 0.0, d, 0.0)) -} - - -pub fn make_projection_rh_custom(fov_y: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Mat4 -{ - let tan_fovy = (fov_y * 0.5).tan(); // use half angle beta - let right = tan_fovy * aspect_ratio * z_near; - let left = -right; - let top = tan_fovy * z_near; - let bottom = -top; - - //make_projection_rh_from_frustum(left, right, bottom, top, z_near, z_far) - - make_projection_rh_from_frustum_reversed(left, right, bottom, top, z_near, z_far) -} - - - impl CameraProjection for OffAxisProjection { fn get_projection_matrix(&self) -> Mat4 { + make_projection_rh_custom(45.0_f32.to_radians(), self.aspect, self.near, self.far) // Mat4::perspective_rh(45.0_f32.to_radians(), @@ -101,7 +46,7 @@ impl Default for OffAxisProjection { Self { near: 0.1, far: 1000.0, - aspect: 1.0, + aspect: 1.5, } } } @@ -141,42 +86,3 @@ pub fn offaxis_camera_setup(mut commands: Commands) { } - -#[cfg(test)] -mod tests { - use bevy::prelude::Mat4; - - use super::make_projection_rh_from_frustum; - - - #[test] - fn compare_projections() { - - // build an on-axis frustum - let fovy = 33.0_f32; - let aspect_ratio = 1.6666_f32; - let z_near = 1.0_f32; - let z_far = 500.0_f32; - - let tan_fovy = (fovy * 0.5).to_radians().tan(); // use half angle beta - let right = tan_fovy * aspect_ratio * z_near; - let left = -right; - let top = tan_fovy * z_near; - let bottom = -top; - - let mat_frust = make_projection_rh_from_frustum(left, right, bottom, top, z_near, z_far); - - println!("mat 1 {:?}",mat_frust); - - let mat_pers = Mat4::perspective_rh_gl(fovy.to_radians(),aspect_ratio,z_near,z_far); - - println!("mat 2 {:?}",mat_pers); - - assert!(mat_frust.abs_diff_eq(mat_pers, f32::EPSILON)); - - } - - - - -} \ No newline at end of file diff --git a/src/projection.rs b/src/projection.rs new file mode 100644 index 0000000..3790373 --- /dev/null +++ b/src/projection.rs @@ -0,0 +1,94 @@ +use bevy::prelude::*; +use bevy::math::Mat4; + +/// creates a conventional projection matrix from frustum planes +/// +/// returns a potentially off-axis projection matrix +pub fn make_projection_rh_from_frustum(left: f32, right: f32, bottom: f32, top: f32, near:f32, far:f32) -> Mat4 +{ + // based on OpenSceneGraph / glFrustum implementation + let a = (right + left) / (right - left); + let b: f32 = (top + bottom) / (top - bottom); + let c= if far.abs() > f32::MAX { -1.0 } else { -(far + near) / (far - near)}; + let d = if far.abs() > f32::MAX { -2.0 * near } else { -2.0 * far * near / (far - near) }; + + Mat4::from_cols( + Vec4::new(2.0 * near / (right-left),0.0,0.0,0.0), + Vec4::new(0.0, 2.0 *near / (top-bottom), 0.0,0.0), + Vec4::new(a, b, c, -1.0), + Vec4::new(0.0, 0.0, d, 0.0)) +} + + +/// creates a projection from a frustum planes with a reversed depth mapped to [0..1] +pub fn make_projection_rh_from_frustum_reversed(left: f32, right: f32, bottom: f32, top: f32, z_near:f32, z_far:f32) -> Mat4 +{ + assert!(z_near > 0.0 && z_far > 0.0); + + // + // reversed z 0..1 projection based on https://thxforthefish.com/posts/reverse_z/ + // + let a = (right + left) / (right - left); + let b: f32 = (top + bottom) / (top - bottom); + + let c = z_near / (z_far - z_near); + let d = z_far * z_near / (z_far - z_near); + + + Mat4::from_cols( + Vec4::new(2.0 * z_near / (right-left),0.0,0.0,0.0), + Vec4::new(0.0, 2.0 * z_near / (top-bottom), 0.0,0.0), + Vec4::new(a, b, c, -1.0), + Vec4::new(0.0, 0.0, d, 0.0)) +} + + +pub fn make_projection_rh_custom(fov_y: f32, aspect_ratio: f32, z_near: f32, z_far: f32) -> Mat4 +{ + let tan_fovy = (fov_y * 0.5).tan(); // use half angle beta + let right = tan_fovy * aspect_ratio * z_near; + let left = -right; + let top = tan_fovy * z_near; + let bottom = -top; + + //make_projection_rh_from_frustum(left, right, bottom, top, z_near, z_far) + + make_projection_rh_from_frustum_reversed(left, right, bottom, top, z_near, z_far) +} + + +#[cfg(test)] +mod tests { + use bevy::prelude::Mat4; + + use super::make_projection_rh_from_frustum; + + + #[test] + fn compare_projections() { + + // build an on-axis frustum + let fovy = 33.0_f32; + let aspect_ratio = 1.6666_f32; + let z_near = 1.0_f32; + let z_far = 1000.0_f32; + + let tan_fovy = (fovy * 0.5).to_radians().tan(); // use half angle beta + let right = tan_fovy * aspect_ratio * z_near; + let left = -right; + let top = tan_fovy * z_near; + let bottom = -top; + + let mat_frust = make_projection_rh_from_frustum(left, right, bottom, top, z_near, z_far); + + println!("mat 1 {:?}",mat_frust); + + let mat_pers = Mat4::perspective_rh_gl(fovy.to_radians(),aspect_ratio,z_near,z_far); + + println!("mat 2 {:?}",mat_pers); + + assert!(mat_frust.abs_diff_eq(mat_pers, f32::EPSILON)); + + } + +} diff --git a/src/scene.rs b/src/scene.rs index ff5d68c..c0339e9 100644 --- a/src/scene.rs +++ b/src/scene.rs @@ -33,7 +33,6 @@ fn generalized_projection_stereo(eyePos : Vec3) } - fn generalized_projection ( projectionScreen: ProjectionScreen, eyePos: Vec3, @@ -100,77 +99,4 @@ pub fn build_scene( ..default() }); - - // camera - - // let mut cam = Camera3dBundle { - // transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), - - // ..default() - // }; - - - - // commands.spawn(cam); - - // commands.spawn((Person, Position { x: 10.0, y: 10.0 })); - // commands.spawn() - // .insert(Person) - // .insert(Position { x: 10.0, y: 10.0 } ); - - // camera - // commands.spawn_bundle(OffAxisProjection { - // transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), - // ..default() - // }); -} - - - -// pub fn modify_frustum(mut query: Query<&Frustum>) -// { -// let mut rng = rand::thread_rng(); - -// for mut q in query.iter() { - -// for mut p in q.planes { - -// println!("{:?}",p); - -// let mut n = p.normal_d(); - -// n.w += rng.gen::(); - -// p = Plane::new(n); - -// println!("{:?}",p); - - - -// // p.normal_d() += rng.gen(); -// } - -// // println!("{:?}",q.frustum.planes.len()); -// } -// } - - -// pub fn modify_projection(mut query: Query<&Projection>) -// { -// let mut rng = rand::thread_rng(); - -// for mut q in query.iter() { - -// print!("{:?}",q); -// } -// } - -// pub fn print_positions(query: Query<&Position>) { -// for _position in query.iter() { -// _ = 33; -// // println!("position {:?} {:?}", position.x, position.y) -// } -// } - -// Problem with off-axis -// projection 2401, 240 \ No newline at end of file +} \ No newline at end of file diff --git a/src/screeninfo.rs b/src/screeninfo.rs index 56b9732..704de24 100644 --- a/src/screeninfo.rs +++ b/src/screeninfo.rs @@ -1,5 +1,5 @@ -use bevy::{prelude::*, math::bool, render::primitives::Frustum}; +use bevy::{prelude::*, math::bool, prelude::shape::Quad }; use rand::prelude::*; use bevy::render::primitives::Plane; @@ -44,6 +44,19 @@ impl ScreenInfo { } } + pub fn build_debug_geometry(&self, + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, + ) + { + // plane + commands.spawn(PbrBundle { + mesh: meshes.add(Mesh::from( Quad { size: Vec2 { x: self.width, y: self.height }, flip:false })), + material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()), + ..default() + }); + } pub fn update(&mut self) -> &mut Self { diff --git a/src/viewer.rs b/src/viewer.rs index 95176a2..798335d 100644 --- a/src/viewer.rs +++ b/src/viewer.rs @@ -1,4 +1,6 @@ use bevy::{prelude::*, window::PresentMode, render::camera::CameraProjectionPlugin}; + +use crate::screeninfo::ScreenInfo; // use offaxis::{offaxis_camera_setup, OffAxisProjection}; @@ -36,10 +38,17 @@ pub fn simulate_viewer(mut query: Query<&mut Viewer>) //v.position += Vec3::Y * 0.005; v.alpha += 0.01; let radius = 1.5; - v.position = Vec3::new(v.alpha.sin()*radius,v.alpha.cos()*radius + 1.0_f32,15.0); + + let z_distance = 8.0_f32; + + v.position = Vec3::new(v.alpha.sin()*radius,v.alpha.cos()*radius + 1.0_f32,z_distance); let vm = Mat4::look_at_rh(v.position, Vec3::ZERO, Vec3::Y); + + + + println!("{:?}",vm); // view matrices should be orientation only