From 9c778afa2b8901b03a9251740afc38a0e8df2f57 Mon Sep 17 00:00:00 2001 From: Hartmut Seichter Date: Sun, 11 Dec 2022 21:12:08 +0100 Subject: [PATCH] update to utilize a proper off-axis projection including a demo scene to prototype all systems --- src/main.rs | 2 +- src/offaxis.rs | 19 ++++------------ src/projection.rs | 30 +++++++++++++++++++------ src/scene.rs | 4 ++-- src/screeninfo.rs | 46 +++++++++++++++++++------------------- src/utils.rs | 54 ++++++++++++++++++++++++++++++++------------- src/viewer.rs | 56 ++++++++++++++++++++++++++++++++--------------- 7 files changed, 130 insertions(+), 81 deletions(-) diff --git a/src/main.rs b/src/main.rs index bdfa01d..55c6267 100644 --- a/src/main.rs +++ b/src/main.rs @@ -41,8 +41,8 @@ fn main() { .add_startup_system(offaxis_camera_setup) .add_plugin(CameraProjectionPlugin::::default()) - .add_system(update_offaxis) .add_system(simulate_viewer) + .add_system(apply_viewer_to_projections) .run(); } diff --git a/src/offaxis.rs b/src/offaxis.rs index 8fc9ec1..3d58a09 100644 --- a/src/offaxis.rs +++ b/src/offaxis.rs @@ -12,31 +12,21 @@ use crate::projection::*; #[derive(Component, Debug, Clone, Reflect)] #[reflect(Component, Default)] pub struct OffAxisProjection { - near: f32, pub far: f32, - aspect: f32, + pub projection_matrix: Mat4 } 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(), - // self.aspect, - // self.near, - // self.far) - + self.projection_matrix } // what to do on window resize fn update(&mut self, width: f32, height: f32) { - self.aspect = width / height; + // self.aspect = width / height; } fn far(&self) -> f32 { - println!("Z-Value"); self.far } } @@ -44,9 +34,8 @@ impl CameraProjection for OffAxisProjection { impl Default for OffAxisProjection { fn default() -> Self { Self { - near: 0.1, far: 1000.0, - aspect: 1.5, + projection_matrix: make_projection_rh_custom(45.0f32.to_radians(),1.3f32, 1.0, 1000.0) } } } diff --git a/src/projection.rs b/src/projection.rs index 1e5552b..2b8ccd3 100644 --- a/src/projection.rs +++ b/src/projection.rs @@ -1,5 +1,5 @@ use bevy::prelude::*; -use bevy::math::Mat4; +use bevy::math::{Mat4, Quat, Affine3A}; /// creates a conventional projection matrix from frustum planes /// @@ -86,15 +86,24 @@ pub fn create_offaxis_matrices( // println!("Dist {}",dist); - let z_near = 0.001_f32.max(dist - 0.01); + // small offset for the near plane + let min_near_distance_offset = 0.01f32; - let left = vec_right_normalized.dot(frustum_left) * z_near / dist; - let right = vec_right_normalized.dot(frustum_right) * z_near / dist; - let bottom = vec_up_normalized.dot(frustum_left) * z_near / dist; - let top = vec_up_normalized.dot(frustum_up) * z_near / dist; + // set a minimal near distance + let min_near_distance = 0.00001f32; - // println!("l r b t {} {} {} {}",left,right,bottom,top); + // calculate a reasonable near distance + let z_near = min_near_distance.max(dist - min_near_distance_offset); + // distances + let left = vec_right_normalized.dot(frustum_left) * z_near / dist; // left screen edge + let right = vec_right_normalized.dot(frustum_right) * z_near / dist; // right screen edge + let bottom = vec_up_normalized.dot(frustum_left) * z_near / dist; // bottom screen edge + let top = vec_up_normalized.dot(frustum_up) * z_near / dist; // distance eye from screen + + info!("l r b t {} {} {} {}",left,right,bottom,top); + + // create a view frustum let projection_matrix = make_projection_rh_from_frustum_reversed(left,right,bottom,top,z_near,z_far); let view_matrix_rotation = Mat4::from_cols( @@ -104,6 +113,11 @@ pub fn create_offaxis_matrices( Vec4::W ); + let rotation_quat = Quat::from_mat4(&view_matrix_rotation); /// Quat::from_mat4(view_matrix_rotation); + + info!("Rotation Mat {:?}",view_matrix_rotation); + info!("Viewer Rotation {:?}",rotation_quat); + let view_matrix_eye = Mat4::from_cols( Vec4::X, Vec4::Y, @@ -111,8 +125,10 @@ pub fn create_offaxis_matrices( (-pos_eye).extend(1.0) ); + // create resulting view matrix (this should be much simpler using glam API) let view_matrix = view_matrix_rotation * view_matrix_eye; + // return tuple of view and projection (view_matrix,projection_matrix) } diff --git a/src/scene.rs b/src/scene.rs index c0339e9..25a657a 100644 --- a/src/scene.rs +++ b/src/scene.rs @@ -77,7 +77,7 @@ pub fn build_scene( ) { // plane commands.spawn(PbrBundle { - mesh: meshes.add(Mesh::from(shape::Plane { size: 5.0 })), + mesh: meshes.add(Mesh::from(shape::Plane { size: 4.0 })), material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()), ..default() }); @@ -95,7 +95,7 @@ pub fn build_scene( shadows_enabled: true, ..default() }, - transform: Transform::from_xyz(4.0, 8.0, -4.0), + transform: Transform::from_xyz(4.0, 1.0, -4.0), ..default() }); diff --git a/src/screeninfo.rs b/src/screeninfo.rs index 64fa812..02a365a 100644 --- a/src/screeninfo.rs +++ b/src/screeninfo.rs @@ -10,13 +10,13 @@ enum EyePos { #[derive(Default, Component)] pub struct ScreenInfo { pub name: String, // main (to identify the screen) - width: f32, // 3.08 (full width in m) - height: f32, // 2.33 (full height in m) + pub width: f32, // 3.08 (full width in m) + pub height: f32, // 2.33 (full height in m) - center: Vec3, // 0.0 -1.15 -3.08 (mid point of screen in global coordinated - tracking!) - normal: Vec3, // 0.0 0.0 1.0 (orientation of front side) - up: Vec3, // 0.0 1.0 0.0 (vertical axis) - horizontal: Vec3, // right vector computed as orthonormal + pub center: Vec3, // 0.0 -1.15 -3.08 (mid point of screen in global coordinated - tracking!) + // normal: Vec3, // 0.0 0.0 1.0 (orientation of front side) + // up: Vec3, // 0.0 1.0 0.0 (vertical axis) + // horizontal: Vec3, // right vector computed as orthonormal } @@ -28,15 +28,25 @@ impl ScreenInfo { height: 2.33, center: Vec3 { x: 0.0, - y: -1.15, - z: -3.08, + y: 0.0, + z: 0.0, }, - normal: Vec3::Z, - up: Vec3::Y, - horizontal: Vec3::ZERO, + // normal: Vec3::Z, + // up: Vec3::Y, + // horizontal: Vec3::ZERO, } } + pub fn corner_points(&self) -> (Vec3,Vec3,Vec3,Vec3) { + + let lower_left = Vec3::new(self.center.x - self.width * 0.5,self.center.y - self.height * 0.5,0.0); + let lower_right = Vec3::new(self.center.x + self.width * 0.5,self.center.y - self.height * 0.5,0.0); + let upper_left = Vec3::new(self.center.x - self.width * 0.5,self.center.y + self.height * 0.5,0.0); + let upper_right = Vec3::new(self.center.x + self.width * 0.5,self.center.y + self.height * 0.5,0.0); + + (lower_left,lower_right,upper_left,upper_right) + } + pub fn build_debug_geometry( &self, mut commands: Commands, @@ -70,18 +80,8 @@ impl ScreenInfo { // self // } - fn intersection(&self, p1: Vec3, p2: Vec3) -> (bool, Vec3) { - let u = self.normal.dot(self.center - p1) / self.normal.dot(p2 - p1); - let intersection_point = p1 + ((p2 - p1) * u); - // returns a tuple if the intersection point is in front and the actual point - (u >= 0.0 && u <= 1.0, intersection_point) - } - - fn normal_intersection(&self, p1: Vec3) -> (bool, Vec3) { - let p2 = p1 - self.normal * 10.0; - - self.intersection(p1, p2) - } } + + diff --git a/src/utils.rs b/src/utils.rs index 2480282..8cd4a03 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -19,27 +19,51 @@ pub fn cycle_msaa(input: Res>, mut msaa: ResMut) { } } -pub fn update_offaxis(mut query : Query<( - &mut OffAxisProjection, - &mut Transform, - &ScreenInfo, - &Viewer -)> -) { - for (mut projection,mut transform,screen_info,viewer) in query.iter_mut() { +// pub fn update_offaxis(mut query : Query<( +// &mut OffAxisProjection, +// &mut Transform, +// &ScreenInfo, +// &Viewer +// )> +// ) { +// for (mut projection,mut transform,screen_info,viewer) in query.iter_mut() { - // we fake access to far for updating the matrix - (*projection).far *= 1.0; +// // we fake access to far for updating the matrix +// (*projection).far *= 1.0; - println!("Projection {:?}",*projection); +// info!("Projection {:?}",*projection); - println!("Screen Info {:?}",screen_info.name); +// info!("Screen Info {:?}",screen_info.name); - println!("Viewer {:?}",viewer.position); +// info!("Viewer {:?}",viewer.position); - *transform = Transform::from_translation(viewer.position).with_rotation(transform.rotation); +// *transform = Transform::from_translation(viewer.position).with_rotation(transform.rotation); - } +// } +// } + + +fn intersection_point( + center_point: Vec3, + normal: Vec3, + p1: Vec3, + p2: Vec3) -> (bool, Vec3) { + let u = normal.dot(center_point - p1) / normal.dot(p2 - p1); + + let intersection_point = p1.lerp(p2,u); //p1 + ((p2 - p1) * u); + + // returns a tuple if the intersection point is in front and the actual point + (u >= 0.0 && u <= 1.0, intersection_point) +} + +fn normal_intersection_point( + center_point: Vec3, + normal : Vec3, + p1: Vec3) -> (bool, Vec3) +{ + let p2 = p1 - normal * 10.0; + + intersection_point(center_point, normal, p1, p2) } \ No newline at end of file diff --git a/src/viewer.rs b/src/viewer.rs index 2a4b984..d7fa752 100644 --- a/src/viewer.rs +++ b/src/viewer.rs @@ -1,7 +1,6 @@ -use bevy::{prelude::*, render::camera::CameraProjectionPlugin, window::PresentMode}; +use bevy::{prelude::*, transform, math::Vec4Swizzles}; -use crate::screeninfo::ScreenInfo; -// use offaxis::{offaxis_camera_setup, OffAxisProjection}; +use crate::{screeninfo::ScreenInfo, offaxis::OffAxisProjection, projection::create_offaxis_matrices}; #[derive(Component, Default)] pub struct Viewer { @@ -29,27 +28,48 @@ impl Viewer { } } -pub fn simulate_viewer(mut query: Query<&mut Viewer>) { - for mut v in query.iter_mut() { - //v.position += Vec3::Y * 0.005; - v.alpha += 0.01; - let radius = 1.5; - let z_distance = 8.0_f32; +pub fn apply_viewer_to_projections(mut query: Query<(&Viewer,&ScreenInfo,&mut OffAxisProjection,&mut Transform)>) +{ + query.for_each_mut(|(viewer,screen_info,mut offaxis, mut transform)| { + + let eye = viewer.position; + + + let (lower_left,lower_right,upper_left,_) = screen_info.corner_points(); + + // let lower_left = Vec3::new(screen_info.center.x - screen_info.width / 2.0,screen_info.center.y - screen_info.height / 2.0,screen_info.center.z); + // let upper_left = Vec3::new(screen_info.center.x - screen_info.width / 2.0,screen_info.center.y + screen_info.height / 2.0,screen_info.center.z); + + // let lower_right = Vec3::new(screen_info.center.x + screen_info.width / 2.0,screen_info.center.y - screen_info.height / 2.0,screen_info.center.z); + + + let (view, projection) = create_offaxis_matrices(lower_left, lower_right, upper_left, eye, 1000.0f32); + + offaxis.projection_matrix = projection; + + *transform = Transform::from_matrix(view.inverse()); + + }); +} + + +pub fn simulate_viewer(mut query: Query<&mut Viewer>,time: Res