From 6b03a59b77c663661c727a2becb2cefa2d822f39 Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Thu, 21 Sep 2023 13:14:59 -0400 Subject: [PATCH 01/11] pinned to working version for now --- Cargo.toml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 84e1f11..58c5101 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,9 @@ linked = ["openxr/linked", "openxr/static"] [dependencies] anyhow = "1.0.75" ash = "0.37.3" -bevy = { git = "https://github.com/awtterpip/bevy", default-features = false, features = ["bevy_render"] } +bevy = { git = "https://github.com/awtterpip/bevy", default-features = false, features = [ + "bevy_render", +], rev = "ac28b11797c0a85b431ee4940c6afa434f712f7a" } openxr = { version = "0.17.1", features = ["mint"] } mint = "0.5.9" wgpu = "0.16.0" @@ -18,7 +20,7 @@ wgpu-core = { version = "0.16.0", features = ["vulkan"] } wgpu-hal = "0.16.0" [dev-dependencies] -bevy = { git = "https://github.com/awtterpip/bevy" } +bevy = { git = "https://github.com/awtterpip/bevy", rev = "ac28b11797c0a85b431ee4940c6afa434f712f7a" } color-eyre = "0.6.2" [[example]] @@ -26,4 +28,4 @@ name = "xr" path = "examples/xr.rs" [profile.release] -debug = true \ No newline at end of file +debug = true From 23ed65f06a5bb35ba115c1604ffd64f57b609dc9 Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Sun, 24 Sep 2023 23:15:24 -0400 Subject: [PATCH 02/11] added initial interactions --- Cargo.toml | 4 +- examples/xr.rs | 69 ++++++++++++++++++++ src/xr_input/interactions.rs | 123 +++++++++++++++++++++++++++++++++++ src/xr_input/mod.rs | 1 + 4 files changed, 195 insertions(+), 2 deletions(-) create mode 100644 src/xr_input/interactions.rs diff --git a/Cargo.toml b/Cargo.toml index 58c5101..578d584 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ anyhow = "1.0.75" ash = "0.37.3" bevy = { git = "https://github.com/awtterpip/bevy", default-features = false, features = [ "bevy_render", -], rev = "ac28b11797c0a85b431ee4940c6afa434f712f7a" } +] } openxr = { version = "0.17.1", features = ["mint"] } mint = "0.5.9" wgpu = "0.16.0" @@ -20,7 +20,7 @@ wgpu-core = { version = "0.16.0", features = ["vulkan"] } wgpu-hal = "0.16.0" [dev-dependencies] -bevy = { git = "https://github.com/awtterpip/bevy", rev = "ac28b11797c0a85b431ee4940c6afa434f712f7a" } +bevy = { git = "https://github.com/awtterpip/bevy" } color-eyre = "0.6.2" [[example]] diff --git a/examples/xr.rs b/examples/xr.rs index 548fe15..36e835c 100644 --- a/examples/xr.rs +++ b/examples/xr.rs @@ -1,11 +1,19 @@ use bevy::diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}; use bevy::prelude::*; use bevy::transform::components::Transform; +use bevy_openxr::input::XrInput; +use bevy_openxr::resources::{XrFrameState, XrInstance, XrSession}; use bevy_openxr::xr_input::debug_gizmos::OpenXrDebugRenderer; +use bevy_openxr::xr_input::interactions::{ + draw_interaction_gizmos, hover_interaction, XRDirectInteractor, XRInteractable, + XRInteractableState, XRInteractorState, +}; +use bevy_openxr::xr_input::oculus_touch::OculusController; use bevy_openxr::xr_input::prototype_locomotion::{proto_locomotion, PrototypeLocomotionConfig}; use bevy_openxr::xr_input::trackers::{ OpenXRController, OpenXRLeftController, OpenXRRightController, OpenXRTracker, }; +use bevy_openxr::xr_input::Hand; use bevy_openxr::DefaultXrPlugins; fn main() { @@ -21,6 +29,9 @@ fn main() { .add_systems(Update, proto_locomotion) .add_systems(Startup, spawn_controllers_example) .insert_resource(PrototypeLocomotionConfig::default()) + .add_systems(Update, draw_interaction_gizmos) + .add_systems(Update, hover_interaction) + .add_systems(Update, prototype_interaction_input) .run(); } @@ -65,6 +76,15 @@ fn setup( transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), ..default() },)); + //simple interactable + commands.spawn(( + SpatialBundle { + transform: Transform::from_xyz(0.0, 1.0, 0.0), + ..default() + }, + XRInteractable, + XRInteractableState::default(), + )); } fn spawn_controllers_example(mut commands: Commands) { @@ -74,6 +94,8 @@ fn spawn_controllers_example(mut commands: Commands) { OpenXRController, OpenXRTracker, SpatialBundle::default(), + XRDirectInteractor, + XRInteractorState::default(), )); //right hand commands.spawn(( @@ -81,5 +103,52 @@ fn spawn_controllers_example(mut commands: Commands) { OpenXRController, OpenXRTracker, SpatialBundle::default(), + XRDirectInteractor, + XRInteractorState::default(), )); } + +fn prototype_interaction_input( + oculus_controller: Res, + frame_state: Res, + xr_input: Res, + instance: Res, + session: Res, + mut right_interactor_query: Query< + (&mut XRInteractorState), + ( + With, + With, + Without, + ), + >, + mut left_interactor_query: Query< + (&mut XRInteractorState), + ( + With, + With, + Without, + ), + >, +) { + //lock frame + let frame_state = *frame_state.lock().unwrap(); + //get controller + let controller = oculus_controller.get_ref(&instance, &session, &frame_state, &xr_input); + //get controller triggers + let left_trigger = controller.trigger(Hand::Left); + let right_trigger = controller.trigger(Hand::Right); + //get the interactors and do state stuff + let mut left_state = left_interactor_query.single_mut(); + if left_trigger > 0.8 { + *left_state = XRInteractorState::Selecting; + } else { + *left_state = XRInteractorState::Idle; + } + let mut right_state = right_interactor_query.single_mut(); + if right_trigger > 0.8 { + *right_state = XRInteractorState::Selecting; + } else { + *right_state = XRInteractorState::Idle; + } +} diff --git a/src/xr_input/interactions.rs b/src/xr_input/interactions.rs new file mode 100644 index 0000000..ea34112 --- /dev/null +++ b/src/xr_input/interactions.rs @@ -0,0 +1,123 @@ +use std::f32::consts::PI; + +use bevy::prelude::{ + info, Color, Component, Gizmos, GlobalTransform, Quat, Query, Vec3, With, Without, +}; + +#[derive(Component)] +pub struct XRDirectInteractor; +#[derive(Component)] +pub enum XRInteractableState { + Idle, + Hover, + Select, +} + +impl Default for XRInteractableState { + fn default() -> Self { + XRInteractableState::Idle + } +} + +#[derive(Component)] +pub enum XRInteractorState { + Idle, + Selecting, +} +impl Default for XRInteractorState { + fn default() -> Self { + XRInteractorState::Idle + } +} + +#[derive(Component)] +pub struct XRInteractable; + +pub fn draw_interaction_gizmos( + mut gizmos: Gizmos, + interactable_query: Query< + (&GlobalTransform, &XRInteractableState), + (With, Without), + >, + interactor_query: Query< + (&GlobalTransform, &XRInteractorState), + (With, Without), + >, +) { + for (global_transform, interactable_state) in interactable_query.iter() { + let transform = global_transform.compute_transform(); + let color = match interactable_state { + XRInteractableState::Idle => Color::RED, + XRInteractableState::Hover => Color::YELLOW, + XRInteractableState::Select => Color::GREEN, + }; + gizmos.sphere(transform.translation, transform.rotation, 0.1, color); + } + + for (interactor_global_transform, interactor_state) in interactor_query.iter() { + let mut transform = interactor_global_transform.compute_transform(); + transform.scale = Vec3::splat(0.1); + let quat = Quat::from_euler( + bevy::prelude::EulerRot::XYZ, + 45.0 * (PI / 180.0), + 0.0, + 45.0 * (PI / 180.0), + ); + transform.rotation = quat; + let color = match interactor_state { + XRInteractorState::Idle => Color::BLUE, + XRInteractorState::Selecting => Color::PURPLE, + }; + gizmos.cuboid(transform, color); + } +} + +pub fn hover_interaction( + mut interactable_query: Query< + (&GlobalTransform, &mut XRInteractableState), + (With, Without), + >, + interactor_query: Query< + (&GlobalTransform, &XRInteractorState), + (With, Without), + >, +) { + 'interactable: for (xr_interactable_global_transform, mut state) in + interactable_query.iter_mut() + { + let mut hovered = false; + let mut selected = false; + for (interactor_global_transform, interactor_state) in interactor_query.iter() { + //check for sphere overlaps + let size = 0.1; + if interactor_global_transform + .compute_transform() + .translation + .distance_squared( + xr_interactable_global_transform + .compute_transform() + .translation, + ) + < (size * size) * 2.0 + { + info!("we overlapping"); + //check for selections first + match interactor_state { + XRInteractorState::Idle => hovered = true, + XRInteractorState::Selecting => { + selected = true; + } + } + } + } + //check what we found + //also i dont like this + if selected { + *state = XRInteractableState::Select; + } else if hovered { + *state = XRInteractableState::Hover; + } else { + *state = XRInteractableState::Idle; + } + } +} diff --git a/src/xr_input/mod.rs b/src/xr_input/mod.rs index 55e7c56..fe77373 100644 --- a/src/xr_input/mod.rs +++ b/src/xr_input/mod.rs @@ -1,5 +1,6 @@ pub mod controllers; pub mod debug_gizmos; +pub mod interactions; pub mod oculus_touch; pub mod prototype_locomotion; pub mod trackers; From 328c574f9e96d3ff439b0d56886190af6ea63b00 Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Sun, 24 Sep 2023 23:30:50 -0400 Subject: [PATCH 03/11] removed worthless logging, and loop tag --- src/xr_input/interactions.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xr_input/interactions.rs b/src/xr_input/interactions.rs index ea34112..2fa5c35 100644 --- a/src/xr_input/interactions.rs +++ b/src/xr_input/interactions.rs @@ -82,7 +82,7 @@ pub fn hover_interaction( (With, Without), >, ) { - 'interactable: for (xr_interactable_global_transform, mut state) in + for (xr_interactable_global_transform, mut state) in interactable_query.iter_mut() { let mut hovered = false; @@ -100,7 +100,7 @@ pub fn hover_interaction( ) < (size * size) * 2.0 { - info!("we overlapping"); + //check for selections first match interactor_state { XRInteractorState::Idle => hovered = true, From 16bbe283cbccb92c73fd66175c2602c9a3fd80a2 Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Sun, 24 Sep 2023 23:46:57 -0400 Subject: [PATCH 04/11] change default locomotion to head tracked --- src/xr_input/prototype_locomotion.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xr_input/prototype_locomotion.rs b/src/xr_input/prototype_locomotion.rs index 615f9fd..71e708f 100644 --- a/src/xr_input/prototype_locomotion.rs +++ b/src/xr_input/prototype_locomotion.rs @@ -43,7 +43,7 @@ pub struct PrototypeLocomotionConfig { impl Default for PrototypeLocomotionConfig { fn default() -> Self { Self { - locomotion_type: LocomotionType::Hand, + locomotion_type: LocomotionType::Head, locomotion_speed: 1.0, rotation_type: RotationType::Smooth, snap_angle: 45.0 * (PI / 180.0), From e1f19487263004f528c20301fe6235bc19f71a03 Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Wed, 27 Sep 2023 15:40:29 -0400 Subject: [PATCH 05/11] basics of ray interactors --- examples/xr.rs | 11 ++- src/xr_input/interactions.rs | 157 ++++++++++++++++++++++++++++++----- src/xr_input/trackers.rs | 36 ++++++-- 3 files changed, 170 insertions(+), 34 deletions(-) diff --git a/examples/xr.rs b/examples/xr.rs index 36e835c..e8252f4 100644 --- a/examples/xr.rs +++ b/examples/xr.rs @@ -5,13 +5,13 @@ use bevy_openxr::input::XrInput; use bevy_openxr::resources::{XrFrameState, XrInstance, XrSession}; use bevy_openxr::xr_input::debug_gizmos::OpenXrDebugRenderer; use bevy_openxr::xr_input::interactions::{ - draw_interaction_gizmos, hover_interaction, XRDirectInteractor, XRInteractable, - XRInteractableState, XRInteractorState, + draw_interaction_gizmos, direct_interaction, XRDirectInteractor, XRInteractable, + XRInteractableState, XRInteractorState, XRRayInteractor, ray_interaction, }; use bevy_openxr::xr_input::oculus_touch::OculusController; use bevy_openxr::xr_input::prototype_locomotion::{proto_locomotion, PrototypeLocomotionConfig}; use bevy_openxr::xr_input::trackers::{ - OpenXRController, OpenXRLeftController, OpenXRRightController, OpenXRTracker, + OpenXRController, OpenXRLeftController, OpenXRRightController, OpenXRTracker, AimPose, }; use bevy_openxr::xr_input::Hand; use bevy_openxr::DefaultXrPlugins; @@ -30,7 +30,8 @@ fn main() { .add_systems(Startup, spawn_controllers_example) .insert_resource(PrototypeLocomotionConfig::default()) .add_systems(Update, draw_interaction_gizmos) - .add_systems(Update, hover_interaction) + .add_systems(Update, direct_interaction) + .add_systems(Update, ray_interaction) .add_systems(Update, prototype_interaction_input) .run(); } @@ -95,6 +96,8 @@ fn spawn_controllers_example(mut commands: Commands) { OpenXRTracker, SpatialBundle::default(), XRDirectInteractor, + XRRayInteractor, + AimPose(Transform::default()), XRInteractorState::default(), )); //right hand diff --git a/src/xr_input/interactions.rs b/src/xr_input/interactions.rs index 2fa5c35..a36d832 100644 --- a/src/xr_input/interactions.rs +++ b/src/xr_input/interactions.rs @@ -1,11 +1,17 @@ use std::f32::consts::PI; use bevy::prelude::{ - info, Color, Component, Gizmos, GlobalTransform, Quat, Query, Vec3, With, Without, + info, Color, Component, Gizmos, GlobalTransform, Quat, Query, Transform, Vec3, With, Without, }; +use super::trackers::{AimPose, OpenXRTrackingRoot}; + #[derive(Component)] pub struct XRDirectInteractor; + +#[derive(Component)] +pub struct XRRayInteractor; + #[derive(Component)] pub enum XRInteractableState { Idle, @@ -40,10 +46,18 @@ pub fn draw_interaction_gizmos( (With, Without), >, interactor_query: Query< - (&GlobalTransform, &XRInteractorState), - (With, Without), + ( + &GlobalTransform, + &XRInteractorState, + Option<&XRDirectInteractor>, + Option<&XRRayInteractor>, + Option<&AimPose>, + ), + (Without), >, + tracking_root_query: Query<(&mut Transform, With)>, ) { + let root = tracking_root_query.get_single().unwrap().0; for (global_transform, interactable_state) in interactable_query.iter() { let transform = global_transform.compute_transform(); let color = match interactable_state { @@ -54,25 +68,49 @@ pub fn draw_interaction_gizmos( gizmos.sphere(transform.translation, transform.rotation, 0.1, color); } - for (interactor_global_transform, interactor_state) in interactor_query.iter() { - let mut transform = interactor_global_transform.compute_transform(); - transform.scale = Vec3::splat(0.1); - let quat = Quat::from_euler( - bevy::prelude::EulerRot::XYZ, - 45.0 * (PI / 180.0), - 0.0, - 45.0 * (PI / 180.0), - ); - transform.rotation = quat; - let color = match interactor_state { - XRInteractorState::Idle => Color::BLUE, - XRInteractorState::Selecting => Color::PURPLE, - }; - gizmos.cuboid(transform, color); + for (interactor_global_transform, interactor_state, direct, ray, aim) in interactor_query.iter() + { + let transform = interactor_global_transform.compute_transform(); + match direct { + Some(_) => { + let mut local = transform.clone(); + local.scale = Vec3::splat(0.1); + let quat = Quat::from_euler( + bevy::prelude::EulerRot::XYZ, + 45.0 * (PI / 180.0), + 0.0, + 45.0 * (PI / 180.0), + ); + local.rotation = quat; + let color = match interactor_state { + XRInteractorState::Idle => Color::BLUE, + XRInteractorState::Selecting => Color::PURPLE, + }; + gizmos.cuboid(local, color); + } + None => (), + } + match ray { + Some(_) => match aim { + Some(aim) => { + let color = match interactor_state { + XRInteractorState::Idle => Color::BLUE, + XRInteractorState::Selecting => Color::PURPLE, + }; + gizmos.ray( + root.translation + root.rotation.mul_vec3(aim.0.translation), + root.rotation.mul_vec3(aim.0.forward()), + color, + ); + } + None => todo!(), + }, + None => (), + } } } -pub fn hover_interaction( +pub fn direct_interaction( mut interactable_query: Query< (&GlobalTransform, &mut XRInteractableState), (With, Without), @@ -82,9 +120,7 @@ pub fn hover_interaction( (With, Without), >, ) { - for (xr_interactable_global_transform, mut state) in - interactable_query.iter_mut() - { + for (xr_interactable_global_transform, mut state) in interactable_query.iter_mut() { let mut hovered = false; let mut selected = false; for (interactor_global_transform, interactor_state) in interactor_query.iter() { @@ -100,7 +136,6 @@ pub fn hover_interaction( ) < (size * size) * 2.0 { - //check for selections first match interactor_state { XRInteractorState::Idle => hovered = true, @@ -121,3 +156,79 @@ pub fn hover_interaction( } } } + +pub fn ray_interaction( + mut interactable_query: Query< + (&GlobalTransform, &mut XRInteractableState), + (With, Without), + >, + interactor_query: Query< + (&GlobalTransform, &XRInteractorState, Option<&AimPose>), + (With, Without), + >, + tracking_root_query: Query<(&mut Transform, With)>, +) { + for (xr_interactable_global_transform, mut state) in interactable_query.iter_mut() { + let mut hovered = false; + let mut selected = false; + for (interactor_global_transform, interactor_state, aim) in interactor_query.iter() { + //check for ray-sphere intersection + let sphere_transform = xr_interactable_global_transform.compute_transform(); + let center = sphere_transform.translation; + let radius: f32 = 0.1; + //I hate this but the aim pose needs the root for now + let root = tracking_root_query.get_single().unwrap().0; + match aim { + Some(aim) => { + let ray_origin = root.translation + root.rotation.mul_vec3(aim.0.translation); + let ray_dir = root.rotation.mul_vec3(aim.0.forward()); + + if ray_sphere_intersection( + center, + radius, + ray_origin, + ray_dir.normalize_or_zero(), + ) { + //check for selections first + match interactor_state { + XRInteractorState::Idle => hovered = true, + XRInteractorState::Selecting => { + selected = true; + } + } + } + } + None => info!("no aim pose"), + } + } + //check what we found + //also i dont like this + if selected { + *state = XRInteractableState::Select; + } else if hovered { + *state = XRInteractableState::Hover; + } else { + *state = XRInteractableState::Idle; + } + } +} + +fn ray_sphere_intersection(center: Vec3, radius: f32, ray_origin: Vec3, ray_dir: Vec3) -> bool { + let l = center - ray_origin; + let adj = l.dot(ray_dir); + let d2 = l.dot(l) - (adj * adj); + let radius2 = radius * radius; + if d2 > radius2 { + return false; + } + let thc = (radius2 - d2).sqrt(); + let t0 = adj - thc; + let t1 = adj + thc; + + if t0 < 0.0 && t1 < 0.0 { + return false; + } + + // let distance = if t0 < t1 { t0 } else { t1 }; + return true; +} diff --git a/src/xr_input/trackers.rs b/src/xr_input/trackers.rs index f33e6ee..cbd4697 100644 --- a/src/xr_input/trackers.rs +++ b/src/xr_input/trackers.rs @@ -1,8 +1,14 @@ -use bevy::prelude::{Added, BuildChildren, Commands, Entity, Query, With, Res, Transform, Without, Component, info}; +use bevy::prelude::{ + info, Added, BuildChildren, Commands, Component, Entity, Query, Res, Transform, Vec3, With, + Without, +}; -use crate::{resources::{XrFrameState, XrInstance, XrSession}, input::XrInput}; +use crate::{ + input::XrInput, + resources::{XrFrameState, XrInstance, XrSession}, +}; -use super::{oculus_touch::OculusController, Hand, Vec3Conv, QuatConv}; +use super::{oculus_touch::OculusController, Hand, QuatConv, Vec3Conv}; #[derive(Component)] pub struct OpenXRTrackingRoot; @@ -20,6 +26,8 @@ pub struct OpenXRLeftController; pub struct OpenXRRightController; #[derive(Component)] pub struct OpenXRController; +#[derive(Component)] +pub struct AimPose(pub Transform); pub fn adopt_open_xr_trackers( query: Query<(Entity), Added>, @@ -43,11 +51,13 @@ pub fn update_open_xr_controllers( oculus_controller: Res, mut left_controller_query: Query<( &mut Transform, + Option<&mut AimPose>, With, Without, )>, mut right_controller_query: Query<( &mut Transform, + Option<&mut AimPose>, With, Without, )>, @@ -61,8 +71,20 @@ pub fn update_open_xr_controllers( //get controller let controller = oculus_controller.get_ref(&instance, &session, &frame_state, &xr_input); //get left controller - let left = controller.grip_space(Hand::Left); - let left_postion = left.0.pose.position.to_vec3(); + let left_grip_space = controller.grip_space(Hand::Left); + let left_aim_space = controller.aim_space(Hand::Left); + let left_postion = left_grip_space.0.pose.position.to_vec3(); + let aim_pose = left_controller_query.get_single_mut().unwrap().1; + match aim_pose { + Some(mut pose) => { + *pose = AimPose(Transform { + translation: left_aim_space.0.pose.position.to_vec3(), + rotation: left_aim_space.0.pose.orientation.to_quat(), + scale: Vec3::splat(1.0), + }); + } + None => (), + } left_controller_query .get_single_mut() @@ -70,7 +92,8 @@ pub fn update_open_xr_controllers( .0 .translation = left_postion; - left_controller_query.get_single_mut().unwrap().0.rotation = left.0.pose.orientation.to_quat(); + left_controller_query.get_single_mut().unwrap().0.rotation = + left_grip_space.0.pose.orientation.to_quat(); //get right controller let right = controller.grip_space(Hand::Right); let right_postion = right.0.pose.position.to_vec3(); @@ -84,4 +107,3 @@ pub fn update_open_xr_controllers( right_controller_query.get_single_mut().unwrap().0.rotation = right.0.pose.orientation.to_quat(); } - From 6e83b887be28d6f38962d5f13293b580b27ee28b Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Wed, 27 Sep 2023 23:43:03 -0400 Subject: [PATCH 06/11] interactions, and grabbables --- examples/xr.rs | 59 +++++++++-- src/xr_input/interactions.rs | 184 ++++++++++++++++++++--------------- 2 files changed, 157 insertions(+), 86 deletions(-) diff --git a/examples/xr.rs b/examples/xr.rs index e8252f4..68b7b5d 100644 --- a/examples/xr.rs +++ b/examples/xr.rs @@ -5,13 +5,13 @@ use bevy_openxr::input::XrInput; use bevy_openxr::resources::{XrFrameState, XrInstance, XrSession}; use bevy_openxr::xr_input::debug_gizmos::OpenXrDebugRenderer; use bevy_openxr::xr_input::interactions::{ - draw_interaction_gizmos, direct_interaction, XRDirectInteractor, XRInteractable, - XRInteractableState, XRInteractorState, XRRayInteractor, ray_interaction, + interactions, draw_interaction_gizmos, update_interactable_states, InteractionEvent, + XRDirectInteractor, XRInteractable, XRInteractableState, XRInteractorState, XRRayInteractor, }; use bevy_openxr::xr_input::oculus_touch::OculusController; use bevy_openxr::xr_input::prototype_locomotion::{proto_locomotion, PrototypeLocomotionConfig}; use bevy_openxr::xr_input::trackers::{ - OpenXRController, OpenXRLeftController, OpenXRRightController, OpenXRTracker, AimPose, + AimPose, OpenXRController, OpenXRLeftController, OpenXRRightController, OpenXRTracker, }; use bevy_openxr::xr_input::Hand; use bevy_openxr::DefaultXrPlugins; @@ -29,10 +29,15 @@ fn main() { .add_systems(Update, proto_locomotion) .add_systems(Startup, spawn_controllers_example) .insert_resource(PrototypeLocomotionConfig::default()) - .add_systems(Update, draw_interaction_gizmos) - .add_systems(Update, direct_interaction) - .add_systems(Update, ray_interaction) + .add_systems( + Update, + draw_interaction_gizmos.after(update_interactable_states), + ) + .add_systems(Update, interactions) .add_systems(Update, prototype_interaction_input) + .add_systems(Update, update_interactable_states.after(interactions)) + .add_systems(Update, update_grabbables.after(update_interactable_states)) + .add_event::() .run(); } @@ -85,6 +90,7 @@ fn setup( }, XRInteractable, XRInteractableState::default(), + Grabbable, )); } @@ -95,7 +101,6 @@ fn spawn_controllers_example(mut commands: Commands) { OpenXRController, OpenXRTracker, SpatialBundle::default(), - XRDirectInteractor, XRRayInteractor, AimPose(Transform::default()), XRInteractorState::default(), @@ -128,7 +133,7 @@ fn prototype_interaction_input( mut left_interactor_query: Query< (&mut XRInteractorState), ( - With, + With, With, Without, ), @@ -155,3 +160,41 @@ fn prototype_interaction_input( *right_state = XRInteractorState::Idle; } } + +#[derive(Component)] +pub struct Grabbable; + +pub fn update_grabbables( + mut events: EventReader, + mut grabbable_query: Query<(&mut Transform, With, Without)>, + interactor_query: Query<(&GlobalTransform, With, Without)>, +) { + //so basically the idea is to try all the events? + for event in events.read() { + info!("some event"); + match grabbable_query.get_mut(event.interactable) { + Ok(mut grabbable_transform) => { + info!("we got a grabbable"); + //now we need the location of our interactor + match interactor_query.get(event.interactor) { + Ok(interactor_transform) => { + info!("its a direct interactor?"); + info!( + "before gT: {:?}, iT: {:?}", + grabbable_transform, interactor_transform + ); + *grabbable_transform.0 = interactor_transform.0.compute_transform(); + info!( + "after gT: {:?}, iT: {:?}", + grabbable_transform, interactor_transform + ); + } + Err(_) => info!("not a direct interactor"), + } + } + Err(_) => { + info!("not a grabbable?") + } + } + } +} diff --git a/src/xr_input/interactions.rs b/src/xr_input/interactions.rs index a36d832..86a35e5 100644 --- a/src/xr_input/interactions.rs +++ b/src/xr_input/interactions.rs @@ -1,7 +1,8 @@ use std::f32::consts::PI; use bevy::prelude::{ - info, Color, Component, Gizmos, GlobalTransform, Quat, Query, Transform, Vec3, With, Without, + info, Color, Component, Entity, Event, EventReader, EventWriter, Gizmos, GlobalTransform, Quat, + Query, Transform, Vec3, With, Without, }; use super::trackers::{AimPose, OpenXRTrackingRoot}; @@ -12,7 +13,7 @@ pub struct XRDirectInteractor; #[derive(Component)] pub struct XRRayInteractor; -#[derive(Component)] +#[derive(Component, Clone, Copy)] pub enum XRInteractableState { Idle, Hover, @@ -110,102 +111,113 @@ pub fn draw_interaction_gizmos( } } -pub fn direct_interaction( - mut interactable_query: Query< - (&GlobalTransform, &mut XRInteractableState), - (With, Without), - >, - interactor_query: Query< - (&GlobalTransform, &XRInteractorState), - (With, Without), - >, -) { - for (xr_interactable_global_transform, mut state) in interactable_query.iter_mut() { - let mut hovered = false; - let mut selected = false; - for (interactor_global_transform, interactor_state) in interactor_query.iter() { - //check for sphere overlaps - let size = 0.1; - if interactor_global_transform - .compute_transform() - .translation - .distance_squared( - xr_interactable_global_transform - .compute_transform() - .translation, - ) - < (size * size) * 2.0 - { - //check for selections first - match interactor_state { - XRInteractorState::Idle => hovered = true, - XRInteractorState::Selecting => { - selected = true; - } - } - } - } - //check what we found - //also i dont like this - if selected { - *state = XRInteractableState::Select; - } else if hovered { - *state = XRInteractableState::Hover; - } else { - *state = XRInteractableState::Idle; - } - } +#[derive(Event)] +pub struct InteractionEvent { + pub interactor: Entity, + pub interactable: Entity, + pub interactable_state: XRInteractableState, } -pub fn ray_interaction( +pub fn interactions( mut interactable_query: Query< - (&GlobalTransform, &mut XRInteractableState), + (&GlobalTransform, &mut XRInteractableState, Entity), (With, Without), >, interactor_query: Query< - (&GlobalTransform, &XRInteractorState, Option<&AimPose>), - (With, Without), + ( + &GlobalTransform, + &XRInteractorState, + Entity, + Option<&XRDirectInteractor>, + Option<&XRRayInteractor>, + Option<&AimPose>, + ), + (Without), >, tracking_root_query: Query<(&mut Transform, With)>, + mut writer: EventWriter, ) { - for (xr_interactable_global_transform, mut state) in interactable_query.iter_mut() { + for (xr_interactable_global_transform, mut state, interactable_entity) in + interactable_query.iter_mut() + { let mut hovered = false; - let mut selected = false; - for (interactor_global_transform, interactor_state, aim) in interactor_query.iter() { - //check for ray-sphere intersection - let sphere_transform = xr_interactable_global_transform.compute_transform(); - let center = sphere_transform.translation; - let radius: f32 = 0.1; - //I hate this but the aim pose needs the root for now - let root = tracking_root_query.get_single().unwrap().0; - match aim { - Some(aim) => { - let ray_origin = root.translation + root.rotation.mul_vec3(aim.0.translation); - let ray_dir = root.rotation.mul_vec3(aim.0.forward()); - - if ray_sphere_intersection( - center, - radius, - ray_origin, - ray_dir.normalize_or_zero(), - ) { + for (interactor_global_transform, interactor_state, interactor_entity, direct, ray, aim) in + interactor_query.iter() + { + match direct { + Some(_) => { + //check for sphere overlaps + let size = 0.1; + if interactor_global_transform + .compute_transform() + .translation + .distance_squared( + xr_interactable_global_transform + .compute_transform() + .translation, + ) + < (size * size) * 2.0 + { //check for selections first match interactor_state { XRInteractorState::Idle => hovered = true, XRInteractorState::Selecting => { - selected = true; + //welp now I gota actually make things do stuff lol + let event = InteractionEvent { + interactor: interactor_entity, + interactable: interactable_entity, + interactable_state: XRInteractableState::Select, + }; + writer.send(event); } } } } - None => info!("no aim pose"), + None => (), + } + match ray { + Some(_) => { + //check for ray-sphere intersection + let sphere_transform = xr_interactable_global_transform.compute_transform(); + let center = sphere_transform.translation; + let radius: f32 = 0.1; + //I hate this but the aim pose needs the root for now + let root = tracking_root_query.get_single().unwrap().0; + match aim { + Some(aim) => { + let ray_origin = + root.translation + root.rotation.mul_vec3(aim.0.translation); + let ray_dir = root.rotation.mul_vec3(aim.0.forward()); + + if ray_sphere_intersection( + center, + radius, + ray_origin, + ray_dir.normalize_or_zero(), + ) { + //check for selections first + match interactor_state { + XRInteractorState::Idle => hovered = true, + XRInteractorState::Selecting => { + //welp now I gota actually make things do stuff lol + let event = InteractionEvent { + interactor: interactor_entity, + interactable: interactable_entity, + interactable_state: XRInteractableState::Select, + }; + writer.send(event); + } + } + } + } + None => info!("no aim pose"), + } + } + None => (), } } - //check what we found - //also i dont like this - if selected { - *state = XRInteractableState::Select; - } else if hovered { + //still hate this + if hovered { *state = XRInteractableState::Hover; } else { *state = XRInteractableState::Idle; @@ -213,6 +225,22 @@ pub fn ray_interaction( } } +pub fn update_interactable_states( + mut events: EventReader, + mut interactable_query: Query<(Entity, &mut XRInteractableState), (With)>, +) { + for event in events.read() { + //lets change the state? + match interactable_query.get_mut(event.interactable) { + Ok((_entity, mut entity_state)) => { + *entity_state = event.interactable_state; + } + Err(_) => { + } + } + } +} + fn ray_sphere_intersection(center: Vec3, radius: f32, ray_origin: Vec3, ray_dir: Vec3) -> bool { let l = center - ray_origin; let adj = l.dot(ray_dir); From 88838b595b9b06ad5b02d460ecf72ccee97e47b5 Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Sat, 30 Sep 2023 23:02:30 -0400 Subject: [PATCH 07/11] jank socket interactor --- examples/xr.rs | 30 +++++++++----- src/xr_input/interactions.rs | 80 +++++++++++++++++++++++++++++++++++- 2 files changed, 98 insertions(+), 12 deletions(-) diff --git a/examples/xr.rs b/examples/xr.rs index 68b7b5d..35b0800 100644 --- a/examples/xr.rs +++ b/examples/xr.rs @@ -5,8 +5,9 @@ use bevy_openxr::input::XrInput; use bevy_openxr::resources::{XrFrameState, XrInstance, XrSession}; use bevy_openxr::xr_input::debug_gizmos::OpenXrDebugRenderer; use bevy_openxr::xr_input::interactions::{ - interactions, draw_interaction_gizmos, update_interactable_states, InteractionEvent, - XRDirectInteractor, XRInteractable, XRInteractableState, XRInteractorState, XRRayInteractor, + draw_interaction_gizmos, draw_socket_gizmos, interactions, update_interactable_states, + InteractionEvent, XRDirectInteractor, XRInteractable, XRInteractableState, XRInteractorState, + XRRayInteractor, XRSocketInteractor, socket_interactions, }; use bevy_openxr::xr_input::oculus_touch::OculusController; use bevy_openxr::xr_input::prototype_locomotion::{proto_locomotion, PrototypeLocomotionConfig}; @@ -33,7 +34,9 @@ fn main() { Update, draw_interaction_gizmos.after(update_interactable_states), ) + .add_systems(Update, draw_socket_gizmos.after(update_interactable_states)) .add_systems(Update, interactions) + .add_systems(Update, socket_interactions) .add_systems(Update, prototype_interaction_input) .add_systems(Update, update_interactable_states.after(interactions)) .add_systems(Update, update_grabbables.after(update_interactable_states)) @@ -60,13 +63,16 @@ fn setup( transform: Transform::from_xyz(0.0, 0.5, 0.0), ..default() }); - // cube - commands.spawn(PbrBundle { - mesh: meshes.add(Mesh::from(shape::Cube { size: 0.1 })), - material: materials.add(Color::rgb(0.8, 0.0, 0.0).into()), - transform: Transform::from_xyz(0.0, 0.5, 1.0), - ..default() - }); + // socket + commands.spawn(( + SpatialBundle { + transform: Transform::from_xyz(0.0, 0.5, 1.0), + ..default() + }, + XRInteractorState::Selecting, + XRSocketInteractor, + )); + // light commands.spawn(PointLightBundle { point_light: PointLight { @@ -167,7 +173,11 @@ pub struct Grabbable; pub fn update_grabbables( mut events: EventReader, mut grabbable_query: Query<(&mut Transform, With, Without)>, - interactor_query: Query<(&GlobalTransform, With, Without)>, + interactor_query: Query<( + &GlobalTransform, + With, + Without, + )>, ) { //so basically the idea is to try all the events? for event in events.read() { diff --git a/src/xr_input/interactions.rs b/src/xr_input/interactions.rs index 86a35e5..db3dfc2 100644 --- a/src/xr_input/interactions.rs +++ b/src/xr_input/interactions.rs @@ -13,6 +13,9 @@ pub struct XRDirectInteractor; #[derive(Component)] pub struct XRRayInteractor; +#[derive(Component)] +pub struct XRSocketInteractor; + #[derive(Component, Clone, Copy)] pub enum XRInteractableState { Idle, @@ -40,6 +43,27 @@ impl Default for XRInteractorState { #[derive(Component)] pub struct XRInteractable; +//i guess really these should be seperate +pub fn draw_socket_gizmos( + mut gizmos: Gizmos, + interactor_query: Query<( + &GlobalTransform, + &XRInteractorState, + Entity, + &XRSocketInteractor, + )>, +) { + for (global, state, _entity, _socket) in interactor_query.iter() { + let mut transform = global.compute_transform().clone(); + transform.scale = Vec3::splat(0.1); + let color = match state { + XRInteractorState::Idle => Color::BLUE, + XRInteractorState::Selecting => Color::PURPLE, + }; + gizmos.cuboid(transform, color) + } +} + pub fn draw_interaction_gizmos( mut gizmos: Gizmos, interactable_query: Query< @@ -118,6 +142,59 @@ pub struct InteractionEvent { pub interactable_state: XRInteractableState, } +//yeah these need to be seperate somehow +pub fn socket_interactions( + mut interactable_query: Query< + (&GlobalTransform, &mut XRInteractableState, Entity), + (With, Without), + >, + interactor_query: Query< + ( + &GlobalTransform, + &XRInteractorState, + Entity, + &XRSocketInteractor, + ), + (Without), + >, + mut writer: EventWriter, +) { + for interactable in interactable_query.iter() { + //for the interactbles + for socket in interactor_query.iter() { + let interactor_global_transform = socket.0; + let xr_interactable_global_transform = interactable.0; + let interactor_state = socket.1; + //check for sphere overlaps + let size = 0.1; + if interactor_global_transform + .compute_transform() + .translation + .distance_squared( + xr_interactable_global_transform + .compute_transform() + .translation, + ) + < (size * size) * 2.0 + { + //check for selections first + match interactor_state { + XRInteractorState::Idle => (), //welp this wont work, + XRInteractorState::Selecting => { + //welp now I gota actually make things do stuff lol + let event = InteractionEvent { + interactor: socket.2, + interactable: interactable.2, + interactable_state: XRInteractableState::Select, + }; + writer.send(event); + } + } + } + } + } +} + pub fn interactions( mut interactable_query: Query< (&GlobalTransform, &mut XRInteractableState, Entity), @@ -235,8 +312,7 @@ pub fn update_interactable_states( Ok((_entity, mut entity_state)) => { *entity_state = event.interactable_state; } - Err(_) => { - } + Err(_) => {} } } } From d80506c43c0a1957ee3cd3dbc410149d52db86b9 Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Sun, 1 Oct 2023 00:22:42 -0400 Subject: [PATCH 08/11] this is a little better --- examples/xr.rs | 56 ++++++++++++++++------------- src/xr_input/interactions.rs | 69 +++++++++++++++++++++++++----------- 2 files changed, 79 insertions(+), 46 deletions(-) diff --git a/examples/xr.rs b/examples/xr.rs index 35b0800..fd8f2ea 100644 --- a/examples/xr.rs +++ b/examples/xr.rs @@ -5,9 +5,9 @@ use bevy_openxr::input::XrInput; use bevy_openxr::resources::{XrFrameState, XrInstance, XrSession}; use bevy_openxr::xr_input::debug_gizmos::OpenXrDebugRenderer; use bevy_openxr::xr_input::interactions::{ - draw_interaction_gizmos, draw_socket_gizmos, interactions, update_interactable_states, - InteractionEvent, XRDirectInteractor, XRInteractable, XRInteractableState, XRInteractorState, - XRRayInteractor, XRSocketInteractor, socket_interactions, + draw_interaction_gizmos, draw_socket_gizmos, interactions, socket_interactions, + update_interactable_states, InteractionEvent, XRDirectInteractor, XRInteractable, + XRInteractableState, XRInteractorState, XRRayInteractor, XRSocketInteractor, }; use bevy_openxr::xr_input::oculus_touch::OculusController; use bevy_openxr::xr_input::prototype_locomotion::{proto_locomotion, PrototypeLocomotionConfig}; @@ -35,10 +35,13 @@ fn main() { draw_interaction_gizmos.after(update_interactable_states), ) .add_systems(Update, draw_socket_gizmos.after(update_interactable_states)) - .add_systems(Update, interactions) - .add_systems(Update, socket_interactions) + .add_systems(Update, interactions.before(update_interactable_states)) + .add_systems( + Update, + socket_interactions.before(update_interactable_states), + ) .add_systems(Update, prototype_interaction_input) - .add_systems(Update, update_interactable_states.after(interactions)) + .add_systems(Update, update_interactable_states) .add_systems(Update, update_grabbables.after(update_interactable_states)) .add_event::() .run(); @@ -173,37 +176,40 @@ pub struct Grabbable; pub fn update_grabbables( mut events: EventReader, mut grabbable_query: Query<(&mut Transform, With, Without)>, - interactor_query: Query<( - &GlobalTransform, - With, - Without, - )>, + interactor_query: Query<(&GlobalTransform, &XRInteractorState, Without)>, ) { //so basically the idea is to try all the events? for event in events.read() { - info!("some event"); + // info!("some event"); match grabbable_query.get_mut(event.interactable) { Ok(mut grabbable_transform) => { - info!("we got a grabbable"); + // info!("we got a grabbable"); //now we need the location of our interactor match interactor_query.get(event.interactor) { Ok(interactor_transform) => { - info!("its a direct interactor?"); - info!( - "before gT: {:?}, iT: {:?}", - grabbable_transform, interactor_transform - ); - *grabbable_transform.0 = interactor_transform.0.compute_transform(); - info!( - "after gT: {:?}, iT: {:?}", - grabbable_transform, interactor_transform - ); + match interactor_transform.1 { + XRInteractorState::Idle => (), + XRInteractorState::Selecting => { + // info!("its a direct interactor?"); + // info!( + // "before gT: {:?}, iT: {:?}", + // grabbable_transform, interactor_transform + // ); + *grabbable_transform.0 = interactor_transform.0.compute_transform(); + // info!( + // "after gT: {:?}, iT: {:?}", + // grabbable_transform, interactor_transform + // ); + } + } + } + Err(_) => { + // info!("not a direct interactor") } - Err(_) => info!("not a direct interactor"), } } Err(_) => { - info!("not a grabbable?") + // info!("not a grabbable?") } } } diff --git a/src/xr_input/interactions.rs b/src/xr_input/interactions.rs index db3dfc2..425d8d6 100644 --- a/src/xr_input/interactions.rs +++ b/src/xr_input/interactions.rs @@ -16,7 +16,7 @@ pub struct XRRayInteractor; #[derive(Component)] pub struct XRSocketInteractor; -#[derive(Component, Clone, Copy)] +#[derive(Component, Clone, Copy, PartialEq, PartialOrd, Debug)] pub enum XRInteractableState { Idle, Hover, @@ -78,7 +78,7 @@ pub fn draw_interaction_gizmos( Option<&XRRayInteractor>, Option<&AimPose>, ), - (Without), + Without, >, tracking_root_query: Query<(&mut Transform, With)>, ) { @@ -144,7 +144,7 @@ pub struct InteractionEvent { //yeah these need to be seperate somehow pub fn socket_interactions( - mut interactable_query: Query< + interactable_query: Query< (&GlobalTransform, &mut XRInteractableState, Entity), (With, Without), >, @@ -155,7 +155,7 @@ pub fn socket_interactions( Entity, &XRSocketInteractor, ), - (Without), + Without, >, mut writer: EventWriter, ) { @@ -179,7 +179,15 @@ pub fn socket_interactions( { //check for selections first match interactor_state { - XRInteractorState::Idle => (), //welp this wont work, + XRInteractorState::Idle => { + //welp now I gota actually make things do stuff lol + let event = InteractionEvent { + interactor: socket.2, + interactable: interactable.2, + interactable_state: XRInteractableState::Hover, + }; + writer.send(event); + } XRInteractorState::Selecting => { //welp now I gota actually make things do stuff lol let event = InteractionEvent { @@ -196,8 +204,8 @@ pub fn socket_interactions( } pub fn interactions( - mut interactable_query: Query< - (&GlobalTransform, &mut XRInteractableState, Entity), + interactable_query: Query< + (&GlobalTransform, Entity), (With, Without), >, interactor_query: Query< @@ -209,15 +217,12 @@ pub fn interactions( Option<&XRRayInteractor>, Option<&AimPose>, ), - (Without), + Without, >, tracking_root_query: Query<(&mut Transform, With)>, mut writer: EventWriter, ) { - for (xr_interactable_global_transform, mut state, interactable_entity) in - interactable_query.iter_mut() - { - let mut hovered = false; + for (xr_interactable_global_transform, interactable_entity) in interactable_query.iter() { for (interactor_global_transform, interactor_state, interactor_entity, direct, ray, aim) in interactor_query.iter() { @@ -237,7 +242,15 @@ pub fn interactions( { //check for selections first match interactor_state { - XRInteractorState::Idle => hovered = true, + XRInteractorState::Idle => { + //welp now I gota actually make things do stuff lol + let event = InteractionEvent { + interactor: interactor_entity, + interactable: interactable_entity, + interactable_state: XRInteractableState::Hover, + }; + writer.send(event); + } XRInteractorState::Selecting => { //welp now I gota actually make things do stuff lol let event = InteractionEvent { @@ -274,7 +287,15 @@ pub fn interactions( ) { //check for selections first match interactor_state { - XRInteractorState::Idle => hovered = true, + XRInteractorState::Idle => { + //welp now I gota actually make things do stuff lol + let event = InteractionEvent { + interactor: interactor_entity, + interactable: interactable_entity, + interactable_state: XRInteractableState::Hover, + }; + writer.send(event); + } XRInteractorState::Selecting => { //welp now I gota actually make things do stuff lol let event = InteractionEvent { @@ -293,23 +314,29 @@ pub fn interactions( None => (), } } - //still hate this - if hovered { - *state = XRInteractableState::Hover; - } else { - *state = XRInteractableState::Idle; - } } } pub fn update_interactable_states( mut events: EventReader, - mut interactable_query: Query<(Entity, &mut XRInteractableState), (With)>, + mut interactable_query: Query<(Entity, &mut XRInteractableState), With>, ) { + //i legit hate this haha but it works + for (_entity, mut state) in interactable_query.iter_mut() { + *state = XRInteractableState::Idle; + } + for event in events.read() { //lets change the state? match interactable_query.get_mut(event.interactable) { Ok((_entity, mut entity_state)) => { + if event.interactable_state > *entity_state { + // info!( + // "event.state: {:?}, interactable.state: {:?}", + // event.interactable_state, entity_state + // ); + // info!("event has a higher state"); + } *entity_state = event.interactable_state; } Err(_) => {} From b487bf6cbb3d79593091ffed003532a2bb4e6ff0 Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Sun, 1 Oct 2023 23:42:43 -0400 Subject: [PATCH 09/11] this works well enough for now --- examples/xr.rs | 3 ++- src/xr_input/interactions.rs | 37 ++++++++++++++++++++---------------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/examples/xr.rs b/examples/xr.rs index fd8f2ea..2aed227 100644 --- a/examples/xr.rs +++ b/examples/xr.rs @@ -6,7 +6,7 @@ use bevy_openxr::resources::{XrFrameState, XrInstance, XrSession}; use bevy_openxr::xr_input::debug_gizmos::OpenXrDebugRenderer; use bevy_openxr::xr_input::interactions::{ draw_interaction_gizmos, draw_socket_gizmos, interactions, socket_interactions, - update_interactable_states, InteractionEvent, XRDirectInteractor, XRInteractable, + update_interactable_states, InteractionEvent, Touched, XRDirectInteractor, XRInteractable, XRInteractableState, XRInteractorState, XRRayInteractor, XRSocketInteractor, }; use bevy_openxr::xr_input::oculus_touch::OculusController; @@ -100,6 +100,7 @@ fn setup( XRInteractable, XRInteractableState::default(), Grabbable, + Touched(false), )); } diff --git a/src/xr_input/interactions.rs b/src/xr_input/interactions.rs index 425d8d6..9660839 100644 --- a/src/xr_input/interactions.rs +++ b/src/xr_input/interactions.rs @@ -16,6 +16,9 @@ pub struct XRRayInteractor; #[derive(Component)] pub struct XRSocketInteractor; +#[derive(Component)] +pub struct Touched(pub bool); + #[derive(Component, Clone, Copy, PartialEq, PartialOrd, Debug)] pub enum XRInteractableState { Idle, @@ -43,7 +46,6 @@ impl Default for XRInteractorState { #[derive(Component)] pub struct XRInteractable; -//i guess really these should be seperate pub fn draw_socket_gizmos( mut gizmos: Gizmos, interactor_query: Query<( @@ -142,7 +144,6 @@ pub struct InteractionEvent { pub interactable_state: XRInteractableState, } -//yeah these need to be seperate somehow pub fn socket_interactions( interactable_query: Query< (&GlobalTransform, &mut XRInteractableState, Entity), @@ -160,7 +161,7 @@ pub fn socket_interactions( mut writer: EventWriter, ) { for interactable in interactable_query.iter() { - //for the interactbles + //for the interactables for socket in interactor_query.iter() { let interactor_global_transform = socket.0; let xr_interactable_global_transform = interactable.0; @@ -180,7 +181,6 @@ pub fn socket_interactions( //check for selections first match interactor_state { XRInteractorState::Idle => { - //welp now I gota actually make things do stuff lol let event = InteractionEvent { interactor: socket.2, interactable: interactable.2, @@ -189,7 +189,6 @@ pub fn socket_interactions( writer.send(event); } XRInteractorState::Selecting => { - //welp now I gota actually make things do stuff lol let event = InteractionEvent { interactor: socket.2, interactable: interactable.2, @@ -243,7 +242,6 @@ pub fn interactions( //check for selections first match interactor_state { XRInteractorState::Idle => { - //welp now I gota actually make things do stuff lol let event = InteractionEvent { interactor: interactor_entity, interactable: interactable_entity, @@ -252,7 +250,6 @@ pub fn interactions( writer.send(event); } XRInteractorState::Selecting => { - //welp now I gota actually make things do stuff lol let event = InteractionEvent { interactor: interactor_entity, interactable: interactable_entity, @@ -288,7 +285,6 @@ pub fn interactions( //check for selections first match interactor_state { XRInteractorState::Idle => { - //welp now I gota actually make things do stuff lol let event = InteractionEvent { interactor: interactor_entity, interactable: interactable_entity, @@ -297,7 +293,6 @@ pub fn interactions( writer.send(event); } XRInteractorState::Selecting => { - //welp now I gota actually make things do stuff lol let event = InteractionEvent { interactor: interactor_entity, interactable: interactable_entity, @@ -319,17 +314,21 @@ pub fn interactions( pub fn update_interactable_states( mut events: EventReader, - mut interactable_query: Query<(Entity, &mut XRInteractableState), With>, + mut interactable_query: Query< + (Entity, &mut XRInteractableState, &mut Touched), + With, + >, ) { - //i legit hate this haha but it works - for (_entity, mut state) in interactable_query.iter_mut() { - *state = XRInteractableState::Idle; + //i very much dislike this + for (_entity, _state, mut touched) in interactable_query.iter_mut() { + *touched = Touched(false); } - for event in events.read() { - //lets change the state? + //lets change the state match interactable_query.get_mut(event.interactable) { - Ok((_entity, mut entity_state)) => { + Ok((_entity, mut entity_state, mut touched)) => { + //since we have an event we were touched this frame, i hate this name + *touched = Touched(true); if event.interactable_state > *entity_state { // info!( // "event.state: {:?}, interactable.state: {:?}", @@ -342,6 +341,12 @@ pub fn update_interactable_states( Err(_) => {} } } + //lets go through all the untouched interactables and set them to idle + for (_entity, mut state, touched) in interactable_query.iter_mut() { + if !touched.0 { + *state = XRInteractableState::Idle; + } + } } fn ray_sphere_intersection(center: Vec3, radius: f32, ray_origin: Vec3, ray_dir: Vec3) -> bool { From 6fc41ecbfca2bdb0bece4b50f9287d8a3ca71be3 Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Sun, 1 Oct 2023 23:44:00 -0400 Subject: [PATCH 10/11] cleaning --- examples/xr.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/examples/xr.rs b/examples/xr.rs index 2aed227..0b15b9d 100644 --- a/examples/xr.rs +++ b/examples/xr.rs @@ -192,15 +192,7 @@ pub fn update_grabbables( XRInteractorState::Idle => (), XRInteractorState::Selecting => { // info!("its a direct interactor?"); - // info!( - // "before gT: {:?}, iT: {:?}", - // grabbable_transform, interactor_transform - // ); *grabbable_transform.0 = interactor_transform.0.compute_transform(); - // info!( - // "after gT: {:?}, iT: {:?}", - // grabbable_transform, interactor_transform - // ); } } } From 903dc2a5da68f86d31e45b458f56515fa552916f Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Sun, 1 Oct 2023 23:48:58 -0400 Subject: [PATCH 11/11] added right hand aim poses --- src/xr_input/trackers.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/xr_input/trackers.rs b/src/xr_input/trackers.rs index cbd4697..233acc6 100644 --- a/src/xr_input/trackers.rs +++ b/src/xr_input/trackers.rs @@ -74,8 +74,8 @@ pub fn update_open_xr_controllers( let left_grip_space = controller.grip_space(Hand::Left); let left_aim_space = controller.aim_space(Hand::Left); let left_postion = left_grip_space.0.pose.position.to_vec3(); - let aim_pose = left_controller_query.get_single_mut().unwrap().1; - match aim_pose { + let left_aim_pose = left_controller_query.get_single_mut().unwrap().1; + match left_aim_pose { Some(mut pose) => { *pose = AimPose(Transform { translation: left_aim_space.0.pose.position.to_vec3(), @@ -95,8 +95,21 @@ pub fn update_open_xr_controllers( left_controller_query.get_single_mut().unwrap().0.rotation = left_grip_space.0.pose.orientation.to_quat(); //get right controller - let right = controller.grip_space(Hand::Right); - let right_postion = right.0.pose.position.to_vec3(); + let right_grip_space = controller.grip_space(Hand::Right); + let right_aim_space = controller.aim_space(Hand::Right); + let right_postion = right_grip_space.0.pose.position.to_vec3(); + + let right_aim_pose = right_controller_query.get_single_mut().unwrap().1; + match right_aim_pose { + Some(mut pose) => { + *pose = AimPose(Transform { + translation: right_aim_space.0.pose.position.to_vec3(), + rotation: right_aim_space.0.pose.orientation.to_quat(), + scale: Vec3::splat(1.0), + }); + } + None => (), + } right_controller_query .get_single_mut() @@ -105,5 +118,5 @@ pub fn update_open_xr_controllers( .translation = right_postion; right_controller_query.get_single_mut().unwrap().0.rotation = - right.0.pose.orientation.to_quat(); + right_grip_space.0.pose.orientation.to_quat(); }