update to utilize a proper off-axis projection including a demo scene to prototype all systems
This commit is contained in:
parent
040bc8d88a
commit
9c778afa2b
7 changed files with 130 additions and 81 deletions
|
@ -41,8 +41,8 @@ fn main() {
|
||||||
|
|
||||||
.add_startup_system(offaxis_camera_setup)
|
.add_startup_system(offaxis_camera_setup)
|
||||||
.add_plugin(CameraProjectionPlugin::<OffAxisProjection>::default())
|
.add_plugin(CameraProjectionPlugin::<OffAxisProjection>::default())
|
||||||
.add_system(update_offaxis)
|
|
||||||
.add_system(simulate_viewer)
|
.add_system(simulate_viewer)
|
||||||
|
.add_system(apply_viewer_to_projections)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,31 +12,21 @@ use crate::projection::*;
|
||||||
#[derive(Component, Debug, Clone, Reflect)]
|
#[derive(Component, Debug, Clone, Reflect)]
|
||||||
#[reflect(Component, Default)]
|
#[reflect(Component, Default)]
|
||||||
pub struct OffAxisProjection {
|
pub struct OffAxisProjection {
|
||||||
near: f32,
|
|
||||||
pub far: f32,
|
pub far: f32,
|
||||||
aspect: f32,
|
pub projection_matrix: Mat4
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CameraProjection for OffAxisProjection {
|
impl CameraProjection for OffAxisProjection {
|
||||||
fn get_projection_matrix(&self) -> Mat4 {
|
fn get_projection_matrix(&self) -> Mat4 {
|
||||||
|
self.projection_matrix
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// what to do on window resize
|
// what to do on window resize
|
||||||
fn update(&mut self, width: f32, height: f32) {
|
fn update(&mut self, width: f32, height: f32) {
|
||||||
self.aspect = width / height;
|
// self.aspect = width / height;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn far(&self) -> f32 {
|
fn far(&self) -> f32 {
|
||||||
println!("Z-Value");
|
|
||||||
self.far
|
self.far
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,9 +34,8 @@ impl CameraProjection for OffAxisProjection {
|
||||||
impl Default for OffAxisProjection {
|
impl Default for OffAxisProjection {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
near: 0.1,
|
|
||||||
far: 1000.0,
|
far: 1000.0,
|
||||||
aspect: 1.5,
|
projection_matrix: make_projection_rh_custom(45.0f32.to_radians(),1.3f32, 1.0, 1000.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::math::Mat4;
|
use bevy::math::{Mat4, Quat, Affine3A};
|
||||||
|
|
||||||
/// creates a conventional projection matrix from frustum planes
|
/// creates a conventional projection matrix from frustum planes
|
||||||
///
|
///
|
||||||
|
@ -86,15 +86,24 @@ pub fn create_offaxis_matrices(
|
||||||
|
|
||||||
// println!("Dist {}",dist);
|
// 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;
|
// set a minimal near distance
|
||||||
let right = vec_right_normalized.dot(frustum_right) * z_near / dist;
|
let min_near_distance = 0.00001f32;
|
||||||
let bottom = vec_up_normalized.dot(frustum_left) * z_near / dist;
|
|
||||||
let top = vec_up_normalized.dot(frustum_up) * z_near / dist;
|
|
||||||
|
|
||||||
// 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 projection_matrix = make_projection_rh_from_frustum_reversed(left,right,bottom,top,z_near,z_far);
|
||||||
|
|
||||||
let view_matrix_rotation = Mat4::from_cols(
|
let view_matrix_rotation = Mat4::from_cols(
|
||||||
|
@ -104,6 +113,11 @@ pub fn create_offaxis_matrices(
|
||||||
Vec4::W
|
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(
|
let view_matrix_eye = Mat4::from_cols(
|
||||||
Vec4::X,
|
Vec4::X,
|
||||||
Vec4::Y,
|
Vec4::Y,
|
||||||
|
@ -111,8 +125,10 @@ pub fn create_offaxis_matrices(
|
||||||
(-pos_eye).extend(1.0)
|
(-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;
|
let view_matrix = view_matrix_rotation * view_matrix_eye;
|
||||||
|
|
||||||
|
// return tuple of view and projection
|
||||||
(view_matrix,projection_matrix)
|
(view_matrix,projection_matrix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ pub fn build_scene(
|
||||||
) {
|
) {
|
||||||
// plane
|
// plane
|
||||||
commands.spawn(PbrBundle {
|
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()),
|
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
|
@ -95,7 +95,7 @@ pub fn build_scene(
|
||||||
shadows_enabled: true,
|
shadows_enabled: true,
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
transform: Transform::from_xyz(4.0, 8.0, -4.0),
|
transform: Transform::from_xyz(4.0, 1.0, -4.0),
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,13 @@ enum EyePos {
|
||||||
#[derive(Default, Component)]
|
#[derive(Default, Component)]
|
||||||
pub struct ScreenInfo {
|
pub struct ScreenInfo {
|
||||||
pub name: String, // main (to identify the screen)
|
pub name: String, // main (to identify the screen)
|
||||||
width: f32, // 3.08 (full width in m)
|
pub width: f32, // 3.08 (full width in m)
|
||||||
height: f32, // 2.33 (full height 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!)
|
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)
|
// normal: Vec3, // 0.0 0.0 1.0 (orientation of front side)
|
||||||
up: Vec3, // 0.0 1.0 0.0 (vertical axis)
|
// up: Vec3, // 0.0 1.0 0.0 (vertical axis)
|
||||||
horizontal: Vec3, // right vector computed as orthonormal
|
// horizontal: Vec3, // right vector computed as orthonormal
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,15 +28,25 @@ impl ScreenInfo {
|
||||||
height: 2.33,
|
height: 2.33,
|
||||||
center: Vec3 {
|
center: Vec3 {
|
||||||
x: 0.0,
|
x: 0.0,
|
||||||
y: -1.15,
|
y: 0.0,
|
||||||
z: -3.08,
|
z: 0.0,
|
||||||
},
|
},
|
||||||
normal: Vec3::Z,
|
// normal: Vec3::Z,
|
||||||
up: Vec3::Y,
|
// up: Vec3::Y,
|
||||||
horizontal: Vec3::ZERO,
|
// 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(
|
pub fn build_debug_geometry(
|
||||||
&self,
|
&self,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
|
@ -70,18 +80,8 @@ impl ScreenInfo {
|
||||||
// self
|
// 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
52
src/utils.rs
52
src/utils.rs
|
@ -19,27 +19,51 @@ pub fn cycle_msaa(input: Res<Input<KeyCode>>, mut msaa: ResMut<Msaa>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_offaxis(mut query : Query<(
|
// pub fn update_offaxis(mut query : Query<(
|
||||||
&mut OffAxisProjection,
|
// &mut OffAxisProjection,
|
||||||
&mut Transform,
|
// &mut Transform,
|
||||||
&ScreenInfo,
|
// &ScreenInfo,
|
||||||
&Viewer
|
// &Viewer
|
||||||
)>
|
// )>
|
||||||
) {
|
// ) {
|
||||||
for (mut projection,mut transform,screen_info,viewer) in query.iter_mut() {
|
// for (mut projection,mut transform,screen_info,viewer) in query.iter_mut() {
|
||||||
|
|
||||||
// we fake access to far for updating the matrix
|
// // we fake access to far for updating the matrix
|
||||||
(*projection).far *= 1.0;
|
// (*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)
|
||||||
}
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
use bevy::{prelude::*, render::camera::CameraProjectionPlugin, window::PresentMode};
|
use bevy::{prelude::*, transform, math::Vec4Swizzles};
|
||||||
|
|
||||||
use crate::screeninfo::ScreenInfo;
|
use crate::{screeninfo::ScreenInfo, offaxis::OffAxisProjection, projection::create_offaxis_matrices};
|
||||||
// use offaxis::{offaxis_camera_setup, OffAxisProjection};
|
|
||||||
|
|
||||||
#[derive(Component, Default)]
|
#[derive(Component, Default)]
|
||||||
pub struct Viewer {
|
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<Time>) {
|
||||||
|
for mut v in query.iter_mut() {
|
||||||
|
|
||||||
|
//v.position += Vec3::Y * 0.005;
|
||||||
|
v.alpha += 1.5 * time.delta_seconds();
|
||||||
|
|
||||||
|
let radius = 1.0;
|
||||||
|
|
||||||
|
let z_distance = 2.0_f32;
|
||||||
|
|
||||||
v.position = Vec3::new(
|
v.position = Vec3::new(
|
||||||
v.alpha.sin() * radius,
|
v.alpha.sin() * radius,
|
||||||
v.alpha.cos() * radius + 1.0_f32,
|
v.alpha.cos() * radius,
|
||||||
z_distance,
|
z_distance,
|
||||||
);
|
);
|
||||||
|
|
||||||
let vm = Mat4::look_at_rh(v.position, Vec3::ZERO, Vec3::Y);
|
info!("Viewer {:?}",v.position);
|
||||||
|
|
||||||
println!("{:?}", vm);
|
|
||||||
|
|
||||||
// view matrices should be orientation only
|
|
||||||
let dir = Quat::from_mat4(&vm);
|
|
||||||
|
|
||||||
v.orientation = dir;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue