diff --git a/Cargo.toml b/Cargo.toml index 84e1f119..58c51010 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 diff --git a/examples/xr.rs b/examples/xr.rs index 35d766ad..548fe152 100644 --- a/examples/xr.rs +++ b/examples/xr.rs @@ -2,6 +2,10 @@ use bevy::diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}; use bevy::prelude::*; use bevy::transform::components::Transform; use bevy_openxr::xr_input::debug_gizmos::OpenXrDebugRenderer; +use bevy_openxr::xr_input::prototype_locomotion::{proto_locomotion, PrototypeLocomotionConfig}; +use bevy_openxr::xr_input::trackers::{ + OpenXRController, OpenXRLeftController, OpenXRRightController, OpenXRTracker, +}; use bevy_openxr::DefaultXrPlugins; fn main() { @@ -14,6 +18,9 @@ fn main() { .add_plugins(LogDiagnosticsPlugin::default()) .add_plugins(FrameTimeDiagnosticsPlugin) .add_systems(Startup, setup) + .add_systems(Update, proto_locomotion) + .add_systems(Startup, spawn_controllers_example) + .insert_resource(PrototypeLocomotionConfig::default()) .run(); } @@ -36,6 +43,13 @@ 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() + }); // light commands.spawn(PointLightBundle { point_light: PointLight { @@ -52,3 +66,20 @@ fn setup( ..default() },)); } + +fn spawn_controllers_example(mut commands: Commands) { + //left hand + commands.spawn(( + OpenXRLeftController, + OpenXRController, + OpenXRTracker, + SpatialBundle::default(), + )); + //right hand + commands.spawn(( + OpenXRRightController, + OpenXRController, + OpenXRTracker, + SpatialBundle::default(), + )); +} diff --git a/src/xr_input/debug_gizmos.rs b/src/xr_input/debug_gizmos.rs index 4e96e2cb..5d7432e8 100644 --- a/src/xr_input/debug_gizmos.rs +++ b/src/xr_input/debug_gizmos.rs @@ -1,4 +1,7 @@ -use bevy::prelude::{Color, Gizmos, Plugin, Quat, Res, Transform, Update, Vec2, Vec3}; +use bevy::prelude::{ + info, Color, Gizmos, GlobalTransform, Plugin, Quat, Query, Res, Transform, Update, Vec2, Vec3, + With, Without, +}; use crate::{ input::XrInput, @@ -7,9 +10,11 @@ use crate::{ use crate::xr_input::{ oculus_touch::{OculusController, OculusControllerRef}, - Hand, QuatConv, Vec3Conv, + Hand, }; +use super::trackers::{OpenXRLeftController, OpenXRRightController, OpenXRTrackingRoot}; + /// add debug renderer for controllers #[derive(Default)] pub struct OpenXrDebugRenderer; @@ -27,22 +32,60 @@ pub fn draw_gizmos( xr_input: Res, instance: Res, session: Res, + tracking_root_query: Query<(&mut Transform, With)>, + left_controller_query: Query<( + &GlobalTransform, + With, + Without, + Without, + )>, + right_controller_query: Query<( + &GlobalTransform, + With, + Without, + Without, + )>, ) { //lock frame let frame_state = *frame_state.lock().unwrap(); //get controller let controller = oculus_controller.get_ref(&instance, &session, &frame_state, &xr_input); + //tracking root? + let mut tracking_transform = &Transform::IDENTITY; + let root = tracking_root_query.get_single(); + match root { + Ok(position) => { + gizmos.circle( + position.0.translation + + Vec3 { + x: 0.0, + y: 0.01, + z: 0.0, + }, + Vec3::Y, + 0.2, + Color::RED, + ); + tracking_transform = position.0; + } + Err(_) => info!("too many tracking roots"), + } //draw the hands - draw_hand_gizmo(&mut gizmos, &controller, Hand::Right); - draw_hand_gizmo(&mut gizmos, &controller, Hand::Left); + let left_transform = left_controller_query.get_single().unwrap().0; + let right_transform = right_controller_query.get_single().unwrap().0; + + draw_hand_gizmo(&mut gizmos, &controller, Hand::Right, right_transform); + draw_hand_gizmo(&mut gizmos, &controller, Hand::Left, left_transform); } -fn draw_hand_gizmo(gizmos: &mut Gizmos, controller: &OculusControllerRef<'_>, hand: Hand) { +fn draw_hand_gizmo( + gizmos: &mut Gizmos, + controller: &OculusControllerRef<'_>, + hand: Hand, + hand_transform: &GlobalTransform, +) { match hand { Hand::Left => { - //get left controller - let left_controller = controller.grip_space(Hand::Left); - let left_color = Color::YELLOW_GREEN; let off_color = Color::BLUE; let touch_color = Color::GREEN; @@ -50,9 +93,9 @@ fn draw_hand_gizmo(gizmos: &mut Gizmos, controller: &OculusControllerRef<'_>, ha let grip_quat_offset = Quat::from_rotation_x(-1.4); let face_quat_offset = Quat::from_rotation_x(1.05); - - let controller_vec3 = left_controller.0.pose.position.to_vec3(); - let controller_quat = left_controller.0.pose.orientation.to_quat(); + let trans = hand_transform.compute_transform(); + let controller_vec3 = trans.translation; + let controller_quat = trans.rotation; let face_quat = controller_quat.mul_quat(face_quat_offset); let face_quat_normal = face_quat.mul_vec3(Vec3::Z); @@ -149,7 +192,6 @@ fn draw_hand_gizmo(gizmos: &mut Gizmos, controller: &OculusControllerRef<'_>, ha } Hand::Right => { //get right controller - let right_controller = controller.grip_space(Hand::Right); let right_color = Color::YELLOW_GREEN; let off_color = Color::BLUE; let touch_color = Color::GREEN; @@ -158,11 +200,14 @@ fn draw_hand_gizmo(gizmos: &mut Gizmos, controller: &OculusControllerRef<'_>, ha let grip_quat_offset = Quat::from_rotation_x(-1.4); let face_quat_offset = Quat::from_rotation_x(1.05); - let controller_vec3 = right_controller.0.pose.position.to_vec3(); - let controller_quat = right_controller.0.pose.orientation.to_quat(); + let trans = hand_transform.compute_transform(); + let controller_vec3 = trans.translation; + let controller_quat = trans.rotation; let face_quat = controller_quat.mul_quat(face_quat_offset); let face_quat_normal = face_quat.mul_vec3(Vec3::Z); + let squeeze = controller.squeeze(Hand::Right); + //info!("{:?}", squeeze); //grip gizmos.rect( controller_vec3, diff --git a/src/xr_input/mod.rs b/src/xr_input/mod.rs index 70fd1f90..55e7c562 100644 --- a/src/xr_input/mod.rs +++ b/src/xr_input/mod.rs @@ -1,6 +1,8 @@ pub mod controllers; pub mod debug_gizmos; pub mod oculus_touch; +pub mod prototype_locomotion; +pub mod trackers; pub mod xr_camera; use crate::resources::XrSession; @@ -10,12 +12,17 @@ use crate::xr_input::oculus_touch::{setup_oculus_controller, ActionSets}; use crate::xr_input::xr_camera::{xr_camera_head_sync, Eye, XRProjection, XrCameraBundle}; use bevy::app::{App, PostUpdate, Startup}; use bevy::log::warn; -use bevy::prelude::IntoSystemConfigs; -use bevy::prelude::{Commands, Plugin, PreUpdate, Quat, Res, Vec3}; +use bevy::prelude::{BuildChildren, IntoSystemConfigs}; +use bevy::prelude::{Commands, Plugin, PreUpdate, Quat, Res, SpatialBundle, Update, Vec3}; use bevy::render::camera::CameraProjectionPlugin; use bevy::render::view::{update_frusta, VisibilitySystems}; use bevy::transform::TransformSystem; +use self::trackers::{ + adopt_open_xr_trackers, update_open_xr_controllers, OpenXRLeftEye, OpenXRRightEye, + OpenXRTrackingRoot, +}; + #[derive(Copy, Clone)] pub struct OpenXrInput { pub controller_type: XrControllerType, @@ -25,6 +32,7 @@ pub enum Hand { Left, Right, } + impl OpenXrInput { pub fn new(controller_type: XrControllerType) -> Self { Self { controller_type } @@ -39,8 +47,12 @@ impl Plugin for OpenXrInput { app.add_systems(Startup, setup_oculus_controller); } } + //adopt any new trackers + app.add_systems(PreUpdate, adopt_open_xr_trackers); app.add_systems(PreUpdate, action_set_system); app.add_systems(PreUpdate, xr_camera_head_sync.after(xr_begin_frame)); + //update controller trackers + app.add_systems(Update, update_open_xr_controllers); app.add_systems( PostUpdate, update_frusta:: @@ -52,8 +64,18 @@ impl Plugin for OpenXrInput { } fn setup_xr_cameras(mut commands: Commands) { - commands.spawn(XrCameraBundle::new(Eye::Right)); - commands.spawn(XrCameraBundle::new(Eye::Left)); + //this needs to do the whole xr tracking volume not just cameras + //get the root? + let tracking_root = commands + .spawn((SpatialBundle::default(), OpenXRTrackingRoot)) + .id(); + let right = commands + .spawn((XrCameraBundle::new(Eye::Right), OpenXRRightEye)) + .id(); + let left = commands + .spawn((XrCameraBundle::new(Eye::Left), OpenXRLeftEye)) + .id(); + commands.entity(tracking_root).push_children(&[right, left]); } fn action_set_system(action_sets: Res, session: Res) { diff --git a/src/xr_input/prototype_locomotion.rs b/src/xr_input/prototype_locomotion.rs new file mode 100644 index 00000000..615f9fd5 --- /dev/null +++ b/src/xr_input/prototype_locomotion.rs @@ -0,0 +1,188 @@ +use std::f32::consts::PI; + +use bevy::{ + prelude::*, + time::{Time, Timer, TimerMode}, +}; + +use crate::{ + input::XrInput, + resources::{XrFrameState, XrInstance, XrSession, XrViews}, +}; + +use super::{ + oculus_touch::OculusController, trackers::OpenXRTrackingRoot, Hand, QuatConv, Vec3Conv, +}; + +pub enum LocomotionType { + Head, + Hand, +} + +pub enum RotationType { + Smooth, + Snap, +} + +#[derive(Resource)] +pub struct RotationTimer { + pub timer: Timer, +} + +#[derive(Resource)] +pub struct PrototypeLocomotionConfig { + pub locomotion_type: LocomotionType, + pub locomotion_speed: f32, + pub rotation_type: RotationType, + pub snap_angle: f32, + pub smooth_rotation_speed: f32, + pub rotation_stick_deadzone: f32, + pub rotation_timer: RotationTimer, +} + +impl Default for PrototypeLocomotionConfig { + fn default() -> Self { + Self { + locomotion_type: LocomotionType::Hand, + locomotion_speed: 1.0, + rotation_type: RotationType::Smooth, + snap_angle: 45.0 * (PI / 180.0), + smooth_rotation_speed: 0.5 * PI, + rotation_stick_deadzone: 0.2, + rotation_timer: RotationTimer { + timer: Timer::from_seconds(1.0, TimerMode::Once), + }, + } + } +} + +pub fn proto_locomotion( + time: Res