interactions, and grabbables

This commit is contained in:
Jay Christy
2023-09-27 23:43:03 -04:00
parent e1f1948726
commit 6e83b887be
2 changed files with 159 additions and 88 deletions

View File

@@ -5,13 +5,13 @@ use bevy_openxr::input::XrInput;
use bevy_openxr::resources::{XrFrameState, XrInstance, XrSession}; use bevy_openxr::resources::{XrFrameState, XrInstance, XrSession};
use bevy_openxr::xr_input::debug_gizmos::OpenXrDebugRenderer; use bevy_openxr::xr_input::debug_gizmos::OpenXrDebugRenderer;
use bevy_openxr::xr_input::interactions::{ use bevy_openxr::xr_input::interactions::{
draw_interaction_gizmos, direct_interaction, XRDirectInteractor, XRInteractable, interactions, draw_interaction_gizmos, update_interactable_states, InteractionEvent,
XRInteractableState, XRInteractorState, XRRayInteractor, ray_interaction, XRDirectInteractor, XRInteractable, XRInteractableState, XRInteractorState, XRRayInteractor,
}; };
use bevy_openxr::xr_input::oculus_touch::OculusController; use bevy_openxr::xr_input::oculus_touch::OculusController;
use bevy_openxr::xr_input::prototype_locomotion::{proto_locomotion, PrototypeLocomotionConfig}; use bevy_openxr::xr_input::prototype_locomotion::{proto_locomotion, PrototypeLocomotionConfig};
use bevy_openxr::xr_input::trackers::{ 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::xr_input::Hand;
use bevy_openxr::DefaultXrPlugins; use bevy_openxr::DefaultXrPlugins;
@@ -29,10 +29,15 @@ fn main() {
.add_systems(Update, proto_locomotion) .add_systems(Update, proto_locomotion)
.add_systems(Startup, spawn_controllers_example) .add_systems(Startup, spawn_controllers_example)
.insert_resource(PrototypeLocomotionConfig::default()) .insert_resource(PrototypeLocomotionConfig::default())
.add_systems(Update, draw_interaction_gizmos) .add_systems(
.add_systems(Update, direct_interaction) Update,
.add_systems(Update, ray_interaction) draw_interaction_gizmos.after(update_interactable_states),
)
.add_systems(Update, interactions)
.add_systems(Update, prototype_interaction_input) .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::<InteractionEvent>()
.run(); .run();
} }
@@ -85,6 +90,7 @@ fn setup(
}, },
XRInteractable, XRInteractable,
XRInteractableState::default(), XRInteractableState::default(),
Grabbable,
)); ));
} }
@@ -95,7 +101,6 @@ fn spawn_controllers_example(mut commands: Commands) {
OpenXRController, OpenXRController,
OpenXRTracker, OpenXRTracker,
SpatialBundle::default(), SpatialBundle::default(),
XRDirectInteractor,
XRRayInteractor, XRRayInteractor,
AimPose(Transform::default()), AimPose(Transform::default()),
XRInteractorState::default(), XRInteractorState::default(),
@@ -128,7 +133,7 @@ fn prototype_interaction_input(
mut left_interactor_query: Query< mut left_interactor_query: Query<
(&mut XRInteractorState), (&mut XRInteractorState),
( (
With<XRDirectInteractor>, With<XRRayInteractor>,
With<OpenXRLeftController>, With<OpenXRLeftController>,
Without<OpenXRRightController>, Without<OpenXRRightController>,
), ),
@@ -155,3 +160,41 @@ fn prototype_interaction_input(
*right_state = XRInteractorState::Idle; *right_state = XRInteractorState::Idle;
} }
} }
#[derive(Component)]
pub struct Grabbable;
pub fn update_grabbables(
mut events: EventReader<InteractionEvent>,
mut grabbable_query: Query<(&mut Transform, With<Grabbable>, Without<XRDirectInteractor>)>,
interactor_query: Query<(&GlobalTransform, With<XRDirectInteractor>, Without<Grabbable>)>,
) {
//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?")
}
}
}
}

View File

@@ -1,7 +1,8 @@
use std::f32::consts::PI; use std::f32::consts::PI;
use bevy::prelude::{ 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}; use super::trackers::{AimPose, OpenXRTrackingRoot};
@@ -12,7 +13,7 @@ pub struct XRDirectInteractor;
#[derive(Component)] #[derive(Component)]
pub struct XRRayInteractor; pub struct XRRayInteractor;
#[derive(Component)] #[derive(Component, Clone, Copy)]
pub enum XRInteractableState { pub enum XRInteractableState {
Idle, Idle,
Hover, Hover,
@@ -110,20 +111,41 @@ pub fn draw_interaction_gizmos(
} }
} }
pub fn direct_interaction( #[derive(Event)]
pub struct InteractionEvent {
pub interactor: Entity,
pub interactable: Entity,
pub interactable_state: XRInteractableState,
}
pub fn interactions(
mut interactable_query: Query< mut interactable_query: Query<
(&GlobalTransform, &mut XRInteractableState), (&GlobalTransform, &mut XRInteractableState, Entity),
(With<XRInteractable>, Without<XRDirectInteractor>), (With<XRInteractable>, Without<XRDirectInteractor>),
>, >,
interactor_query: Query< interactor_query: Query<
(&GlobalTransform, &XRInteractorState), (
(With<XRDirectInteractor>, Without<XRInteractable>), &GlobalTransform,
&XRInteractorState,
Entity,
Option<&XRDirectInteractor>,
Option<&XRRayInteractor>,
Option<&AimPose>,
),
(Without<XRInteractable>),
>, >,
tracking_root_query: Query<(&mut Transform, With<OpenXRTrackingRoot>)>,
mut writer: EventWriter<InteractionEvent>,
) { ) {
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 hovered = false;
let mut selected = false; for (interactor_global_transform, interactor_state, interactor_entity, direct, ray, aim) in
for (interactor_global_transform, interactor_state) in interactor_query.iter() { interactor_query.iter()
{
match direct {
Some(_) => {
//check for sphere overlaps //check for sphere overlaps
let size = 0.1; let size = 0.1;
if interactor_global_transform if interactor_global_transform
@@ -140,38 +162,21 @@ pub fn direct_interaction(
match interactor_state { match interactor_state {
XRInteractorState::Idle => hovered = true, XRInteractorState::Idle => hovered = true,
XRInteractorState::Selecting => { 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);
} }
} }
} }
} }
//check what we found None => (),
//also i dont like this
if selected {
*state = XRInteractableState::Select;
} else if hovered {
*state = XRInteractableState::Hover;
} else {
*state = XRInteractableState::Idle;
} }
} match ray {
} Some(_) => {
pub fn ray_interaction(
mut interactable_query: Query<
(&GlobalTransform, &mut XRInteractableState),
(With<XRInteractable>, Without<XRDirectInteractor>),
>,
interactor_query: Query<
(&GlobalTransform, &XRInteractorState, Option<&AimPose>),
(With<XRRayInteractor>, Without<XRInteractable>),
>,
tracking_root_query: Query<(&mut Transform, With<OpenXRTrackingRoot>)>,
) {
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 //check for ray-sphere intersection
let sphere_transform = xr_interactable_global_transform.compute_transform(); let sphere_transform = xr_interactable_global_transform.compute_transform();
let center = sphere_transform.translation; let center = sphere_transform.translation;
@@ -180,7 +185,8 @@ pub fn ray_interaction(
let root = tracking_root_query.get_single().unwrap().0; let root = tracking_root_query.get_single().unwrap().0;
match aim { match aim {
Some(aim) => { Some(aim) => {
let ray_origin = root.translation + root.rotation.mul_vec3(aim.0.translation); let ray_origin =
root.translation + root.rotation.mul_vec3(aim.0.translation);
let ray_dir = root.rotation.mul_vec3(aim.0.forward()); let ray_dir = root.rotation.mul_vec3(aim.0.forward());
if ray_sphere_intersection( if ray_sphere_intersection(
@@ -193,7 +199,13 @@ pub fn ray_interaction(
match interactor_state { match interactor_state {
XRInteractorState::Idle => hovered = true, XRInteractorState::Idle => hovered = true,
XRInteractorState::Selecting => { 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);
} }
} }
} }
@@ -201,11 +213,11 @@ pub fn ray_interaction(
None => info!("no aim pose"), None => info!("no aim pose"),
} }
} }
//check what we found None => (),
//also i dont like this }
if selected { }
*state = XRInteractableState::Select; //still hate this
} else if hovered { if hovered {
*state = XRInteractableState::Hover; *state = XRInteractableState::Hover;
} else { } else {
*state = XRInteractableState::Idle; *state = XRInteractableState::Idle;
@@ -213,6 +225,22 @@ pub fn ray_interaction(
} }
} }
pub fn update_interactable_states(
mut events: EventReader<InteractionEvent>,
mut interactable_query: Query<(Entity, &mut XRInteractableState), (With<XRInteractable>)>,
) {
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 { fn ray_sphere_intersection(center: Vec3, radius: f32, ray_origin: Vec3, ray_dir: Vec3) -> bool {
let l = center - ray_origin; let l = center - ray_origin;
let adj = l.dot(ray_dir); let adj = l.dot(ray_dir);