//! A simple 3D scene with light shining over a cube sitting on a plane. use std::ops::Deref; use bevy::prelude::*; use bevy_mod_openxr::{ action_binding::{OxrSendActionBindings, OxrSuggestActionBinding}, action_set_attaching::OxrAttachActionSet, action_set_syncing::{OxrActionSetSyncSet, OxrSyncActionSet}, add_xr_plugins, helper_traits::{ToQuat, ToVec3}, resources::{OxrFrameState, OxrInstance, Pipelined}, session::OxrSession, spaces::{OxrSpaceExt, OxrSpaceLocationFlags, OxrSpaceSyncSet}, }; use bevy_mod_xr::{ session::{session_available, session_running, XrSessionCreated, XrTrackingRoot}, spaces::{XrPrimaryReferenceSpace, XrReferenceSpace, XrSpace}, types::XrPose, }; use bevy_xr_utils::tracking_utils::{ TrackingUtilitiesPlugin, XRTrackedLocalFloor, XRTrackedStage, XRTrackedView, }; use openxr::Posef; fn main() { let mut app = App::new(); app.add_plugins(add_xr_plugins(DefaultPlugins)); app.add_systems(Startup, setup); //create bindings app.add_systems(OxrSendActionBindings, suggest_action_bindings); //sync actions app.add_systems( PreUpdate, sync_actions .before(OxrActionSetSyncSet) .run_if(session_running), ); //things? app.add_systems(XrSessionCreated, spawn_hands); app.add_systems(XrSessionCreated, attach_set); app.add_systems(Startup, create_actions.run_if(session_available)); //tracking utils plugin app.add_plugins(TrackingUtilitiesPlugin); app.run(); } /// set up a simple 3D scene fn setup( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, ) { // circular base commands.spawn(PbrBundle { mesh: meshes.add(Circle::new(4.0)), material: materials.add(Color::WHITE), transform: Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)), ..default() }); // // cube // commands.spawn(PbrBundle { // mesh: meshes.add(Cuboid::new(1.0, 1.0, 1.0)), // material: materials.add(Color::srgb_u8(124, 144, 255)), // transform: Transform::from_xyz(0.0, 0.5, 0.0), // ..default() // }); // light commands.spawn(PointLightBundle { point_light: PointLight { shadows_enabled: true, ..default() }, transform: Transform::from_xyz(4.0, 8.0, 4.0), ..default() }); commands.spawn(Camera3dBundle { transform: Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y), ..default() }); } #[derive(Resource)] struct ControllerActions { set: openxr::ActionSet, left: openxr::Action, right: openxr::Action, } fn suggest_action_bindings( actions: Res, mut bindings: EventWriter, ) { bindings.send(OxrSuggestActionBinding { action: actions.left.as_raw(), interaction_profile: "/interaction_profiles/oculus/touch_controller".into(), bindings: vec!["/user/hand/left/input/grip/pose".into()], }); bindings.send(OxrSuggestActionBinding { action: actions.right.as_raw(), interaction_profile: "/interaction_profiles/oculus/touch_controller".into(), bindings: vec!["/user/hand/right/input/grip/pose".into()], }); } fn sync_actions(actions: Res, mut sync: EventWriter) { sync.send(OxrSyncActionSet(actions.set.clone())); } fn attach_set(actions: Res, mut attach: EventWriter) { attach.send(OxrAttachActionSet(actions.set.clone())); } fn create_actions(instance: Res, mut cmds: Commands) { let set = instance.create_action_set("hands", "Hands", 0).unwrap(); let left = set .create_action("left_pose", "Left Hand Grip Pose", &[]) .unwrap(); let right = set .create_action("right_pose", "Right Hand Grip Pose", &[]) .unwrap(); cmds.insert_resource(ControllerActions { set, left, right }) } fn spawn_hands( actions: Res, mut cmds: Commands, root: Query>, session: Res, mut meshes: ResMut>, mut materials: ResMut>, ) { // This is a demonstation of how to integrate with the openxr crate, the right space is the // recommended way let left_space = XrSpace::from_openxr_space( actions .left .create_space( session.deref().deref().clone(), openxr::Path::NULL, Posef::IDENTITY, ) .unwrap(), ); let right_space = session .create_action_space(&actions.right, openxr::Path::NULL, XrPose::IDENTITY) .unwrap(); let left = cmds .spawn(( PbrBundle { mesh: meshes.add(Cuboid::new(0.1, 0.1, 0.05)), material: materials.add(Color::srgb_u8(124, 144, 255)), transform: Transform::from_xyz(0.0, 0.5, 0.0), ..default() }, left_space, )) .id(); let right = cmds .spawn(( PbrBundle { mesh: meshes.add(Cuboid::new(0.1, 0.1, 0.05)), material: materials.add(Color::srgb_u8(124, 144, 255)), transform: Transform::from_xyz(0.0, 0.5, 0.0), ..default() }, right_space, )) .id(); //head? let head = cmds .spawn(( PbrBundle { mesh: meshes.add(Cuboid::new(0.2, 0.2, 0.2)), material: materials.add(Color::srgb_u8(255, 144, 144)), transform: Transform::from_xyz(0.0, 0.0, 0.0), ..default() }, XRTrackedView, )) .id(); //local_floor? emulated let local_floor = cmds .spawn(( PbrBundle { mesh: meshes.add(Cuboid::new(0.5, 0.1, 0.5)), material: materials.add(Color::srgb_u8(144, 255, 144)), transform: Transform::from_xyz(0.0, 0.0, 0.0), ..default() }, XRTrackedLocalFloor, )) .id(); let rooter = cmds .spawn(( PbrBundle { mesh: meshes.add(Cuboid::new(0.5, 0.1, 0.5)), material: materials.add(Color::srgb_u8(144, 255, 255)), transform: Transform::from_xyz(0.0, 0.0, 0.0), ..default() }, XRTrackedStage, )) .id(); cmds.entity(root.single()) .push_children(&[left, right, head, local_floor]); }