clean up passthrough, change hand entity behavior and add cleanup steps to some plugins

This commit is contained in:
Schmarni
2024-02-12 09:05:44 +01:00
parent ab8a95b7a5
commit 3803968b7c
13 changed files with 178 additions and 195 deletions

View File

@@ -16,10 +16,10 @@ bevy_oxr.path = "../.."
bevy = "0.12" bevy = "0.12"
openxr = { git = "https://github.com/Ralith/openxrs", rev = "0177d2d", features = ["mint"] } openxr = { git = "https://github.com/Ralith/openxrs", rev = "0177d2d", features = ["mint"] }
[profile.release] # [profile.release]
lto = "fat" # lto = "fat"
codegen-units = 1 # codegen-units = 1
panic = "abort" # panic = "abort"
# This metadata is used by `cargo-apk` - `xbuild` uses the `manifest.yaml` instead. # This metadata is used by `cargo-apk` - `xbuild` uses the `manifest.yaml` instead.
[package.metadata.android] [package.metadata.android]

View File

@@ -3,10 +3,10 @@ use bevy::prelude::*;
use bevy::transform::components::Transform; use bevy::transform::components::Transform;
use bevy_oxr::graphics::extensions::XrExtensions; use bevy_oxr::graphics::extensions::XrExtensions;
use bevy_oxr::graphics::XrAppInfo; use bevy_oxr::graphics::XrAppInfo;
use bevy_oxr::graphics::XrPreferdBlendMode::AlphaBlend; use bevy_oxr::passthrough::{PausePassthrough, ResumePassthrough, XrPassthroughState};
use bevy_oxr::passthrough::{passthrough_layer_pause, passthrough_layer_resume}; use bevy_oxr::xr_init::xr_only;
use bevy_oxr::xr_init::XrRenderData;
use bevy_oxr::xr_input::debug_gizmos::OpenXrDebugRenderer; use bevy_oxr::xr_input::debug_gizmos::OpenXrDebugRenderer;
use bevy_oxr::xr_input::hands::HandBone;
use bevy_oxr::xr_input::prototype_locomotion::{proto_locomotion, PrototypeLocomotionConfig}; use bevy_oxr::xr_input::prototype_locomotion::{proto_locomotion, PrototypeLocomotionConfig};
use bevy_oxr::xr_input::trackers::{ use bevy_oxr::xr_input::trackers::{
OpenXRController, OpenXRLeftController, OpenXRRightController, OpenXRTracker, OpenXRController, OpenXRLeftController, OpenXRRightController, OpenXRTracker,
@@ -25,16 +25,23 @@ fn main() {
}, },
prefered_blend_mode: bevy_oxr::graphics::XrPreferdBlendMode::Opaque, prefered_blend_mode: bevy_oxr::graphics::XrPreferdBlendMode::Opaque,
}) })
.add_plugins(OpenXrDebugRenderer) // .add_plugins(OpenXrDebugRenderer)
.add_plugins(LogDiagnosticsPlugin::default()) .add_plugins(LogDiagnosticsPlugin::default())
.add_plugins(FrameTimeDiagnosticsPlugin) .add_plugins(FrameTimeDiagnosticsPlugin)
.add_systems(Startup, setup) .add_systems(Startup, setup)
.add_systems(Update, (proto_locomotion, toggle_passthrough)) .add_systems(Update, (proto_locomotion, toggle_passthrough).run_if(xr_only()))
.add_systems(Update, debug_hand_render.run_if(xr_only()))
.add_systems(Startup, spawn_controllers_example) .add_systems(Startup, spawn_controllers_example)
.insert_resource(PrototypeLocomotionConfig::default()) .insert_resource(PrototypeLocomotionConfig::default())
.run(); .run();
} }
fn debug_hand_render(query: Query<&GlobalTransform, With<HandBone>>, mut gizmos: Gizmos) {
for transform in &query {
gizmos.sphere(transform.translation(), Quat::IDENTITY, 0.01, Color::RED);
}
}
/// set up a simple 3D scene /// set up a simple 3D scene
fn setup( fn setup(
mut commands: Commands, mut commands: Commands,
@@ -90,15 +97,18 @@ fn spawn_controllers_example(mut commands: Commands) {
)); ));
} }
// Does this work? Not getting logs // TODO: make this a vr button
fn toggle_passthrough(keys: Res<Input<KeyCode>>, mut xr_data: ResMut<XrRenderData>) { fn toggle_passthrough(
keys: Res<Input<KeyCode>>,
passthrough_state: Res<XrPassthroughState>,
mut resume: EventWriter<ResumePassthrough>,
mut pause: EventWriter<PausePassthrough>,
) {
if keys.just_pressed(KeyCode::Space) { if keys.just_pressed(KeyCode::Space) {
if xr_data.xr_passthrough_active { match *passthrough_state {
passthrough_layer_pause(xr_data); XrPassthroughState::Unsupported => {}
bevy::log::info!("Passthrough paused"); XrPassthroughState::Running => pause.send_default(),
} else { XrPassthroughState::Paused => resume.send_default(),
passthrough_layer_resume(xr_data);
bevy::log::info!("Passthrough resumed");
} }
} }
} }

View File

@@ -23,7 +23,7 @@ use bevy_oxr::{
xr_input::{ xr_input::{
actions::XrActionSets, actions::XrActionSets,
debug_gizmos::OpenXrDebugRenderer, debug_gizmos::OpenXrDebugRenderer,
hands::common::{HandInputDebugRenderer, HandResource, HandsResource, OpenXrHandInput}, hands::common::{HandInputDebugRenderer, HandResource, HandsResource},
hands::HandBone, hands::HandBone,
interactions::{ interactions::{
draw_interaction_gizmos, draw_socket_gizmos, interactions, socket_interactions, draw_interaction_gizmos, draw_socket_gizmos, interactions, socket_interactions,
@@ -120,7 +120,7 @@ pub fn main() {
//test capsule //test capsule
.add_systems(Startup, spawn_capsule) .add_systems(Startup, spawn_capsule)
//physics hands //physics hands
.add_plugins(OpenXrHandInput) // .add_plugins(OpenXrHandInput)
.add_plugins(HandInputDebugRenderer) .add_plugins(HandInputDebugRenderer)
.add_systems(Startup, spawn_physics_hands) .add_systems(Startup, spawn_physics_hands)
.add_systems( .add_systems(

View File

@@ -3,7 +3,7 @@ use bevy::prelude::*;
use bevy::transform::components::Transform; use bevy::transform::components::Transform;
use bevy_oxr::graphics::XrAppInfo; use bevy_oxr::graphics::XrAppInfo;
use bevy_oxr::resources::XrViews; use bevy_oxr::resources::XrViews;
use bevy_oxr::xr_input::hands::common::{HandInputDebugRenderer, OpenXrHandInput}; use bevy_oxr::xr_input::hands::common::HandInputDebugRenderer;
use bevy_oxr::xr_input::interactions::{ use bevy_oxr::xr_input::interactions::{
InteractionEvent, XRDirectInteractor, XRInteractorState, XRRayInteractor, XRSocketInteractor, InteractionEvent, XRDirectInteractor, XRInteractorState, XRRayInteractor, XRSocketInteractor,
}; };
@@ -31,7 +31,6 @@ fn main() {
.add_systems(Update, (proto_locomotion, pull_to_ground).chain()) .add_systems(Update, (proto_locomotion, pull_to_ground).chain())
.insert_resource(PrototypeLocomotionConfig::default()) .insert_resource(PrototypeLocomotionConfig::default())
.add_systems(Startup, spawn_controllers_example) .add_systems(Startup, spawn_controllers_example)
.add_plugins(OpenXrHandInput)
.add_plugins(HandInputDebugRenderer) .add_plugins(HandInputDebugRenderer)
.add_event::<InteractionEvent>() .add_event::<InteractionEvent>()
.run(); .run();

View File

@@ -7,7 +7,7 @@ use bevy_oxr::input::XrInput;
use bevy_oxr::resources::{XrFrameState, XrSession}; use bevy_oxr::resources::{XrFrameState, XrSession};
use bevy_oxr::xr_input::actions::XrActionSets; use bevy_oxr::xr_input::actions::XrActionSets;
use bevy_oxr::xr_input::hands::common::{HandInputDebugRenderer, OpenXrHandInput}; use bevy_oxr::xr_input::hands::common::HandInputDebugRenderer;
use bevy_oxr::xr_input::interactions::{ use bevy_oxr::xr_input::interactions::{
draw_interaction_gizmos, draw_socket_gizmos, interactions, socket_interactions, draw_interaction_gizmos, draw_socket_gizmos, interactions, socket_interactions,
update_interactable_states, InteractionEvent, Touched, XRDirectInteractor, XRInteractable, update_interactable_states, InteractionEvent, Touched, XRDirectInteractor, XRInteractable,
@@ -39,7 +39,6 @@ fn main() {
.add_systems(Update, proto_locomotion) .add_systems(Update, proto_locomotion)
.insert_resource(PrototypeLocomotionConfig::default()) .insert_resource(PrototypeLocomotionConfig::default())
.add_systems(Startup, spawn_controllers_example) .add_systems(Startup, spawn_controllers_example)
.add_plugins(OpenXrHandInput)
.add_plugins(HandInputDebugRenderer) .add_plugins(HandInputDebugRenderer)
.add_systems( .add_systems(
Update, Update,

View File

@@ -31,11 +31,13 @@ use openxr as xr;
use passthrough::{PassthroughPlugin, XrPassthroughLayer, XrPassthroughState}; use passthrough::{PassthroughPlugin, XrPassthroughLayer, XrPassthroughState};
use resources::*; use resources::*;
use xr_init::{ use xr_init::{
xr_after_wait_only, xr_only, xr_render_only, CleanupXrData, XrEarlyInitPlugin, XrHasWaited, xr_after_wait_only, xr_only, xr_render_only, CleanupXrData, SetupXrData, XrEarlyInitPlugin,
XrShouldRender, XrStatus, XrHasWaited, XrShouldRender, XrStatus,
}; };
use xr_input::controllers::XrControllerType; use xr_input::controllers::XrControllerType;
use xr_input::hands::XrHandPlugins; use xr_input::hands::emulated::HandEmulationPlugin;
use xr_input::hands::hand_tracking::HandTrackingPlugin;
use xr_input::hands::HandPlugin;
use xr_input::OpenXrInput; use xr_input::OpenXrInput;
const VIEW_TYPE: xr::ViewConfigurationType = xr::ViewConfigurationType::PRIMARY_STEREO; const VIEW_TYPE: xr::ViewConfigurationType = xr::ViewConfigurationType::PRIMARY_STEREO;
@@ -51,11 +53,6 @@ pub struct OpenXrPlugin {
app_info: XrAppInfo, app_info: XrAppInfo,
} }
fn mr_test(mut commands: Commands, mut resume: EventWriter<ResumePassthrough>) {
commands.insert_resource(ClearColor(Color::rgba(0.0, 0.0, 0.0, 0.0)));
resume.send_default();
}
impl Plugin for OpenXrPlugin { impl Plugin for OpenXrPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.insert_resource(XrSessionRunning::new(AtomicBool::new(false))); app.insert_resource(XrSessionRunning::new(AtomicBool::new(false)));
@@ -114,7 +111,6 @@ impl Plugin for OpenXrPlugin {
app.add_plugins(RenderPlugin::default()); app.add_plugins(RenderPlugin::default());
app.insert_resource(XrStatus::Disabled); app.insert_resource(XrStatus::Disabled);
} }
app.add_systems(Update, mr_test.run_if(xr_only()));
app.add_systems( app.add_systems(
PreUpdate, PreUpdate,
xr_poll_events.run_if(|status: Res<XrStatus>| *status != XrStatus::NoInstance), xr_poll_events.run_if(|status: Res<XrStatus>| *status != XrStatus::NoInstance),
@@ -146,8 +142,6 @@ impl Plugin for OpenXrPlugin {
.run_if(xr_only()) .run_if(xr_only())
.run_if(xr_after_wait_only()) .run_if(xr_after_wait_only())
.run_if(xr_render_only()) .run_if(xr_render_only())
// Do NOT touch this ordering! idk why but you can NOT just put in a RenderSet
// right before rendering
.before(render_system) .before(render_system)
.after(RenderSet::ExtractCommands), .after(RenderSet::ExtractCommands),
// .in_set(RenderSet::Prepare), // .in_set(RenderSet::Prepare),
@@ -224,7 +218,9 @@ impl PluginGroup for DefaultXrPlugins {
.add_after::<OpenXrPlugin, _>(OpenXrInput::new(XrControllerType::OculusTouch)) .add_after::<OpenXrPlugin, _>(OpenXrInput::new(XrControllerType::OculusTouch))
.add_after::<OpenXrPlugin, _>(XrInitPlugin) .add_after::<OpenXrPlugin, _>(XrInitPlugin)
.add_before::<OpenXrPlugin, _>(XrEarlyInitPlugin) .add_before::<OpenXrPlugin, _>(XrEarlyInitPlugin)
.add(XrHandPlugins) .add(HandPlugin)
.add(HandTrackingPlugin)
.add(HandEmulationPlugin)
.add(PassthroughPlugin) .add(PassthroughPlugin)
.add(XrResourcePlugin) .add(XrResourcePlugin)
.set(WindowPlugin { .set(WindowPlugin {
@@ -259,6 +255,7 @@ fn xr_poll_events(
session: Option<Res<XrSession>>, session: Option<Res<XrSession>>,
session_running: Res<XrSessionRunning>, session_running: Res<XrSessionRunning>,
mut app_exit: EventWriter<AppExit>, mut app_exit: EventWriter<AppExit>,
mut setup_xr: EventWriter<SetupXrData>,
mut cleanup_xr: EventWriter<CleanupXrData>, mut cleanup_xr: EventWriter<CleanupXrData>,
) { ) {
if let (Some(instance), Some(session)) = (instance, session) { if let (Some(instance), Some(session)) = (instance, session) {
@@ -274,6 +271,7 @@ fn xr_poll_events(
xr::SessionState::READY => { xr::SessionState::READY => {
info!("Calling Session begin :3"); info!("Calling Session begin :3");
session.begin(VIEW_TYPE).unwrap(); session.begin(VIEW_TYPE).unwrap();
setup_xr.send_default();
session_running.store(true, std::sync::atomic::Ordering::Relaxed); session_running.store(true, std::sync::atomic::Ordering::Relaxed);
} }
xr::SessionState::STOPPING => { xr::SessionState::STOPPING => {
@@ -283,7 +281,6 @@ fn xr_poll_events(
} }
xr::SessionState::EXITING | xr::SessionState::LOSS_PENDING => { xr::SessionState::EXITING | xr::SessionState::LOSS_PENDING => {
// app_exit.send(AppExit); // app_exit.send(AppExit);
return;
} }
_ => {} _ => {}

View File

@@ -25,10 +25,11 @@ pub enum XrPassthroughState {
Paused, Paused,
} }
pub struct PassthroughPlugin;
xr_arc_resource_wrapper!(XrPassthrough, xr::Passthrough); xr_arc_resource_wrapper!(XrPassthrough, xr::Passthrough);
xr_arc_resource_wrapper!(XrPassthroughLayer, xr::PassthroughLayer); xr_arc_resource_wrapper!(XrPassthroughLayer, xr::PassthroughLayer);
pub struct PassthroughPlugin;
impl Plugin for PassthroughPlugin { impl Plugin for PassthroughPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_event::<ResumePassthrough>(); app.add_event::<ResumePassthrough>();
@@ -78,20 +79,31 @@ fn check_passthrough_support(mut cmds: Commands, instance: Option<Res<XrInstance
} }
} }
fn resume_passthrough(layer: Res<XrPassthroughLayer>, mut state: ResMut<XrPassthroughState>) { fn resume_passthrough(
layer: Res<XrPassthroughLayer>,
mut state: ResMut<XrPassthroughState>,
mut clear_color: ResMut<ClearColor>,
) {
if let Err(e) = layer.resume() { if let Err(e) = layer.resume() {
warn!("Unable to resume Passthrough: {}", e); warn!("Unable to resume Passthrough: {}", e);
return; return;
} }
info!("<=> Resume Passthrough"); clear_color.set_a(0.0);
clear_color.set_r(0.0);
clear_color.set_g(0.0);
clear_color.set_b(0.0);
*state = XrPassthroughState::Running; *state = XrPassthroughState::Running;
} }
fn pause_passthrough(layer: Res<XrPassthroughLayer>, mut state: ResMut<XrPassthroughState>) { fn pause_passthrough(
layer: Res<XrPassthroughLayer>,
mut state: ResMut<XrPassthroughState>,
mut clear_color: ResMut<ClearColor>,
) {
if let Err(e) = layer.pause() { if let Err(e) = layer.pause() {
warn!("Unable to resume Passthrough: {}", e); warn!("Unable to resume Passthrough: {}", e);
return; return;
} }
info!("<=> Pausing Passthrough"); clear_color.set_a(1.0);
*state = XrPassthroughState::Paused; *state = XrPassthroughState::Paused;
} }
@@ -100,8 +112,8 @@ fn cleanup_passthrough(mut cmds: Commands) {
cmds.remove_resource::<XrPassthroughLayer>(); cmds.remove_resource::<XrPassthroughLayer>();
} }
fn setup_passthrough(mut cmds: Commands, instance: Res<XrInstance>, session: Res<XrSession>) { fn setup_passthrough(mut cmds: Commands, session: Res<XrSession>) {
match create_passthrough(&instance, &session) { match create_passthrough(&session) {
Ok((passthrough, layer)) => { Ok((passthrough, layer)) => {
cmds.insert_resource(XrPassthrough::from(passthrough)); cmds.insert_resource(XrPassthrough::from(passthrough));
cmds.insert_resource(XrPassthroughLayer::from(layer)); cmds.insert_resource(XrPassthroughLayer::from(layer));
@@ -181,7 +193,6 @@ pub fn supports_passthrough(instance: &XrInstance, system: xr::SystemId) -> xr::
#[inline] #[inline]
pub fn create_passthrough( pub fn create_passthrough(
instance: &XrInstance,
xr_session: &XrSession, xr_session: &XrSession,
) -> xr::Result<(xr::Passthrough, xr::PassthroughLayer)> { ) -> xr::Result<(xr::Passthrough, xr::PassthroughLayer)> {
let passthrough = match xr_session { let passthrough = match xr_session {
@@ -199,28 +210,14 @@ pub fn create_passthrough(
Ok((passthrough, passthrough_layer)) Ok((passthrough, passthrough_layer))
} }
// #[inline] /// Enable Passthrough on xr startup
// pub fn passthrough_layer_resume(mut layer: ResMut<XrPassthroughLayer>, mut passthrough: ResMut<XrPassthrough>) -> xr::Result<()> { /// just sends the [`ResumePassthrough`] event in [`XrSetup`]
// layer.resume() pub struct EnablePassthroughStartup;
// }
// #[inline] impl Plugin for EnablePassthroughStartup {
// pub fn passthrough_layer_pause(mut xr_data_resource: ResMut<XrRenderData>) -> xr::Result<()> { fn build(&self, app: &mut App) {
// unsafe { app.add_systems(XrSetup, |mut e: EventWriter<ResumePassthrough>| {
// let passthrough_layer = &xr_data_resource.xr_passthrough_layer; e.send_default();
// { });
// let passthrough_layer_locked = passthrough_layer.lock().unwrap(); }
// cvt((xr_data_resource }
// .xr_instance
// .exts()
// .fb_passthrough
// .unwrap()
// .passthrough_layer_pause)(
// *passthrough_layer_locked
// ))?;
// }
// xr_data_resource.xr_passthrough_active = false;
// bevy::log::info!("Paused passthrough layer");
// Ok(())
// }
// }

View File

@@ -126,7 +126,7 @@ pub struct StartXrSession;
pub struct EndXrSession; pub struct EndXrSession;
#[derive(Event, Clone, Copy, Default)] #[derive(Event, Clone, Copy, Default)]
struct SetupXrData; pub(crate) struct SetupXrData;
#[derive(Event, Clone, Copy, Default)] #[derive(Event, Clone, Copy, Default)]
pub(crate) struct CleanupXrData; pub(crate) struct CleanupXrData;
@@ -192,7 +192,6 @@ fn start_xr_session(
commands.insert_resource(xr_views); commands.insert_resource(xr_views);
commands.insert_resource(xr_frame_state); commands.insert_resource(xr_frame_state);
*status = XrStatus::Enabling; *status = XrStatus::Enabling;
setup_xr.send_default();
} }
fn stop_xr_session(session: ResMut<XrSession>, mut status: ResMut<XrStatus>) { fn stop_xr_session(session: ResMut<XrSession>, mut status: ResMut<XrStatus>) {

View File

@@ -6,7 +6,7 @@ use xr::{Action, Binding, Haptic, Posef, Vector2f};
use crate::{ use crate::{
resources::{XrInstance, XrSession}, resources::{XrInstance, XrSession},
xr_init::XrPrePostSetup, xr_init::{XrCleanup, XrPrePostSetup, XrPreSetup},
}; };
use super::oculus_touch::ActionSets; use super::oculus_touch::ActionSets;
@@ -16,11 +16,21 @@ pub use xr::sys::NULL_PATH;
pub struct OpenXrActionsPlugin; pub struct OpenXrActionsPlugin;
impl Plugin for OpenXrActionsPlugin { impl Plugin for OpenXrActionsPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.insert_resource(SetupActionSets { app.add_systems(XrPreSetup, insert_setup_action_sets);
app.add_systems(XrPrePostSetup, setup_oxr_actions);
app.add_systems(XrCleanup, clean_actions);
}
}
fn insert_setup_action_sets(mut cmds: Commands) {
cmds.insert_resource(SetupActionSets {
sets: HashMap::new(), sets: HashMap::new(),
}); });
app.add_systems(XrPrePostSetup, setup_oxr_actions);
} }
fn clean_actions(mut cmds: Commands) {
cmds.remove_resource::<ActionSets>();
cmds.remove_resource::<XrActionSets>();
} }
#[inline(always)] #[inline(always)]

View File

@@ -1,6 +1,10 @@
use bevy::prelude::{ use bevy::{
core::Name,
prelude::{
default, Color, Commands, Component, Deref, DerefMut, Entity, Gizmos, Plugin, PostUpdate, default, Color, Commands, Component, Deref, DerefMut, Entity, Gizmos, Plugin, PostUpdate,
Query, Resource, SpatialBundle, Startup, Transform, Query, Resource, SpatialBundle, Startup, Transform,
},
transform::components::GlobalTransform,
}; };
use crate::xr_input::{trackers::OpenXRTracker, Hand}; use crate::xr_input::{trackers::OpenXRTracker, Hand};
@@ -8,14 +12,14 @@ use crate::xr_input::{trackers::OpenXRTracker, Hand};
use super::{BoneTrackingStatus, HandBone}; use super::{BoneTrackingStatus, HandBone};
/// add debug renderer for controllers /// add debug renderer for controllers
#[derive(Default)] // #[derive(Default)]
pub struct OpenXrHandInput; // pub struct OpenXrHandInput;
//
impl Plugin for OpenXrHandInput { // impl Plugin for OpenXrHandInput {
fn build(&self, app: &mut bevy::prelude::App) { // fn build(&self, app: &mut bevy::prelude::App) {
app.add_systems(Startup, spawn_hand_entities); // app.add_systems(Startup, spawn_hand_entities);
} // }
} // }
/// add debug renderer for controllers /// add debug renderer for controllers
#[derive(Default)] #[derive(Default)]
@@ -161,75 +165,46 @@ pub fn spawn_hand_entities(mut commands: Commands) {
for bone in bones.iter() { for bone in bones.iter() {
let boneid = commands let boneid = commands
.spawn(( .spawn((
Name::new(format!("{:?} {:?}", hand, bone)),
SpatialBundle::default(), SpatialBundle::default(),
bone.clone(), *bone,
OpenXRTracker, OpenXRTracker,
hand.clone(), *hand,
BoneTrackingStatus::Emulated, BoneTrackingStatus::Emulated,
HandBoneRadius(0.1), HandBoneRadius(0.1),
)) ))
.id(); .id();
match hand { let hand_res = match hand {
Hand::Left => match bone { Hand::Left => &mut hand_resource.left,
HandBone::Palm => hand_resource.left.palm = boneid, Hand::Right => &mut hand_resource.right,
HandBone::Wrist => hand_resource.left.wrist = boneid, };
HandBone::ThumbMetacarpal => hand_resource.left.thumb.metacarpal = boneid, match bone {
HandBone::ThumbProximal => hand_resource.left.thumb.proximal = boneid, HandBone::Palm => hand_res.palm = boneid,
HandBone::ThumbDistal => hand_resource.left.thumb.distal = boneid, HandBone::Wrist => hand_res.wrist = boneid,
HandBone::ThumbTip => hand_resource.left.thumb.tip = boneid, HandBone::ThumbMetacarpal => hand_res.thumb.metacarpal = boneid,
HandBone::IndexMetacarpal => hand_resource.left.index.metacarpal = boneid, HandBone::ThumbProximal => hand_res.thumb.proximal = boneid,
HandBone::IndexProximal => hand_resource.left.index.proximal = boneid, HandBone::ThumbDistal => hand_res.thumb.distal = boneid,
HandBone::IndexIntermediate => hand_resource.left.index.intermediate = boneid, HandBone::ThumbTip => hand_res.thumb.tip = boneid,
HandBone::IndexDistal => hand_resource.left.index.distal = boneid, HandBone::IndexMetacarpal => hand_res.index.metacarpal = boneid,
HandBone::IndexTip => hand_resource.left.index.tip = boneid, HandBone::IndexProximal => hand_res.index.proximal = boneid,
HandBone::MiddleMetacarpal => hand_resource.left.middle.metacarpal = boneid, HandBone::IndexIntermediate => hand_res.index.intermediate = boneid,
HandBone::MiddleProximal => hand_resource.left.middle.proximal = boneid, HandBone::IndexDistal => hand_res.index.distal = boneid,
HandBone::MiddleIntermediate => hand_resource.left.middle.intermediate = boneid, HandBone::IndexTip => hand_res.index.tip = boneid,
HandBone::MiddleDistal => hand_resource.left.middle.distal = boneid, HandBone::MiddleMetacarpal => hand_res.middle.metacarpal = boneid,
HandBone::MiddleTip => hand_resource.left.middle.tip = boneid, HandBone::MiddleProximal => hand_res.middle.proximal = boneid,
HandBone::RingMetacarpal => hand_resource.left.ring.metacarpal = boneid, HandBone::MiddleIntermediate => hand_res.middle.intermediate = boneid,
HandBone::RingProximal => hand_resource.left.ring.proximal = boneid, HandBone::MiddleDistal => hand_res.middle.distal = boneid,
HandBone::RingIntermediate => hand_resource.left.ring.intermediate = boneid, HandBone::MiddleTip => hand_res.middle.tip = boneid,
HandBone::RingDistal => hand_resource.left.ring.distal = boneid, HandBone::RingMetacarpal => hand_res.ring.metacarpal = boneid,
HandBone::RingTip => hand_resource.left.ring.tip = boneid, HandBone::RingProximal => hand_res.ring.proximal = boneid,
HandBone::LittleMetacarpal => hand_resource.left.little.metacarpal = boneid, HandBone::RingIntermediate => hand_res.ring.intermediate = boneid,
HandBone::LittleProximal => hand_resource.left.little.proximal = boneid, HandBone::RingDistal => hand_res.ring.distal = boneid,
HandBone::LittleIntermediate => hand_resource.left.little.intermediate = boneid, HandBone::RingTip => hand_res.ring.tip = boneid,
HandBone::LittleDistal => hand_resource.left.little.distal = boneid, HandBone::LittleMetacarpal => hand_res.little.metacarpal = boneid,
HandBone::LittleTip => hand_resource.left.little.tip = boneid, HandBone::LittleProximal => hand_res.little.proximal = boneid,
}, HandBone::LittleIntermediate => hand_res.little.intermediate = boneid,
Hand::Right => match bone { HandBone::LittleDistal => hand_res.little.distal = boneid,
HandBone::Palm => hand_resource.right.palm = boneid, HandBone::LittleTip => hand_res.little.tip = boneid,
HandBone::Wrist => hand_resource.right.wrist = boneid,
HandBone::ThumbMetacarpal => hand_resource.right.thumb.metacarpal = boneid,
HandBone::ThumbProximal => hand_resource.right.thumb.proximal = boneid,
HandBone::ThumbDistal => hand_resource.right.thumb.distal = boneid,
HandBone::ThumbTip => hand_resource.right.thumb.tip = boneid,
HandBone::IndexMetacarpal => hand_resource.right.index.metacarpal = boneid,
HandBone::IndexProximal => hand_resource.right.index.proximal = boneid,
HandBone::IndexIntermediate => hand_resource.right.index.intermediate = boneid,
HandBone::IndexDistal => hand_resource.right.index.distal = boneid,
HandBone::IndexTip => hand_resource.right.index.tip = boneid,
HandBone::MiddleMetacarpal => hand_resource.right.middle.metacarpal = boneid,
HandBone::MiddleProximal => hand_resource.right.middle.proximal = boneid,
HandBone::MiddleIntermediate => {
hand_resource.right.middle.intermediate = boneid
}
HandBone::MiddleDistal => hand_resource.right.middle.distal = boneid,
HandBone::MiddleTip => hand_resource.right.middle.tip = boneid,
HandBone::RingMetacarpal => hand_resource.right.ring.metacarpal = boneid,
HandBone::RingProximal => hand_resource.right.ring.proximal = boneid,
HandBone::RingIntermediate => hand_resource.right.ring.intermediate = boneid,
HandBone::RingDistal => hand_resource.right.ring.distal = boneid,
HandBone::RingTip => hand_resource.right.ring.tip = boneid,
HandBone::LittleMetacarpal => hand_resource.right.little.metacarpal = boneid,
HandBone::LittleProximal => hand_resource.right.little.proximal = boneid,
HandBone::LittleIntermediate => {
hand_resource.right.little.intermediate = boneid
}
HandBone::LittleDistal => hand_resource.right.little.distal = boneid,
HandBone::LittleTip => hand_resource.right.little.tip = boneid,
},
} }
} }
} }
@@ -241,16 +216,12 @@ pub struct HandBoneRadius(pub f32);
pub fn draw_hand_entities( pub fn draw_hand_entities(
mut gizmos: Gizmos, mut gizmos: Gizmos,
query: Query<(&Transform, &HandBone, &HandBoneRadius)>, query: Query<(&GlobalTransform, &HandBone, &HandBoneRadius)>,
) { ) {
for (transform, hand_bone, hand_bone_radius) in query.iter() { for (transform, hand_bone, hand_bone_radius) in query.iter() {
let (_, color) = get_bone_gizmo_style(hand_bone); let (_, color) = get_bone_gizmo_style(hand_bone);
gizmos.sphere( let (_, rotation, translation) = transform.to_scale_rotation_translation();
transform.translation, gizmos.sphere(translation, rotation, hand_bone_radius.0, color);
transform.rotation,
hand_bone_radius.0,
color,
);
} }
} }

View File

@@ -92,8 +92,6 @@ fn setup_hand_emulation_action_set(mut action_sets: ResMut<SetupActionSets>) {
suggest_oculus_touch_profile(action_set); suggest_oculus_touch_profile(action_set);
} }
pub struct EmulatedHandPoseData {}
fn suggest_oculus_touch_profile(action_set: &mut SetupActionSet) { fn suggest_oculus_touch_profile(action_set: &mut SetupActionSet) {
action_set.suggest_binding( action_set.suggest_binding(
"/interaction_profiles/oculus/touch_controller", "/interaction_profiles/oculus/touch_controller",
@@ -131,7 +129,6 @@ pub(crate) fn update_hand_skeleton_from_emulated(
action_sets: Res<XrActionSets>, action_sets: Res<XrActionSets>,
left_controller_transform: Query<&Transform, With<OpenXRLeftController>>, left_controller_transform: Query<&Transform, With<OpenXRLeftController>>,
right_controller_transform: Query<&Transform, With<OpenXRRightController>>, right_controller_transform: Query<&Transform, With<OpenXRRightController>>,
tracking_root_transform: Query<&Transform, With<OpenXRTrackingRoot>>,
mut bones: Query< mut bones: Query<
( (
&mut Transform, &mut Transform,
@@ -226,7 +223,6 @@ pub(crate) fn update_hand_skeleton_from_emulated(
}, },
} }
} }
let trt = tracking_root_transform.single();
for (mut t, bone, hand, status, mut radius) in bones.iter_mut() { for (mut t, bone, hand, status, mut radius) in bones.iter_mut() {
match status { match status {
BoneTrackingStatus::Emulated => {} BoneTrackingStatus::Emulated => {}
@@ -238,9 +234,9 @@ pub(crate) fn update_hand_skeleton_from_emulated(
Hand::Left => 0, Hand::Left => 0,
Hand::Right => 1, Hand::Right => 1,
}][bone.get_index_from_bone()]; }][bone.get_index_from_bone()];
*t = t.with_scale(trt.scale); // *t = t.with_scale(trt.scale);
*t = t.with_rotation(trt.rotation * t.rotation); // *t = t.with_rotation(trt.rotation * t.rotation);
*t = t.with_translation(trt.transform_point(t.translation)); // *t = t.with_translation(trt.transform_point(t.translation));
} }
} }
pub fn update_hand_bones_emulated( pub fn update_hand_bones_emulated(

View File

@@ -6,7 +6,7 @@ use crate::{
input::XrInput, input::XrInput,
resources::{XrFrameState, XrSession}, resources::{XrFrameState, XrSession},
xr_init::xr_only, xr_init::xr_only,
xr_input::{hands::HandBone, trackers::OpenXRTrackingRoot, Hand, QuatConv, Vec3Conv}, xr_input::{hands::HandBone, Hand, QuatConv, Vec3Conv},
}; };
use super::BoneTrackingStatus; use super::BoneTrackingStatus;
@@ -158,7 +158,6 @@ pub fn update_hand_bones(
hand_tracking: Option<Res<HandTrackingData>>, hand_tracking: Option<Res<HandTrackingData>>,
xr_input: Res<XrInput>, xr_input: Res<XrInput>,
xr_frame_state: Res<XrFrameState>, xr_frame_state: Res<XrFrameState>,
root_query: Query<(&Transform, With<OpenXRTrackingRoot>, Without<HandBone>)>,
mut bones: Query<( mut bones: Query<(
&mut Transform, &mut Transform,
&Hand, &Hand,
@@ -174,7 +173,6 @@ pub fn update_hand_bones(
return; return;
} }
}; };
let (root_transform, _, _) = root_query.get_single().unwrap();
let left_hand_data = hand_ref.get_poses(Hand::Left); let left_hand_data = hand_ref.get_poses(Hand::Left);
let right_hand_data = hand_ref.get_poses(Hand::Right); let right_hand_data = hand_ref.get_poses(Hand::Right);
bones bones
@@ -203,8 +201,7 @@ pub fn update_hand_bones(
*status = BoneTrackingStatus::Tracked; *status = BoneTrackingStatus::Tracked;
} }
radius.0 = bone_data.radius; radius.0 = bone_data.radius;
*transform = transform transform.translation = bone_data.position;
.with_translation(root_transform.transform_point(bone_data.position)) transform.rotation = bone_data.orientation;
.with_rotation(root_transform.rotation * bone_data.orientation)
}); });
} }

View File

@@ -1,38 +1,50 @@
use bevy::{app::PluginGroupBuilder, prelude::*}; use bevy::prelude::*;
use openxr::FormFactor; use openxr::FormFactor;
use crate::{ use crate::{
resources::{XrInstance, XrSession}, resources::{XrInstance, XrSession},
xr_init::XrPreSetup, xr_init::{XrCleanup, XrPreSetup, XrSetup},
}; };
use self::{ use self::{
emulated::HandEmulationPlugin, common::{spawn_hand_entities, HandBoneRadius, HandsResource},
hand_tracking::{DisableHandTracking, HandTrackingData, HandTrackingPlugin}, hand_tracking::{DisableHandTracking, HandTrackingData},
}; };
use super::{trackers::OpenXRTracker, Hand};
pub mod common; pub mod common;
pub mod emulated; pub mod emulated;
pub mod hand_tracking; pub mod hand_tracking;
pub struct XrHandPlugins;
impl Plugin for XrHandPlugins {
fn build(&self, app: &mut App) {
app.add_plugins(HandTrackingPlugin)
.add_plugins(HandPlugin)
.add_plugins(HandEmulationPlugin);
}
}
pub struct HandPlugin; pub struct HandPlugin;
impl Plugin for HandPlugin { impl Plugin for HandPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_systems(XrPreSetup, check_for_handtracking); app.add_systems(XrPreSetup, check_for_handtracking);
app.add_systems(XrSetup, spawn_hand_entities);
app.add_systems(XrCleanup, despawn_hand_entities);
} }
} }
#[allow(clippy::type_complexity)]
fn despawn_hand_entities(
mut commands: Commands,
hand_entities: Query<
Entity,
(
With<OpenXRTracker>,
With<HandBone>,
With<BoneTrackingStatus>,
),
>,
) {
for e in &hand_entities {
commands.entity(e).despawn_recursive();
}
commands.remove_resource::<HandsResource>()
}
fn check_for_handtracking( fn check_for_handtracking(
mut commands: Commands, mut commands: Commands,
instance: Res<XrInstance>, instance: Res<XrInstance>,
@@ -86,21 +98,17 @@ pub enum HandBone {
} }
impl HandBone { impl HandBone {
pub fn is_finger(&self) -> bool { pub fn is_finger(&self) -> bool {
match &self { !matches!(self, HandBone::Wrist | HandBone::Palm)
HandBone::Wrist => false,
HandBone::Palm => false,
_ => true,
}
} }
pub fn is_metacarpal(&self) -> bool { pub fn is_metacarpal(&self) -> bool {
match &self { matches!(
HandBone::ThumbMetacarpal => true, self,
HandBone::IndexMetacarpal => true, HandBone::ThumbMetacarpal
HandBone::MiddleMetacarpal => true, | HandBone::IndexMetacarpal
HandBone::RingMetacarpal => true, | HandBone::MiddleMetacarpal
HandBone::LittleTip => true, | HandBone::RingMetacarpal
_ => false, | HandBone::LittleTip
} )
} }
pub const fn get_all_bones() -> [HandBone; 26] { pub const fn get_all_bones() -> [HandBone; 26] {
[ [