From 23ed65f06a5bb35ba115c1604ffd64f57b609dc9 Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Sun, 24 Sep 2023 23:15:24 -0400 Subject: [PATCH] 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;