add XrTracker component that auto parents the entity to the XrTrackingRoot, XrSpace requires XrTracker
Signed-off-by: Schmarni <marnistromer@gmail.com>
This commit is contained in:
@@ -11,7 +11,7 @@ use bevy_mod_openxr::{
|
|||||||
spaces::OxrSpaceExt,
|
spaces::OxrSpaceExt,
|
||||||
};
|
};
|
||||||
use bevy_mod_xr::{
|
use bevy_mod_xr::{
|
||||||
session::{session_available, session_running, XrSessionCreated, XrTrackingRoot},
|
session::{session_available, session_running, XrSessionCreated},
|
||||||
spaces::XrSpace,
|
spaces::XrSpace,
|
||||||
};
|
};
|
||||||
use openxr::Posef;
|
use openxr::Posef;
|
||||||
@@ -108,7 +108,6 @@ fn create_actions(instance: Res<OxrInstance>, mut cmds: Commands) {
|
|||||||
fn spawn_hands(
|
fn spawn_hands(
|
||||||
actions: Res<ControllerActions>,
|
actions: Res<ControllerActions>,
|
||||||
mut cmds: Commands,
|
mut cmds: Commands,
|
||||||
root: Query<Entity, With<XrTrackingRoot>>,
|
|
||||||
session: Res<OxrSession>,
|
session: Res<OxrSession>,
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
@@ -128,26 +127,18 @@ fn spawn_hands(
|
|||||||
let right_space = session
|
let right_space = session
|
||||||
.create_action_space(&actions.right, openxr::Path::NULL, Isometry3d::IDENTITY)
|
.create_action_space(&actions.right, openxr::Path::NULL, Isometry3d::IDENTITY)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let left = cmds
|
cmds.spawn((
|
||||||
.spawn((
|
Mesh3d(meshes.add(Cuboid::new(0.1, 0.1, 0.05))),
|
||||||
Mesh3d(meshes.add(Cuboid::new(0.1, 0.1, 0.05))),
|
MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))),
|
||||||
MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))),
|
left_space,
|
||||||
Transform::from_xyz(0.0, 0.5, 0.0),
|
Controller,
|
||||||
left_space,
|
));
|
||||||
Controller,
|
cmds.spawn((
|
||||||
))
|
Mesh3d(meshes.add(Cuboid::new(0.1, 0.1, 0.05))),
|
||||||
.id();
|
MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))),
|
||||||
let right = cmds
|
right_space,
|
||||||
.spawn((
|
Controller,
|
||||||
Mesh3d(meshes.add(Cuboid::new(0.1, 0.1, 0.05))),
|
));
|
||||||
MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))),
|
|
||||||
Transform::from_xyz(0.0, 0.5, 0.0),
|
|
||||||
right_space,
|
|
||||||
Controller,
|
|
||||||
))
|
|
||||||
.id();
|
|
||||||
|
|
||||||
cmds.entity(root.single()).add_children(&[left, right]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_mod_openxr::add_xr_plugins;
|
use bevy_mod_openxr::add_xr_plugins;
|
||||||
use bevy_mod_xr::session::XrSessionCreated;
|
use bevy_mod_xr::session::{XrSessionCreated, XrTracker};
|
||||||
use bevy_xr_utils::tracking_utils::{
|
use bevy_xr_utils::tracking_utils::{
|
||||||
TrackingUtilitiesPlugin, XrTrackedLeftGrip, XrTrackedLocalFloor, XrTrackedRightGrip,
|
TrackingUtilitiesPlugin, XrTrackedLeftGrip, XrTrackedLocalFloor, XrTrackedRightGrip,
|
||||||
XrTrackedStage, XrTrackedView,
|
XrTrackedStage, XrTrackedView,
|
||||||
@@ -53,50 +53,42 @@ fn spawn_hands(
|
|||||||
mut meshes: ResMut<Assets<Mesh>>,
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
) {
|
) {
|
||||||
let left = cmds
|
cmds.spawn((
|
||||||
.spawn((
|
Mesh3d(meshes.add(Cuboid::new(0.1, 0.1, 0.05))),
|
||||||
Mesh3d(meshes.add(Cuboid::new(0.1, 0.1, 0.05))),
|
MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))),
|
||||||
MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))),
|
Transform::from_xyz(0.0, 0.5, 0.0),
|
||||||
Transform::from_xyz(0.0, 0.5, 0.0),
|
XrTrackedLeftGrip,
|
||||||
XrTrackedLeftGrip,
|
XrTracker,
|
||||||
))
|
));
|
||||||
.id();
|
cmds.spawn((
|
||||||
let bundle = (
|
|
||||||
Mesh3d(meshes.add(Cuboid::new(0.1, 0.1, 0.05))),
|
Mesh3d(meshes.add(Cuboid::new(0.1, 0.1, 0.05))),
|
||||||
MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))),
|
MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))),
|
||||||
Transform::from_xyz(0.0, 0.5, 0.0),
|
Transform::from_xyz(0.0, 0.5, 0.0),
|
||||||
XrTrackedRightGrip,
|
XrTrackedRightGrip,
|
||||||
);
|
XrTracker,
|
||||||
let right = cmds.spawn(bundle).id();
|
));
|
||||||
//head
|
//head
|
||||||
|
cmds.spawn((
|
||||||
let head = cmds
|
Mesh3d(meshes.add(Cuboid::new(0.2, 0.2, 0.2))),
|
||||||
.spawn((
|
MeshMaterial3d(materials.add(Color::srgb_u8(255, 144, 144))),
|
||||||
Mesh3d(meshes.add(Cuboid::new(0.2, 0.2, 0.2))),
|
Transform::from_xyz(0.0, 0.0, 0.0),
|
||||||
MeshMaterial3d(materials.add(Color::srgb_u8(255, 144, 144))),
|
XrTrackedView,
|
||||||
Transform::from_xyz(0.0, 0.0, 0.0),
|
XrTracker,
|
||||||
XrTrackedView,
|
));
|
||||||
))
|
|
||||||
.id();
|
|
||||||
//local_floor emulated
|
//local_floor emulated
|
||||||
let local_floor = cmds
|
cmds.spawn((
|
||||||
.spawn((
|
Mesh3d(meshes.add(Cuboid::new(0.5, 0.1, 0.5))),
|
||||||
Mesh3d(meshes.add(Cuboid::new(0.5, 0.1, 0.5))),
|
MeshMaterial3d(materials.add(Color::srgb_u8(144, 255, 144))),
|
||||||
MeshMaterial3d(materials.add(Color::srgb_u8(144, 255, 144))),
|
Transform::from_xyz(0.0, 0.0, 0.0),
|
||||||
Transform::from_xyz(0.0, 0.0, 0.0),
|
XrTrackedLocalFloor,
|
||||||
XrTrackedLocalFloor,
|
XrTracker,
|
||||||
))
|
));
|
||||||
.id();
|
|
||||||
|
|
||||||
let stage = cmds
|
cmds.spawn((
|
||||||
.spawn((
|
Mesh3d(meshes.add(Cuboid::new(0.5, 0.1, 0.5))),
|
||||||
Mesh3d(meshes.add(Cuboid::new(0.5, 0.1, 0.5))),
|
MeshMaterial3d(materials.add(Color::srgb_u8(144, 255, 255))),
|
||||||
MeshMaterial3d(materials.add(Color::srgb_u8(144, 255, 255))),
|
Transform::from_xyz(0.0, 0.0, 0.0),
|
||||||
Transform::from_xyz(0.0, 0.0, 0.0),
|
XrTrackedStage,
|
||||||
XrTrackedStage,
|
XrTracker,
|
||||||
))
|
));
|
||||||
.id();
|
|
||||||
|
|
||||||
cmds.entity(stage)
|
|
||||||
.add_children(&[left, right, head, local_floor]);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_mod_xr::hands::{
|
use bevy_mod_xr::hands::{
|
||||||
spawn_hand_bones, HandBone, HandBoneRadius, HandSide, SpawnHandTracker,
|
spawn_hand_bones, HandBone, HandSide, SpawnHandTracker, SpawnHandTrackerCommandExecutor,
|
||||||
SpawnHandTrackerCommandExecutor,
|
XrHandBoneRadius,
|
||||||
};
|
};
|
||||||
use bevy_mod_xr::hands::{LeftHand, RightHand, XrHandBoneEntities};
|
use bevy_mod_xr::hands::{LeftHand, RightHand, XrHandBoneEntities};
|
||||||
use bevy_mod_xr::session::{XrPreDestroySession, XrSessionCreated, XrTrackingRoot};
|
use bevy_mod_xr::session::{XrPreDestroySession, XrSessionCreated};
|
||||||
use bevy_mod_xr::spaces::{
|
use bevy_mod_xr::spaces::{
|
||||||
XrPrimaryReferenceSpace, XrReferenceSpace, XrSpaceLocationFlags, XrSpaceVelocityFlags,
|
XrPrimaryReferenceSpace, XrReferenceSpace, XrSpaceLocationFlags, XrSpaceVelocityFlags,
|
||||||
XrVelocity,
|
XrVelocity,
|
||||||
@@ -70,11 +70,7 @@ fn handle_tracker_spawn(world: &mut World, tracker: Entity, side: HandSide) {
|
|||||||
.insert(OxrHandTracker(oxr_tracker));
|
.insert(OxrHandTracker(oxr_tracker));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_default_hands(mut cmds: Commands, root: Query<Entity, With<XrTrackingRoot>>) {
|
fn spawn_default_hands(mut cmds: Commands) {
|
||||||
let Ok(root) = root.get_single() else {
|
|
||||||
error!("unable to get tracking root, skipping handtracker creation");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
debug!("spawning default hands");
|
debug!("spawning default hands");
|
||||||
let left_bones = spawn_hand_bones(&mut cmds, |_| {
|
let left_bones = spawn_hand_bones(&mut cmds, |_| {
|
||||||
(
|
(
|
||||||
@@ -90,8 +86,6 @@ fn spawn_default_hands(mut cmds: Commands, root: Query<Entity, With<XrTrackingRo
|
|||||||
OxrSpaceLocationFlags(openxr::SpaceLocationFlags::default()),
|
OxrSpaceLocationFlags(openxr::SpaceLocationFlags::default()),
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
cmds.entity(root).add_children(&left_bones);
|
|
||||||
cmds.entity(root).add_children(&right_bones);
|
|
||||||
cmds.queue(SpawnHandTracker {
|
cmds.queue(SpawnHandTracker {
|
||||||
joints: XrHandBoneEntities(left_bones),
|
joints: XrHandBoneEntities(left_bones),
|
||||||
tracker_bundle: DefaultHandTracker,
|
tracker_bundle: DefaultHandTracker,
|
||||||
@@ -134,7 +128,7 @@ fn locate_hands(
|
|||||||
session: Res<OxrSession>,
|
session: Res<OxrSession>,
|
||||||
mut bone_query: Query<(
|
mut bone_query: Query<(
|
||||||
&HandBone,
|
&HandBone,
|
||||||
&mut HandBoneRadius,
|
&mut XrHandBoneRadius,
|
||||||
&mut Transform,
|
&mut Transform,
|
||||||
Option<&mut XrVelocity>,
|
Option<&mut XrVelocity>,
|
||||||
&mut OxrSpaceLocationFlags,
|
&mut OxrSpaceLocationFlags,
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use bevy::{
|
use bevy::{
|
||||||
ecs::query::QuerySingleError,
|
|
||||||
prelude::*,
|
prelude::*,
|
||||||
render::{
|
render::{
|
||||||
camera::{ManualTextureView, ManualTextureViewHandle, ManualTextureViews, RenderTarget},
|
camera::{ManualTextureView, ManualTextureViewHandle, ManualTextureViews, RenderTarget},
|
||||||
@@ -12,9 +11,7 @@ use bevy::{
|
|||||||
};
|
};
|
||||||
use bevy_mod_xr::{
|
use bevy_mod_xr::{
|
||||||
camera::{XrCamera, XrProjection},
|
camera::{XrCamera, XrProjection},
|
||||||
session::{
|
session::{XrFirst, XrHandleEvents, XrPreDestroySession, XrRenderSet, XrRootTransform},
|
||||||
XrFirst, XrHandleEvents, XrPreDestroySession, XrRenderSet, XrRootTransform, XrTrackingRoot,
|
|
||||||
},
|
|
||||||
spaces::XrPrimaryReferenceSpace,
|
spaces::XrPrimaryReferenceSpace,
|
||||||
};
|
};
|
||||||
use openxr::ViewStateFlags;
|
use openxr::ViewStateFlags;
|
||||||
@@ -34,10 +31,6 @@ impl Plugin for OxrRenderPlugin {
|
|||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
if app.is_plugin_added::<PipelinedRenderingPlugin>() {
|
if app.is_plugin_added::<PipelinedRenderingPlugin>() {
|
||||||
app.init_resource::<Pipelined>();
|
app.init_resource::<Pipelined>();
|
||||||
|
|
||||||
// if let Some(sub_app) = app.remove_sub_app(RenderExtractApp) {
|
|
||||||
// app.insert_sub_app(RenderExtractApp, SubApp::new(sub_app.app, update_rendering));
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.add_plugins((
|
app.add_plugins((
|
||||||
@@ -140,7 +133,6 @@ pub fn init_views(
|
|||||||
graphics_info: Res<OxrGraphicsInfo>,
|
graphics_info: Res<OxrGraphicsInfo>,
|
||||||
mut manual_texture_views: ResMut<ManualTextureViews>,
|
mut manual_texture_views: ResMut<ManualTextureViews>,
|
||||||
swapchain_images: Res<OxrSwapchainImages>,
|
swapchain_images: Res<OxrSwapchainImages>,
|
||||||
root: Query<Entity, With<XrTrackingRoot>>,
|
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
) {
|
) {
|
||||||
let _span = info_span!("xr_init_views");
|
let _span = info_span!("xr_init_views");
|
||||||
@@ -150,27 +142,13 @@ pub fn init_views(
|
|||||||
info!("XrCamera resolution: {}", graphics_info.resolution);
|
info!("XrCamera resolution: {}", graphics_info.resolution);
|
||||||
let view_handle =
|
let view_handle =
|
||||||
add_texture_view(&mut manual_texture_views, temp_tex, &graphics_info, index);
|
add_texture_view(&mut manual_texture_views, temp_tex, &graphics_info, index);
|
||||||
let cam = commands
|
commands.spawn((
|
||||||
.spawn((
|
Camera {
|
||||||
Camera {
|
target: RenderTarget::TextureView(view_handle),
|
||||||
target: RenderTarget::TextureView(view_handle),
|
..Default::default()
|
||||||
..Default::default()
|
},
|
||||||
},
|
XrCamera(index),
|
||||||
XrCamera(index),
|
));
|
||||||
))
|
|
||||||
.remove::<Projection>()
|
|
||||||
.id();
|
|
||||||
match root.get_single() {
|
|
||||||
Ok(root) => {
|
|
||||||
commands.entity(root).add_child(cam);
|
|
||||||
}
|
|
||||||
Err(QuerySingleError::NoEntities(_)) => {
|
|
||||||
warn!("No XrTrackingRoot!");
|
|
||||||
}
|
|
||||||
Err(QuerySingleError::MultipleEntities(_)) => {
|
|
||||||
warn!("Multiple XrTrackingRoots! this is not allowed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use core::panic;
|
use core::panic;
|
||||||
|
|
||||||
use bevy::app::{App, Plugin, PostUpdate};
|
use bevy::app::{App, Plugin, PostUpdate};
|
||||||
use bevy::core_pipeline::core_3d::graph::Core3d;
|
|
||||||
use bevy::core_pipeline::core_3d::Camera3d;
|
use bevy::core_pipeline::core_3d::Camera3d;
|
||||||
use bevy::ecs::component::{Component, StorageType};
|
use bevy::ecs::component::{Component, StorageType};
|
||||||
use bevy::ecs::reflect::ReflectComponent;
|
use bevy::ecs::reflect::ReflectComponent;
|
||||||
@@ -18,6 +17,8 @@ use bevy::render::extract_component::{ExtractComponent, ExtractComponentPlugin};
|
|||||||
use bevy::render::view::{update_frusta, VisibilitySystems};
|
use bevy::render::view::{update_frusta, VisibilitySystems};
|
||||||
use bevy::transform::TransformSystem;
|
use bevy::transform::TransformSystem;
|
||||||
|
|
||||||
|
use crate::session::XrTracker;
|
||||||
|
|
||||||
pub struct XrCameraPlugin;
|
pub struct XrCameraPlugin;
|
||||||
|
|
||||||
impl Plugin for XrCameraPlugin {
|
impl Plugin for XrCameraPlugin {
|
||||||
@@ -69,7 +70,7 @@ impl Default for XrProjection {
|
|||||||
|
|
||||||
/// Marker component for an XR view. It is the backends responsibility to update this.
|
/// Marker component for an XR view. It is the backends responsibility to update this.
|
||||||
#[derive(Clone, Copy, Component, ExtractComponent, Debug, Default)]
|
#[derive(Clone, Copy, Component, ExtractComponent, Debug, Default)]
|
||||||
#[require(Camera3d, XrProjection)]
|
#[require(Camera3d, XrProjection, XrTracker)]
|
||||||
pub struct XrCamera(pub u32);
|
pub struct XrCamera(pub u32);
|
||||||
|
|
||||||
impl CameraProjection for XrProjection {
|
impl CameraProjection for XrProjection {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
use bevy::{
|
use bevy::{
|
||||||
ecs::{component::Component, entity::Entity, world::Command},
|
ecs::{component::Component, entity::Entity, world::Command},
|
||||||
log::{error, warn},
|
log::warn,
|
||||||
math::bool,
|
math::bool,
|
||||||
prelude::{BuildChildren, Bundle, Commands, Deref, DerefMut, Resource, Transform, Visibility, With, World},
|
prelude::{Bundle, Commands, Deref, DerefMut, Resource, Transform, Visibility, World},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{session::XrTrackingRoot, spaces::XrSpaceLocationFlags};
|
use crate::{session::XrTracker, spaces::XrSpaceLocationFlags};
|
||||||
pub const HAND_JOINT_COUNT: usize = 26;
|
pub const HAND_JOINT_COUNT: usize = 26;
|
||||||
|
|
||||||
pub fn spawn_hand_bones<T: Bundle>(
|
pub fn spawn_hand_bones<T: Bundle>(
|
||||||
@@ -14,16 +14,7 @@ pub fn spawn_hand_bones<T: Bundle>(
|
|||||||
) -> [Entity; HAND_JOINT_COUNT] {
|
) -> [Entity; HAND_JOINT_COUNT] {
|
||||||
let mut bones: [Entity; HAND_JOINT_COUNT] = [Entity::PLACEHOLDER; HAND_JOINT_COUNT];
|
let mut bones: [Entity; HAND_JOINT_COUNT] = [Entity::PLACEHOLDER; HAND_JOINT_COUNT];
|
||||||
for bone in HandBone::get_all_bones().into_iter() {
|
for bone in HandBone::get_all_bones().into_iter() {
|
||||||
bones[bone as usize] = cmds
|
bones[bone as usize] = cmds.spawn((bone, (get_bundle)(bone))).id();
|
||||||
.spawn((
|
|
||||||
Transform::default(),
|
|
||||||
Visibility::default(),
|
|
||||||
bone,
|
|
||||||
HandBoneRadius(0.0),
|
|
||||||
XrSpaceLocationFlags::default(),
|
|
||||||
))
|
|
||||||
.insert((get_bundle)(bone))
|
|
||||||
.id();
|
|
||||||
}
|
}
|
||||||
bones
|
bones
|
||||||
}
|
}
|
||||||
@@ -45,11 +36,18 @@ pub struct RightHand;
|
|||||||
pub struct XrHandBoneEntities(pub [Entity; HAND_JOINT_COUNT]);
|
pub struct XrHandBoneEntities(pub [Entity; HAND_JOINT_COUNT]);
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(Clone, Copy, Component, Debug, DerefMut, Deref)]
|
#[derive(Clone, Copy, Component, Debug, DerefMut, Deref, Default)]
|
||||||
pub struct HandBoneRadius(pub f32);
|
pub struct XrHandBoneRadius(pub f32);
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Clone, Copy, Component, Debug)]
|
#[derive(Clone, Copy, Component, Debug)]
|
||||||
|
#[require(
|
||||||
|
XrSpaceLocationFlags,
|
||||||
|
XrHandBoneRadius,
|
||||||
|
Transform,
|
||||||
|
Visibility,
|
||||||
|
XrTracker
|
||||||
|
)]
|
||||||
pub enum HandBone {
|
pub enum HandBone {
|
||||||
Palm = 0,
|
Palm = 0,
|
||||||
Wrist = 1,
|
Wrist = 1,
|
||||||
@@ -189,20 +187,12 @@ impl<B: Bundle> Command for SpawnHandTracker<B> {
|
|||||||
warn!("no SpawnHandTracker executor defined, skipping handtracker creation");
|
warn!("no SpawnHandTracker executor defined, skipping handtracker creation");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let Ok(root) = world
|
|
||||||
.query_filtered::<Entity, With<XrTrackingRoot>>()
|
|
||||||
.get_single(world)
|
|
||||||
else {
|
|
||||||
error!("unable to get tracking root, skipping handtracker creation");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let mut tracker = world.spawn(self.joints);
|
let mut tracker = world.spawn(self.joints);
|
||||||
match &self.side {
|
match &self.side {
|
||||||
HandSide::Left => tracker.insert(LeftHand),
|
HandSide::Left => tracker.insert((XrTracker, LeftHand)),
|
||||||
HandSide::Right => tracker.insert(LeftHand),
|
HandSide::Right => tracker.insert((XrTracker, RightHand)),
|
||||||
};
|
};
|
||||||
let tracker = tracker.id();
|
let tracker = tracker.id();
|
||||||
world.entity_mut(root).add_children(&[tracker]);
|
|
||||||
executor.0(world, tracker, self.side);
|
executor.0(world, tracker, self.side);
|
||||||
if let Ok(mut tracker) = world.get_entity_mut(tracker) {
|
if let Ok(mut tracker) = world.get_entity_mut(tracker) {
|
||||||
tracker.insert(self.side);
|
tracker.insert(self.side);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use std::sync::atomic::AtomicBool;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use bevy::app::{AppExit, MainScheduleOrder};
|
use bevy::app::{AppExit, MainScheduleOrder};
|
||||||
|
use bevy::ecs::component::StorageType;
|
||||||
use bevy::ecs::schedule::ScheduleLabel;
|
use bevy::ecs::schedule::ScheduleLabel;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::render::extract_resource::{ExtractResource, ExtractResourcePlugin};
|
use bevy::render::extract_resource::{ExtractResource, ExtractResourcePlugin};
|
||||||
@@ -84,7 +85,29 @@ pub struct XrRootTransform(pub GlobalTransform);
|
|||||||
|
|
||||||
/// Component used to specify the entity we should use as the tracking root.
|
/// Component used to specify the entity we should use as the tracking root.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
|
#[require(Transform, Visibility)]
|
||||||
pub struct XrTrackingRoot;
|
pub struct XrTrackingRoot;
|
||||||
|
#[derive(Resource)]
|
||||||
|
struct TrackingRootRes(Entity);
|
||||||
|
|
||||||
|
/// Makes the entity a child of the XrTrackingRoot if the entity has no parent
|
||||||
|
#[derive(Clone, Copy, Hash, PartialEq, Eq, Reflect, Debug, Default)]
|
||||||
|
pub struct XrTracker;
|
||||||
|
impl Component for XrTracker {
|
||||||
|
const STORAGE_TYPE: StorageType = StorageType::SparseSet;
|
||||||
|
|
||||||
|
fn register_component_hooks(hooks: &mut bevy::ecs::component::ComponentHooks) {
|
||||||
|
hooks.on_add(|mut world, entity, _| {
|
||||||
|
if world.entity(entity).components::<Has<Parent>>() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let Some(root) = world.get_resource::<TrackingRootRes>().map(|r| r.0) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
world.commands().entity(root).add_child(entity);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct XrSessionPlugin {
|
pub struct XrSessionPlugin {
|
||||||
pub auto_handle: bool,
|
pub auto_handle: bool,
|
||||||
@@ -125,12 +148,12 @@ impl Plugin for XrSessionPlugin {
|
|||||||
.run_if(session_created)
|
.run_if(session_created)
|
||||||
.in_set(XrHandleEvents::ExitEvents),
|
.in_set(XrHandleEvents::ExitEvents),
|
||||||
);
|
);
|
||||||
|
let root = app.world_mut().spawn(XrTrackingRoot).id();
|
||||||
|
app.world_mut().insert_resource(TrackingRootRes(root));
|
||||||
app.world_mut()
|
app.world_mut()
|
||||||
.resource_mut::<MainScheduleOrder>()
|
.resource_mut::<MainScheduleOrder>()
|
||||||
.labels
|
.labels
|
||||||
.insert(0, XrFirst.intern());
|
.insert(0, XrFirst.intern());
|
||||||
app.world_mut()
|
|
||||||
.spawn((Transform::default(), Visibility::default(), XrTrackingRoot));
|
|
||||||
|
|
||||||
if self.auto_handle {
|
if self.auto_handle {
|
||||||
app.add_systems(PreUpdate, auto_handle_session);
|
app.add_systems(PreUpdate, auto_handle_session);
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
use bevy::{
|
use bevy::{
|
||||||
ecs::component::StorageType,
|
|
||||||
prelude::*,
|
prelude::*,
|
||||||
render::{extract_component::ExtractComponent, extract_resource::ExtractResource},
|
render::{extract_component::ExtractComponent, extract_resource::ExtractResource},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::session::XrTracker;
|
||||||
|
|
||||||
/// Any Spaces will be invalid after the owning session exits
|
/// Any Spaces will be invalid after the owning session exits
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(Clone, Copy, Hash, PartialEq, Eq, Reflect, Debug, ExtractComponent)]
|
#[derive(Component, Clone, Copy, Hash, PartialEq, Eq, Reflect, Debug, ExtractComponent)]
|
||||||
|
#[require(XrSpaceLocationFlags, Transform, Visibility, XrTracker)]
|
||||||
pub struct XrSpace(u64);
|
pub struct XrSpace(u64);
|
||||||
|
|
||||||
#[derive(Clone, Copy, Reflect, Debug, ExtractComponent, Default)]
|
#[derive(Component, Clone, Copy, Reflect, Debug, ExtractComponent, Default)]
|
||||||
|
#[require(XrSpaceVelocityFlags)]
|
||||||
pub struct XrVelocity {
|
pub struct XrVelocity {
|
||||||
/// Velocity of a space relative to it's reference space
|
/// Velocity of a space relative to it's reference space
|
||||||
pub linear: Vec3,
|
pub linear: Vec3,
|
||||||
@@ -69,28 +72,3 @@ impl XrSpace {
|
|||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for XrSpace {
|
|
||||||
const STORAGE_TYPE: StorageType = StorageType::Table;
|
|
||||||
|
|
||||||
fn register_component_hooks(hooks: &mut bevy::ecs::component::ComponentHooks) {
|
|
||||||
hooks.on_add(|mut world, entity, _| {
|
|
||||||
world
|
|
||||||
.commands()
|
|
||||||
.entity(entity)
|
|
||||||
.insert(XrSpaceLocationFlags::default());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Component for XrVelocity {
|
|
||||||
const STORAGE_TYPE: StorageType = StorageType::Table;
|
|
||||||
|
|
||||||
fn register_component_hooks(hooks: &mut bevy::ecs::component::ComponentHooks) {
|
|
||||||
hooks.on_add(|mut world, entity, _| {
|
|
||||||
world
|
|
||||||
.commands()
|
|
||||||
.entity(entity)
|
|
||||||
.insert(XrSpaceVelocityFlags::default());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use bevy::color::palettes::css;
|
use bevy::color::palettes::css;
|
||||||
use bevy::{prelude::*, transform::TransformSystem};
|
use bevy::{prelude::*, transform::TransformSystem};
|
||||||
use bevy_mod_xr::hands::{HandBone, HandBoneRadius};
|
use bevy_mod_xr::hands::{HandBone, XrHandBoneRadius};
|
||||||
use bevy_mod_xr::spaces::XrSpaceLocationFlags;
|
use bevy_mod_xr::spaces::XrSpaceLocationFlags;
|
||||||
pub struct HandGizmosPlugin;
|
pub struct HandGizmosPlugin;
|
||||||
impl Plugin for HandGizmosPlugin {
|
impl Plugin for HandGizmosPlugin {
|
||||||
@@ -16,7 +16,7 @@ fn draw_hand_gizmos(
|
|||||||
query: Query<(
|
query: Query<(
|
||||||
&GlobalTransform,
|
&GlobalTransform,
|
||||||
&HandBone,
|
&HandBone,
|
||||||
&HandBoneRadius,
|
&XrHandBoneRadius,
|
||||||
&XrSpaceLocationFlags,
|
&XrSpaceLocationFlags,
|
||||||
)>,
|
)>,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use bevy_mod_openxr::{
|
|||||||
spaces::{OxrSpaceLocationFlags, OxrSpaceSyncSet},
|
spaces::{OxrSpaceLocationFlags, OxrSpaceSyncSet},
|
||||||
};
|
};
|
||||||
use bevy_mod_xr::{
|
use bevy_mod_xr::{
|
||||||
session::{XrSessionCreated, XrTrackingRoot},
|
session::{XrSessionCreated, XrTracker, XrTrackingRoot},
|
||||||
spaces::{XrPrimaryReferenceSpace, XrReferenceSpace},
|
spaces::{XrPrimaryReferenceSpace, XrReferenceSpace},
|
||||||
};
|
};
|
||||||
use openxr::Posef;
|
use openxr::Posef;
|
||||||
@@ -80,11 +80,10 @@ impl Plugin for TrackingUtilitiesPlugin {
|
|||||||
|
|
||||||
//stage
|
//stage
|
||||||
fn update_stage(
|
fn update_stage(
|
||||||
mut root_query: Query<&mut Transform, (With<XrTrackingRoot>, Without<XrTrackedStage>)>,
|
root_query: Query<&Transform, (With<XrTrackingRoot>, Without<XrTrackedStage>)>,
|
||||||
mut stage_query: Query<&mut Transform, (With<XrTrackedStage>, Without<XrTrackingRoot>)>,
|
mut stage_query: Query<&mut Transform, (With<XrTrackedStage>, Without<XrTrackingRoot>)>,
|
||||||
) {
|
) {
|
||||||
let tracking_root_transform = root_query.get_single_mut();
|
if let Ok(root) = root_query.get_single() {
|
||||||
if let Ok(root) = tracking_root_transform {
|
|
||||||
for mut transform in &mut stage_query {
|
for mut transform in &mut stage_query {
|
||||||
*transform = *root;
|
*transform = *root;
|
||||||
}
|
}
|
||||||
@@ -148,10 +147,10 @@ fn update_local_floor_transforms(
|
|||||||
let mut calc_floor = *head;
|
let mut calc_floor = *head;
|
||||||
calc_floor.translation.y = 0.0;
|
calc_floor.translation.y = 0.0;
|
||||||
//TODO: use yaw
|
//TODO: use yaw
|
||||||
let (y, x, z) = calc_floor.rotation.to_euler(EulerRot::YXZ);
|
let (y, _, _) = calc_floor.rotation.to_euler(EulerRot::YXZ);
|
||||||
let new_rot = Quat::from_rotation_y(y);
|
let new_rot = Quat::from_rotation_y(y);
|
||||||
calc_floor.rotation = new_rot;
|
calc_floor.rotation = new_rot;
|
||||||
for (mut transform) in &mut local_floor {
|
for mut transform in &mut local_floor {
|
||||||
*transform = calc_floor;
|
*transform = calc_floor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,13 +165,10 @@ fn update_left_grip(
|
|||||||
mut tracked_left_grip: Query<&mut Transform, (With<XrTrackedLeftGrip>, Without<LeftGrip>)>,
|
mut tracked_left_grip: Query<&mut Transform, (With<XrTrackedLeftGrip>, Without<LeftGrip>)>,
|
||||||
) {
|
) {
|
||||||
let head_transform = left_grip.get_single_mut();
|
let head_transform = left_grip.get_single_mut();
|
||||||
match head_transform {
|
if let Ok(head) = head_transform {
|
||||||
Ok(head) => {
|
for mut transform in &mut tracked_left_grip {
|
||||||
for (mut transform) in &mut tracked_left_grip {
|
*transform = *head;
|
||||||
*transform = head.clone();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(_) => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,13 +181,10 @@ fn update_right_grip(
|
|||||||
mut tracked_right_grip: Query<&mut Transform, (With<XrTrackedRightGrip>, Without<RightGrip>)>,
|
mut tracked_right_grip: Query<&mut Transform, (With<XrTrackedRightGrip>, Without<RightGrip>)>,
|
||||||
) {
|
) {
|
||||||
let head_transform = right_grip.get_single_mut();
|
let head_transform = right_grip.get_single_mut();
|
||||||
match head_transform {
|
if let Ok(head) = head_transform {
|
||||||
Ok(head) => {
|
for mut transform in &mut tracked_right_grip {
|
||||||
for (mut transform) in &mut tracked_right_grip {
|
*transform = *head;
|
||||||
*transform = head.clone();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(_) => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,16 +199,18 @@ struct ControllerActions {
|
|||||||
fn spawn_tracking_rig(
|
fn spawn_tracking_rig(
|
||||||
actions: Res<ControllerActions>,
|
actions: Res<ControllerActions>,
|
||||||
mut cmds: Commands,
|
mut cmds: Commands,
|
||||||
root: Query<Entity, With<XrTrackingRoot>>,
|
|
||||||
session: Res<OxrSession>,
|
session: Res<OxrSession>,
|
||||||
) {
|
) {
|
||||||
//head
|
//head
|
||||||
let head_space = session
|
let head_space = session
|
||||||
.create_reference_space(openxr::ReferenceSpaceType::VIEW, Transform::IDENTITY)
|
.create_reference_space(openxr::ReferenceSpaceType::VIEW, Transform::IDENTITY)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let head = cmds
|
cmds.spawn((
|
||||||
.spawn((SpatialBundle::default(), HeadXRSpace(head_space)))
|
Transform::default(),
|
||||||
.id();
|
Visibility::default(),
|
||||||
|
XrTracker,
|
||||||
|
HeadXRSpace(head_space),
|
||||||
|
));
|
||||||
// let local_floor = cmds.spawn((SpatialBundle::default(), LocalFloor)).id();
|
// let local_floor = cmds.spawn((SpatialBundle::default(), LocalFloor)).id();
|
||||||
|
|
||||||
let left_space = session
|
let left_space = session
|
||||||
@@ -224,25 +219,8 @@ fn spawn_tracking_rig(
|
|||||||
let right_space = session
|
let right_space = session
|
||||||
.create_action_space(&actions.right, openxr::Path::NULL, Isometry3d::IDENTITY)
|
.create_action_space(&actions.right, openxr::Path::NULL, Isometry3d::IDENTITY)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let left = cmds
|
cmds.spawn((left_space, LeftGrip));
|
||||||
.spawn((
|
cmds.spawn((right_space, RightGrip));
|
||||||
Transform::default(),
|
|
||||||
Visibility::default(),
|
|
||||||
left_space,
|
|
||||||
LeftGrip,
|
|
||||||
))
|
|
||||||
.id();
|
|
||||||
let right = cmds
|
|
||||||
.spawn((
|
|
||||||
Transform::default(),
|
|
||||||
Visibility::default(),
|
|
||||||
right_space,
|
|
||||||
RightGrip,
|
|
||||||
))
|
|
||||||
.id();
|
|
||||||
|
|
||||||
cmds.entity(root.single())
|
|
||||||
.add_children(&[head, left, right]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//bindings
|
//bindings
|
||||||
|
|||||||
Reference in New Issue
Block a user