basics of ray interactors
This commit is contained in:
@@ -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, hover_interaction, XRDirectInteractor, XRInteractable,
|
draw_interaction_gizmos, direct_interaction, XRDirectInteractor, XRInteractable,
|
||||||
XRInteractableState, XRInteractorState,
|
XRInteractableState, XRInteractorState, XRRayInteractor, ray_interaction,
|
||||||
};
|
};
|
||||||
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,
|
OpenXRController, OpenXRLeftController, OpenXRRightController, OpenXRTracker, AimPose,
|
||||||
};
|
};
|
||||||
use bevy_openxr::xr_input::Hand;
|
use bevy_openxr::xr_input::Hand;
|
||||||
use bevy_openxr::DefaultXrPlugins;
|
use bevy_openxr::DefaultXrPlugins;
|
||||||
@@ -30,7 +30,8 @@ fn main() {
|
|||||||
.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(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)
|
.add_systems(Update, prototype_interaction_input)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
@@ -95,6 +96,8 @@ fn spawn_controllers_example(mut commands: Commands) {
|
|||||||
OpenXRTracker,
|
OpenXRTracker,
|
||||||
SpatialBundle::default(),
|
SpatialBundle::default(),
|
||||||
XRDirectInteractor,
|
XRDirectInteractor,
|
||||||
|
XRRayInteractor,
|
||||||
|
AimPose(Transform::default()),
|
||||||
XRInteractorState::default(),
|
XRInteractorState::default(),
|
||||||
));
|
));
|
||||||
//right hand
|
//right hand
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
use bevy::prelude::{
|
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)]
|
#[derive(Component)]
|
||||||
pub struct XRDirectInteractor;
|
pub struct XRDirectInteractor;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct XRRayInteractor;
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub enum XRInteractableState {
|
pub enum XRInteractableState {
|
||||||
Idle,
|
Idle,
|
||||||
@@ -40,10 +46,18 @@ pub fn draw_interaction_gizmos(
|
|||||||
(With<XRInteractable>, Without<XRDirectInteractor>),
|
(With<XRInteractable>, Without<XRDirectInteractor>),
|
||||||
>,
|
>,
|
||||||
interactor_query: Query<
|
interactor_query: Query<
|
||||||
(&GlobalTransform, &XRInteractorState),
|
(
|
||||||
(With<XRDirectInteractor>, Without<XRInteractable>),
|
&GlobalTransform,
|
||||||
|
&XRInteractorState,
|
||||||
|
Option<&XRDirectInteractor>,
|
||||||
|
Option<&XRRayInteractor>,
|
||||||
|
Option<&AimPose>,
|
||||||
|
),
|
||||||
|
(Without<XRInteractable>),
|
||||||
>,
|
>,
|
||||||
|
tracking_root_query: Query<(&mut Transform, With<OpenXRTrackingRoot>)>,
|
||||||
) {
|
) {
|
||||||
|
let root = tracking_root_query.get_single().unwrap().0;
|
||||||
for (global_transform, interactable_state) in interactable_query.iter() {
|
for (global_transform, interactable_state) in interactable_query.iter() {
|
||||||
let transform = global_transform.compute_transform();
|
let transform = global_transform.compute_transform();
|
||||||
let color = match interactable_state {
|
let color = match interactable_state {
|
||||||
@@ -54,25 +68,49 @@ pub fn draw_interaction_gizmos(
|
|||||||
gizmos.sphere(transform.translation, transform.rotation, 0.1, color);
|
gizmos.sphere(transform.translation, transform.rotation, 0.1, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (interactor_global_transform, interactor_state) in interactor_query.iter() {
|
for (interactor_global_transform, interactor_state, direct, ray, aim) in interactor_query.iter()
|
||||||
let mut transform = interactor_global_transform.compute_transform();
|
{
|
||||||
transform.scale = Vec3::splat(0.1);
|
let transform = interactor_global_transform.compute_transform();
|
||||||
let quat = Quat::from_euler(
|
match direct {
|
||||||
bevy::prelude::EulerRot::XYZ,
|
Some(_) => {
|
||||||
45.0 * (PI / 180.0),
|
let mut local = transform.clone();
|
||||||
0.0,
|
local.scale = Vec3::splat(0.1);
|
||||||
45.0 * (PI / 180.0),
|
let quat = Quat::from_euler(
|
||||||
);
|
bevy::prelude::EulerRot::XYZ,
|
||||||
transform.rotation = quat;
|
45.0 * (PI / 180.0),
|
||||||
let color = match interactor_state {
|
0.0,
|
||||||
XRInteractorState::Idle => Color::BLUE,
|
45.0 * (PI / 180.0),
|
||||||
XRInteractorState::Selecting => Color::PURPLE,
|
);
|
||||||
};
|
local.rotation = quat;
|
||||||
gizmos.cuboid(transform, color);
|
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<
|
mut interactable_query: Query<
|
||||||
(&GlobalTransform, &mut XRInteractableState),
|
(&GlobalTransform, &mut XRInteractableState),
|
||||||
(With<XRInteractable>, Without<XRDirectInteractor>),
|
(With<XRInteractable>, Without<XRDirectInteractor>),
|
||||||
@@ -82,9 +120,7 @@ pub fn hover_interaction(
|
|||||||
(With<XRDirectInteractor>, Without<XRInteractable>),
|
(With<XRDirectInteractor>, Without<XRInteractable>),
|
||||||
>,
|
>,
|
||||||
) {
|
) {
|
||||||
for (xr_interactable_global_transform, mut state) in
|
for (xr_interactable_global_transform, mut state) in interactable_query.iter_mut() {
|
||||||
interactable_query.iter_mut()
|
|
||||||
{
|
|
||||||
let mut hovered = false;
|
let mut hovered = false;
|
||||||
let mut selected = false;
|
let mut selected = false;
|
||||||
for (interactor_global_transform, interactor_state) in interactor_query.iter() {
|
for (interactor_global_transform, interactor_state) in interactor_query.iter() {
|
||||||
@@ -100,7 +136,6 @@ pub fn hover_interaction(
|
|||||||
)
|
)
|
||||||
< (size * size) * 2.0
|
< (size * size) * 2.0
|
||||||
{
|
{
|
||||||
|
|
||||||
//check for selections first
|
//check for selections first
|
||||||
match interactor_state {
|
match interactor_state {
|
||||||
XRInteractorState::Idle => hovered = true,
|
XRInteractorState::Idle => hovered = true,
|
||||||
@@ -121,3 +156,79 @@ pub fn hover_interaction(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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)]
|
#[derive(Component)]
|
||||||
pub struct OpenXRTrackingRoot;
|
pub struct OpenXRTrackingRoot;
|
||||||
@@ -20,6 +26,8 @@ pub struct OpenXRLeftController;
|
|||||||
pub struct OpenXRRightController;
|
pub struct OpenXRRightController;
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct OpenXRController;
|
pub struct OpenXRController;
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct AimPose(pub Transform);
|
||||||
|
|
||||||
pub fn adopt_open_xr_trackers(
|
pub fn adopt_open_xr_trackers(
|
||||||
query: Query<(Entity), Added<OpenXRTracker>>,
|
query: Query<(Entity), Added<OpenXRTracker>>,
|
||||||
@@ -43,11 +51,13 @@ pub fn update_open_xr_controllers(
|
|||||||
oculus_controller: Res<OculusController>,
|
oculus_controller: Res<OculusController>,
|
||||||
mut left_controller_query: Query<(
|
mut left_controller_query: Query<(
|
||||||
&mut Transform,
|
&mut Transform,
|
||||||
|
Option<&mut AimPose>,
|
||||||
With<OpenXRLeftController>,
|
With<OpenXRLeftController>,
|
||||||
Without<OpenXRRightController>,
|
Without<OpenXRRightController>,
|
||||||
)>,
|
)>,
|
||||||
mut right_controller_query: Query<(
|
mut right_controller_query: Query<(
|
||||||
&mut Transform,
|
&mut Transform,
|
||||||
|
Option<&mut AimPose>,
|
||||||
With<OpenXRRightController>,
|
With<OpenXRRightController>,
|
||||||
Without<OpenXRLeftController>,
|
Without<OpenXRLeftController>,
|
||||||
)>,
|
)>,
|
||||||
@@ -61,8 +71,20 @@ pub fn update_open_xr_controllers(
|
|||||||
//get controller
|
//get controller
|
||||||
let controller = oculus_controller.get_ref(&instance, &session, &frame_state, &xr_input);
|
let controller = oculus_controller.get_ref(&instance, &session, &frame_state, &xr_input);
|
||||||
//get left controller
|
//get left controller
|
||||||
let left = controller.grip_space(Hand::Left);
|
let left_grip_space = controller.grip_space(Hand::Left);
|
||||||
let left_postion = left.0.pose.position.to_vec3();
|
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
|
left_controller_query
|
||||||
.get_single_mut()
|
.get_single_mut()
|
||||||
@@ -70,7 +92,8 @@ pub fn update_open_xr_controllers(
|
|||||||
.0
|
.0
|
||||||
.translation = left_postion;
|
.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
|
//get right controller
|
||||||
let right = controller.grip_space(Hand::Right);
|
let right = controller.grip_space(Hand::Right);
|
||||||
let right_postion = right.0.pose.position.to_vec3();
|
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_controller_query.get_single_mut().unwrap().0.rotation =
|
||||||
right.0.pose.orientation.to_quat();
|
right.0.pose.orientation.to_quat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user