From fa9b79761066dfac1f20dc2606e124bd64386b04 Mon Sep 17 00:00:00 2001 From: ForTehLose Date: Tue, 3 Sep 2024 14:52:49 -0400 Subject: [PATCH] refactor stage, hmd, and local floor --- .../bevy_openxr/examples/common_entities.rs | 108 +++------- crates/bevy_xr_utils/src/lib.rs | 5 +- crates/bevy_xr_utils/src/tracking_utils.rs | 192 ++++++++++++++++++ 3 files changed, 224 insertions(+), 81 deletions(-) create mode 100644 crates/bevy_xr_utils/src/tracking_utils.rs diff --git a/crates/bevy_openxr/examples/common_entities.rs b/crates/bevy_openxr/examples/common_entities.rs index 4c7ae4b..595b2bf 100644 --- a/crates/bevy_openxr/examples/common_entities.rs +++ b/crates/bevy_openxr/examples/common_entities.rs @@ -11,13 +11,16 @@ use bevy_mod_openxr::{ helper_traits::{ToQuat, ToVec3}, resources::{OxrFrameState, OxrInstance, Pipelined}, session::OxrSession, - spaces::{OxrSpaceExt, OxrSpaceLocationFlags, OxrSpaceSyncSet, OxrSpaceVelocityFlags}, + spaces::{OxrSpaceExt, OxrSpaceLocationFlags, OxrSpaceSyncSet}, }; use bevy_mod_xr::{ session::{session_available, session_running, XrSessionCreated, XrTrackingRoot}, - spaces::{XrPrimaryReferenceSpace, XrReferenceSpace, XrSpace, XrVelocity}, + spaces::{XrPrimaryReferenceSpace, XrReferenceSpace, XrSpace}, types::XrPose, }; +use bevy_xr_utils::tracking_utils::{ + TrackingUtilitiesPlugin, XRTrackedLocalFloor, XRTrackedStage, XRTrackedView, +}; use openxr::Posef; fn main() { @@ -38,15 +41,8 @@ fn main() { app.add_systems(XrSessionCreated, attach_set); app.add_systems(Startup, create_actions.run_if(session_available)); - //head space - app.add_systems( - PreUpdate, - update_head_transforms - .in_set(OxrSpaceSyncSet) - .run_if(session_running), - ); - //local floor emulated - app.add_systems(PreUpdate, update_local_floor.after(update_head_transforms)); + //tracking utils plugin + app.add_plugins(TrackingUtilitiesPlugin); app.run(); } @@ -64,13 +60,13 @@ fn setup( transform: Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)), ..default() }); - // cube - commands.spawn(PbrBundle { - mesh: meshes.add(Cuboid::new(1.0, 1.0, 1.0)), - material: materials.add(Color::srgb_u8(124, 144, 255)), - transform: Transform::from_xyz(0.0, 0.5, 0.0), - ..default() - }); + // // cube + // commands.spawn(PbrBundle { + // mesh: meshes.add(Cuboid::new(1.0, 1.0, 1.0)), + // material: materials.add(Color::srgb_u8(124, 144, 255)), + // transform: Transform::from_xyz(0.0, 0.5, 0.0), + // ..default() + // }); // light commands.spawn(PointLightBundle { point_light: PointLight { @@ -175,9 +171,7 @@ fn spawn_hands( )) .id(); //head? - let head_space = session - .create_reference_space(openxr::ReferenceSpaceType::VIEW, Transform::IDENTITY) - .unwrap(); + let head = cmds .spawn(( PbrBundle { @@ -186,7 +180,7 @@ fn spawn_hands( transform: Transform::from_xyz(0.0, 0.0, 0.0), ..default() }, - HeadXRSpace(head_space), + XRTrackedView, )) .id(); //local_floor? emulated @@ -198,7 +192,19 @@ fn spawn_hands( transform: Transform::from_xyz(0.0, 0.0, 0.0), ..default() }, - LocalFloor, + XRTrackedLocalFloor, + )) + .id(); + + let rooter = cmds + .spawn(( + PbrBundle { + mesh: meshes.add(Cuboid::new(0.5, 0.1, 0.5)), + material: materials.add(Color::srgb_u8(144, 255, 255)), + transform: Transform::from_xyz(0.0, 0.0, 0.0), + ..default() + }, + XRTrackedStage, )) .id(); @@ -206,59 +212,3 @@ fn spawn_hands( .push_children(&[left, right, head, local_floor]); } -#[derive(Component)] -struct HeadXRSpace(XrReferenceSpace); - -#[allow(clippy::type_complexity)] -fn update_head_transforms( - session: Res, - default_ref_space: Res, - pipelined: Option>, - frame_state: Res, - mut query: Query<(&mut Transform, &HeadXRSpace, Option<&XrReferenceSpace>)>, -) { - for (mut transform, space, ref_space) in &mut query { - let ref_space = ref_space.unwrap_or(&default_ref_space); - let time = if pipelined.is_some() { - openxr::Time::from_nanos( - frame_state.predicted_display_time.as_nanos() - + frame_state.predicted_display_period.as_nanos(), - ) - } else { - frame_state.predicted_display_time - }; - let space_location = session.locate_space(&space.0, ref_space, time); - - if let Ok(space_location) = space_location { - let flags = OxrSpaceLocationFlags(space_location.location_flags); - if flags.pos_valid() { - transform.translation = space_location.pose.position.to_vec3(); - } - if flags.rot_valid() { - transform.rotation = space_location.pose.orientation.to_quat(); - } - } - } -} - -//emulated local_floor -#[derive(Component)] -struct LocalFloor; - -fn update_local_floor( - mut headSpace: Query<&mut Transform, (With, Without)>, - mut local_floor: Query<&mut Transform, (With, Without)>, -) { - let head_transform = headSpace.get_single_mut(); - match head_transform { - Ok(head) => { - let mut calc_floor = head.clone(); - calc_floor.translation.y = 0.0; - calc_floor.rotation = Quat::IDENTITY; - for (mut transform) in &mut local_floor { - *transform = calc_floor; - } - } - Err(_) => (), - } -} diff --git a/crates/bevy_xr_utils/src/lib.rs b/crates/bevy_xr_utils/src/lib.rs index df9edfd..67b1d71 100644 --- a/crates/bevy_xr_utils/src/lib.rs +++ b/crates/bevy_xr_utils/src/lib.rs @@ -1,6 +1,7 @@ // use bevy::prelude::*; pub mod hand_gizmos; -#[cfg(not(target_family = "wasm"))] -pub mod xr_utils_actions; +pub mod tracking_utils; #[cfg(not(target_family = "wasm"))] pub mod transform_utils; +#[cfg(not(target_family = "wasm"))] +pub mod xr_utils_actions; diff --git a/crates/bevy_xr_utils/src/tracking_utils.rs b/crates/bevy_xr_utils/src/tracking_utils.rs new file mode 100644 index 0000000..655a3e9 --- /dev/null +++ b/crates/bevy_xr_utils/src/tracking_utils.rs @@ -0,0 +1,192 @@ +use bevy::prelude::*; +use bevy_mod_openxr::{ + helper_traits::{ToQuat, ToVec3}, + resources::{OxrFrameState, Pipelined}, + session::OxrSession, + spaces::{OxrSpaceLocationFlags, OxrSpaceSyncSet}, +}; +use bevy_mod_xr::{ + session::{session_running, XrSessionCreated, XrTrackingRoot}, + spaces::{XrPrimaryReferenceSpace, XrReferenceSpace}, +}; +use openxr::Posef; + +//exernal api +#[derive(Component)] +pub struct XRTrackedStage; + +#[derive(Component)] +pub struct XRTrackedLocalFloor; + +#[derive(Component)] +pub struct XRTrackedView; + +#[derive(Component)] +pub struct XRTrackedLeftGrip; + +#[derive(Component)] +pub struct XRTRackedRightGrip; + +pub struct TrackingUtilitiesPlugin; + +impl Plugin for TrackingUtilitiesPlugin { + fn build(&self, app: &mut App) { + //spawn tracking rig + app.add_systems(XrSessionCreated, spawn_tracking_rig); + + //update stage transforms + //external + app.add_systems(PreUpdate, update_stage); + + //head view transforms + //internal + app.add_systems( + PreUpdate, + update_head_transforms + .in_set(OxrSpaceSyncSet) + .run_if(session_running), + ); + //external + app.add_systems(PreUpdate, update_view.after(update_head_transforms)); + + //local floor transforms + //internal + app.add_systems( + PreUpdate, + update_local_floor_transforms.after(update_head_transforms), + ); + //external + app.add_systems( + PreUpdate, + update_local_floor.after(update_local_floor_transforms), + ); + } +} + +//stage +fn update_stage( + mut root_query: Query<&mut Transform, (With, Without)>, + mut stage_query: Query<&mut Transform, (With, Without)>, +) { + let tracking_root_transform = root_query.get_single_mut(); + match tracking_root_transform { + Ok(root) => { + for (mut transform) in &mut stage_query { + *transform = root.clone(); + } + } + Err(_) => (), + } +} + +//view +#[derive(Component)] +struct HeadXRSpace(XrReferenceSpace); + +fn update_head_transforms( + session: Res, + default_ref_space: Res, + pipelined: Option>, + frame_state: Res, + mut query: Query<(&mut Transform, &HeadXRSpace, Option<&XrReferenceSpace>)>, +) { + for (mut transform, space, ref_space) in &mut query { + let ref_space = ref_space.unwrap_or(&default_ref_space); + let time = if pipelined.is_some() { + openxr::Time::from_nanos( + frame_state.predicted_display_time.as_nanos() + + frame_state.predicted_display_period.as_nanos(), + ) + } else { + frame_state.predicted_display_time + }; + let space_location = session.locate_space(&space.0, ref_space, time); + + if let Ok(space_location) = space_location { + let flags = OxrSpaceLocationFlags(space_location.location_flags); + if flags.pos_valid() { + transform.translation = space_location.pose.position.to_vec3(); + } + if flags.rot_valid() { + transform.rotation = space_location.pose.orientation.to_quat(); + } + } + } +} + +fn update_view( + mut head_query: Query<&mut Transform, (With, Without)>, + mut view_query: Query<&mut Transform, (With, Without)>, +) { + let head_transform = head_query.get_single_mut(); + match head_transform { + Ok(root) => { + for (mut transform) in &mut view_query { + *transform = root.clone(); + } + } + Err(_) => (), + } +} + +//local floor +#[derive(Component)] +struct LocalFloor; +//internal +fn update_local_floor_transforms( + mut head_space: Query<&mut Transform, (With, Without)>, + mut local_floor: Query<&mut Transform, (With, Without)>, +) { + let head_transform = head_space.get_single_mut(); + match head_transform { + Ok(head) => { + let mut calc_floor = head.clone(); + calc_floor.translation.y = 0.0; + //TODO: use yaw + calc_floor.rotation = Quat::IDENTITY; + for (mut transform) in &mut local_floor { + *transform = calc_floor; + } + } + Err(_) => (), + } +} +//external +fn update_local_floor( + mut local_floor: Query<&mut Transform, (With, Without)>, + mut tracked_floor: Query<&mut Transform, (With, Without)>, +) { + let head_transform = local_floor.get_single_mut(); + match head_transform { + Ok(head) => { + for (mut transform) in &mut tracked_floor { + *transform = head.clone(); + } + } + Err(_) => (), + } +} + +//tracking rig +#[derive(Resource)] +struct ControllerActions { + set: openxr::ActionSet, + left: openxr::Action, + right: openxr::Action, +} + +fn spawn_tracking_rig( + // actions: Res, + mut cmds: Commands, + // root: Query>, + session: Res, +) { + //head + let head_space = session + .create_reference_space(openxr::ReferenceSpaceType::VIEW, Transform::IDENTITY) + .unwrap(); + let head = cmds + .spawn((SpatialBundle { ..default() }, HeadXRSpace(head_space))) + .id(); + let local_floor = cmds.spawn((SpatialBundle { ..default() }, LocalFloor)).id(); +}