refactor stage, hmd, and local floor
This commit is contained in:
@@ -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<OxrSession>,
|
||||
default_ref_space: Res<XrPrimaryReferenceSpace>,
|
||||
pipelined: Option<Res<Pipelined>>,
|
||||
frame_state: Res<OxrFrameState>,
|
||||
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<HeadXRSpace>, Without<LocalFloor>)>,
|
||||
mut local_floor: Query<&mut Transform, (With<LocalFloor>, Without<HeadXRSpace>)>,
|
||||
) {
|
||||
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(_) => (),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
192
crates/bevy_xr_utils/src/tracking_utils.rs
Normal file
192
crates/bevy_xr_utils/src/tracking_utils.rs
Normal file
@@ -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<XrTrackingRoot>, Without<XRTrackedStage>)>,
|
||||
mut stage_query: Query<&mut Transform, (With<XRTrackedStage>, Without<XrTrackingRoot>)>,
|
||||
) {
|
||||
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<OxrSession>,
|
||||
default_ref_space: Res<XrPrimaryReferenceSpace>,
|
||||
pipelined: Option<Res<Pipelined>>,
|
||||
frame_state: Res<OxrFrameState>,
|
||||
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<HeadXRSpace>, Without<XRTrackedView>)>,
|
||||
mut view_query: Query<&mut Transform, (With<XRTrackedView>, Without<HeadXRSpace>)>,
|
||||
) {
|
||||
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<HeadXRSpace>, Without<LocalFloor>)>,
|
||||
mut local_floor: Query<&mut Transform, (With<LocalFloor>, Without<HeadXRSpace>)>,
|
||||
) {
|
||||
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<LocalFloor>, Without<XRTrackedLocalFloor>)>,
|
||||
mut tracked_floor: Query<&mut Transform, (With<XRTrackedLocalFloor>, Without<LocalFloor>)>,
|
||||
) {
|
||||
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<Posef>,
|
||||
right: openxr::Action<Posef>,
|
||||
}
|
||||
|
||||
fn spawn_tracking_rig(
|
||||
// actions: Res<ControllerActions>,
|
||||
mut cmds: Commands,
|
||||
// root: Query<Entity, With<XrTrackingRoot>>,
|
||||
session: Res<OxrSession>,
|
||||
) {
|
||||
//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();
|
||||
}
|
||||
Reference in New Issue
Block a user