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:
Schmarni
2024-11-20 11:46:24 +01:00
parent d1cc160cac
commit a04ebb8426
10 changed files with 128 additions and 203 deletions

View File

@@ -1,7 +1,6 @@
use core::panic;
use bevy::app::{App, Plugin, PostUpdate};
use bevy::core_pipeline::core_3d::graph::Core3d;
use bevy::core_pipeline::core_3d::Camera3d;
use bevy::ecs::component::{Component, StorageType};
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::transform::TransformSystem;
use crate::session::XrTracker;
pub struct 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.
#[derive(Clone, Copy, Component, ExtractComponent, Debug, Default)]
#[require(Camera3d, XrProjection)]
#[require(Camera3d, XrProjection, XrTracker)]
pub struct XrCamera(pub u32);
impl CameraProjection for XrProjection {

View File

@@ -1,11 +1,11 @@
use bevy::{
ecs::{component::Component, entity::Entity, world::Command},
log::{error, warn},
log::warn,
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 fn spawn_hand_bones<T: Bundle>(
@@ -14,16 +14,7 @@ pub fn spawn_hand_bones<T: Bundle>(
) -> [Entity; HAND_JOINT_COUNT] {
let mut bones: [Entity; HAND_JOINT_COUNT] = [Entity::PLACEHOLDER; HAND_JOINT_COUNT];
for bone in HandBone::get_all_bones().into_iter() {
bones[bone as usize] = cmds
.spawn((
Transform::default(),
Visibility::default(),
bone,
HandBoneRadius(0.0),
XrSpaceLocationFlags::default(),
))
.insert((get_bundle)(bone))
.id();
bones[bone as usize] = cmds.spawn((bone, (get_bundle)(bone))).id();
}
bones
}
@@ -45,11 +36,18 @@ pub struct RightHand;
pub struct XrHandBoneEntities(pub [Entity; HAND_JOINT_COUNT]);
#[repr(transparent)]
#[derive(Clone, Copy, Component, Debug, DerefMut, Deref)]
pub struct HandBoneRadius(pub f32);
#[derive(Clone, Copy, Component, Debug, DerefMut, Deref, Default)]
pub struct XrHandBoneRadius(pub f32);
#[repr(u8)]
#[derive(Clone, Copy, Component, Debug)]
#[require(
XrSpaceLocationFlags,
XrHandBoneRadius,
Transform,
Visibility,
XrTracker
)]
pub enum HandBone {
Palm = 0,
Wrist = 1,
@@ -189,20 +187,12 @@ impl<B: Bundle> Command for SpawnHandTracker<B> {
warn!("no SpawnHandTracker executor defined, skipping handtracker creation");
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);
match &self.side {
HandSide::Left => tracker.insert(LeftHand),
HandSide::Right => tracker.insert(LeftHand),
HandSide::Left => tracker.insert((XrTracker, LeftHand)),
HandSide::Right => tracker.insert((XrTracker, RightHand)),
};
let tracker = tracker.id();
world.entity_mut(root).add_children(&[tracker]);
executor.0(world, tracker, self.side);
if let Ok(mut tracker) = world.get_entity_mut(tracker) {
tracker.insert(self.side);

View File

@@ -2,6 +2,7 @@ use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use bevy::app::{AppExit, MainScheduleOrder};
use bevy::ecs::component::StorageType;
use bevy::ecs::schedule::ScheduleLabel;
use bevy::prelude::*;
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.
#[derive(Component)]
#[require(Transform, Visibility)]
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 auto_handle: bool,
@@ -125,12 +148,12 @@ impl Plugin for XrSessionPlugin {
.run_if(session_created)
.in_set(XrHandleEvents::ExitEvents),
);
let root = app.world_mut().spawn(XrTrackingRoot).id();
app.world_mut().insert_resource(TrackingRootRes(root));
app.world_mut()
.resource_mut::<MainScheduleOrder>()
.labels
.insert(0, XrFirst.intern());
app.world_mut()
.spawn((Transform::default(), Visibility::default(), XrTrackingRoot));
if self.auto_handle {
app.add_systems(PreUpdate, auto_handle_session);

View File

@@ -1,15 +1,18 @@
use bevy::{
ecs::component::StorageType,
prelude::*,
render::{extract_component::ExtractComponent, extract_resource::ExtractResource},
};
use crate::session::XrTracker;
/// Any Spaces will be invalid after the owning session exits
#[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);
#[derive(Clone, Copy, Reflect, Debug, ExtractComponent, Default)]
#[derive(Component, Clone, Copy, Reflect, Debug, ExtractComponent, Default)]
#[require(XrSpaceVelocityFlags)]
pub struct XrVelocity {
/// Velocity of a space relative to it's reference space
pub linear: Vec3,
@@ -69,28 +72,3 @@ impl XrSpace {
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());
});
}
}