From 77f50812195d0733b0f706133ed2fe94f870e0ad Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Wed, 15 May 2024 13:22:25 -0400 Subject: [PATCH 01/17] first pass at actions --- crates/bevy_openxr/examples/actions.rs | 131 ++++++++++++++++++ .../bevy_openxr/src/openxr/action_binding.rs | 1 + .../src/openxr/action_set_attaching.rs | 25 +++- 3 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 crates/bevy_openxr/examples/actions.rs diff --git a/crates/bevy_openxr/examples/actions.rs b/crates/bevy_openxr/examples/actions.rs new file mode 100644 index 0000000..9ca9be2 --- /dev/null +++ b/crates/bevy_openxr/examples/actions.rs @@ -0,0 +1,131 @@ +// a simple example showing basic actions + +use std::borrow::Cow; + +use bevy::prelude::*; +use bevy_openxr::{ + action_binding::OxrSuggestActionBinding, + action_set_attaching::{AttachedActionSets, OxrAttachActionSet}, + add_xr_plugins, + resources::{OxrInstance, OxrSession}, +}; +use openxr::{ActiveActionSet, Path}; + +fn main() { + App::new() + .add_plugins(add_xr_plugins(DefaultPlugins)) + .add_plugins(bevy_xr_utils::hand_gizmos::HandGizmosPlugin) + .add_systems(Startup, setup_scene) + .add_systems(Startup, create_action) + .init_resource::() + .add_systems(Update, read_action) + .run(); +} + +/// set up a simple 3D scene +fn setup_scene( + 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::rgb_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, Default)] +struct TestAction { + action: Option>, +} + +fn create_action( + mut writer: EventWriter, + instance: ResMut, + mut test: ResMut, + mut set_writer: EventWriter, +) { + let name = "test"; + let pretty_name = "pretty test"; + let priority = u32::MIN; + //create action set + let set: openxr::ActionSet = instance + .create_action_set(name, pretty_name, priority) + .unwrap(); + + let action_name = "action_name"; + let localized_name = "localized_name"; + //create new action from action set + let bool_action: openxr::Action = set + .create_action::(action_name, localized_name, &[]) + .unwrap(); + + //interaction profile + let profile = Cow::from("/interaction_profiles/valve/index_controller"); + //bindings + let binding = vec![Cow::from("/user/hand/right/input/a/click")]; + let sugestion = OxrSuggestActionBinding { + action: bool_action.as_raw(), + interaction_profile: profile, + bindings: binding, + }; + + //finally send the suggestion + writer.send(sugestion); + set_writer.send(OxrAttachActionSet(set.clone())); + + test.action = Some(bool_action); +} + +fn read_action( + session: ResMut, + test: ResMut, + attached: ResMut +) { + //maybe sync before? + let why = &attached.sets.iter().map(|v| ActiveActionSet::from(v)).collect::>(); + let sync = session.sync_actions(&why[..]); + match sync { + Ok(_) =>info!("sync ok"), + Err(_) => error!("sync error"), + } + + + //now check the action? + let action = &test.action; + match action { + Some(act) => { + let thing = act.state(&session, Path::NULL); + match thing { + Ok(a) => { + info!("action state: {:?}", a); + } + Err(_) => info!("error getting state"), + } + } + None => info!("no action"), + } +} \ No newline at end of file diff --git a/crates/bevy_openxr/src/openxr/action_binding.rs b/crates/bevy_openxr/src/openxr/action_binding.rs index a5de40b..f9796c1 100644 --- a/crates/bevy_openxr/src/openxr/action_binding.rs +++ b/crates/bevy_openxr/src/openxr/action_binding.rs @@ -84,6 +84,7 @@ fn bind_actions(instance: Res, mut actions: EventReader error!("Invalid Path Suggested!"), openxr::sys::Result::ERROR_PATH_UNSUPPORTED => error!("Suggested Path Unsupported!"), + openxr::sys::Result::SUCCESS => info!("suggested binding success"), _ => {} } } diff --git a/crates/bevy_openxr/src/openxr/action_set_attaching.rs b/crates/bevy_openxr/src/openxr/action_set_attaching.rs index b788458..781c958 100644 --- a/crates/bevy_openxr/src/openxr/action_set_attaching.rs +++ b/crates/bevy_openxr/src/openxr/action_set_attaching.rs @@ -1,6 +1,7 @@ use crate::resources::OxrSession; use bevy::prelude::*; use bevy_xr::session::status_changed_to; +use openxr::ActionSet; impl Plugin for OxrActionAttachingPlugin { fn build(&self, app: &mut App) { @@ -9,15 +10,28 @@ impl Plugin for OxrActionAttachingPlugin { PostUpdate, attach_sets.run_if(status_changed_to(bevy_xr::session::XrStatus::Ready)), ); + app.init_resource::(); } } -fn attach_sets(session: Res, mut events: EventReader) { +fn attach_sets( + session: Res, + mut events: EventReader, + mut attached: ResMut, +) { let sets = events.read().map(|v| &v.0).collect::>(); - if sets.is_empty() {return;} + if sets.is_empty() { + return; + } info!("attaching {} sessions", sets.len()); match session.attach_action_sets(&sets) { - Ok(_) => {info!("attached sessions!")} + Ok(_) => { + info!("attached sessions!"); + for &set in sets.iter() { + let clone = set.clone(); + attached.sets.push(clone); + } + } Err(openxr::sys::Result::ERROR_ACTIONSETS_ALREADY_ATTACHED) => { error!("Action Sets Already attached!"); } @@ -36,3 +50,8 @@ fn attach_sets(session: Res, mut events: EventReader, +} From db975b06f07303f4808d7ae6d18d0011f7b39d64 Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Thu, 16 May 2024 09:55:49 -0400 Subject: [PATCH 02/17] made strings cows --- crates/bevy_openxr/src/openxr/action_binding.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_openxr/src/openxr/action_binding.rs b/crates/bevy_openxr/src/openxr/action_binding.rs index f9796c1..53a2d9f 100644 --- a/crates/bevy_openxr/src/openxr/action_binding.rs +++ b/crates/bevy_openxr/src/openxr/action_binding.rs @@ -84,7 +84,7 @@ fn bind_actions(instance: Res, mut actions: EventReader error!("Invalid Path Suggested!"), openxr::sys::Result::ERROR_PATH_UNSUPPORTED => error!("Suggested Path Unsupported!"), - openxr::sys::Result::SUCCESS => info!("suggested binding success"), + openxr::sys::Result::SUCCESS => info!("Suggested binding success"), _ => {} } } From f74f701f5012dc726ca5e50e0e2b1905b693d419 Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Thu, 16 May 2024 09:56:04 -0400 Subject: [PATCH 03/17] more cows --- crates/bevy_openxr/examples/actions.rs | 129 +++++++++++++++++++++++-- 1 file changed, 121 insertions(+), 8 deletions(-) diff --git a/crates/bevy_openxr/examples/actions.rs b/crates/bevy_openxr/examples/actions.rs index 9ca9be2..16b0d9b 100644 --- a/crates/bevy_openxr/examples/actions.rs +++ b/crates/bevy_openxr/examples/actions.rs @@ -2,23 +2,25 @@ use std::borrow::Cow; -use bevy::prelude::*; +use bevy::{prelude::*, utils::hashbrown::HashMap}; use bevy_openxr::{ action_binding::OxrSuggestActionBinding, action_set_attaching::{AttachedActionSets, OxrAttachActionSet}, add_xr_plugins, resources::{OxrInstance, OxrSession}, }; -use openxr::{ActiveActionSet, Path}; +use openxr::{ActionType, ActiveActionSet, Path}; fn main() { App::new() .add_plugins(add_xr_plugins(DefaultPlugins)) .add_plugins(bevy_xr_utils::hand_gizmos::HandGizmosPlugin) .add_systems(Startup, setup_scene) - .add_systems(Startup, create_action) .init_resource::() .add_systems(Update, read_action) + // .add_systems(Startup, create_action) + .add_systems(Startup, create_action_entities) + .add_systems(Startup, create_openxr_events.after(create_action_entities)) .run(); } @@ -103,17 +105,20 @@ fn create_action( fn read_action( session: ResMut, test: ResMut, - attached: ResMut + attached: ResMut, ) { //maybe sync before? - let why = &attached.sets.iter().map(|v| ActiveActionSet::from(v)).collect::>(); + let why = &attached + .sets + .iter() + .map(|v| ActiveActionSet::from(v)) + .collect::>(); let sync = session.sync_actions(&why[..]); match sync { - Ok(_) =>info!("sync ok"), + Ok(_) => info!("sync ok"), Err(_) => error!("sync error"), } - //now check the action? let action = &test.action; match action { @@ -128,4 +133,112 @@ fn read_action( } None => info!("no action"), } -} \ No newline at end of file +} + +#[derive(Component)] +struct CreateActionSet { + name: Cow<'static, str>, + pretty_name: Cow<'static, str>, + priority: u32, +} + +#[derive(Component)] +struct CreateAction { + action_name: Cow<'static, str>, + localized_name: Cow<'static, str>, + action_type: ActionType, +} + +#[derive(Component)] +struct CreateBinding { + profile: Cow<'static, str>, + binding: Cow<'static, str>, +} + +fn create_action_entities(mut commands: Commands) { + //create a set + let set = commands + .spawn(CreateActionSet { + name: "test".into(), + pretty_name: "pretty test".into(), + priority: u32::MIN, + }) + .id(); + //create an action + let action = commands + .spawn(CreateAction { + action_name: "action_name".into(), + localized_name: "localized_name".into(), + action_type: ActionType::BOOLEAN_INPUT, + }) + .id(); + + //create a binding + let binding = commands + .spawn(CreateBinding { + profile: "/interaction_profiles/valve/index_controller".into(), + binding: "/user/hand/right/input/a/click".into(), + }) + .id(); + + //add action to set, this isnt the best + //TODO look into a better system + commands.entity(action).add_child(binding); + commands.entity(set).add_child(action); +} + +fn create_openxr_events( + ActionSetsQuery: Query<(&CreateActionSet, &Children)>, + ActionsQuery: Query<(&CreateAction, &Children)>, + BindingsQuery: Query<&CreateBinding>, + instance: ResMut, + mut binding_writer: EventWriter, + mut attach_writer: EventWriter, + //please remove this + mut test: ResMut, +) { + //lets create some sets! + //we gonna need a collection of these sets for later + // let mut ActionSets = HashMap::new(); + for (set, children) in ActionSetsQuery.iter() { + //create action set + let action_set: openxr::ActionSet = instance + .create_action_set(&set.name, &set.pretty_name, set.priority) + .unwrap(); + + // ActionSets.insert(set.name.clone(), action_set); + //since the actions are made from the sets lets go + for &child in children.iter() { + //first get the action entity and stuff + let (create_action, bindings) = ActionsQuery.get(child).unwrap(); + //lets create dat actions + let bool_action: openxr::Action = action_set + .create_action::( + &create_action.action_name, + &create_action.localized_name, + &[], + ) + .unwrap(); + //TODO remove this crap + test.action = Some(bool_action.clone()); + //since we need actions for bindings lets go!! + for &bind in bindings.iter() { + //interaction profile + //get the binding entity and stuff + let create_binding = BindingsQuery.get(bind).unwrap(); + let profile = Cow::from(create_binding.profile.clone()); + //bindings + let binding = vec![Cow::from(create_binding.binding.clone())]; + let sugestion = OxrSuggestActionBinding { + action: bool_action.as_raw(), + interaction_profile: profile, + bindings: binding, + }; + //finally send the suggestion + binding_writer.send(sugestion); + } + } + + attach_writer.send(OxrAttachActionSet(action_set)); + } +} From 20e3a1cf7a7aa094d02d07ca61213f62f0641739 Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Thu, 16 May 2024 12:45:18 -0400 Subject: [PATCH 04/17] confirmed working for bools and f32 --- crates/bevy_openxr/examples/actions.rs | 179 ++++++++++++++----------- 1 file changed, 101 insertions(+), 78 deletions(-) diff --git a/crates/bevy_openxr/examples/actions.rs b/crates/bevy_openxr/examples/actions.rs index 16b0d9b..f45e49f 100644 --- a/crates/bevy_openxr/examples/actions.rs +++ b/crates/bevy_openxr/examples/actions.rs @@ -2,14 +2,14 @@ use std::borrow::Cow; -use bevy::{prelude::*, utils::hashbrown::HashMap}; +use bevy::{prelude::*, scene::ron::value::Float}; use bevy_openxr::{ action_binding::OxrSuggestActionBinding, action_set_attaching::{AttachedActionSets, OxrAttachActionSet}, add_xr_plugins, resources::{OxrInstance, OxrSession}, }; -use openxr::{ActionType, ActiveActionSet, Path}; +use openxr::{ActionType, ActiveActionSet, Path, Vector2f}; fn main() { App::new() @@ -18,7 +18,6 @@ fn main() { .add_systems(Startup, setup_scene) .init_resource::() .add_systems(Update, read_action) - // .add_systems(Startup, create_action) .add_systems(Startup, create_action_entities) .add_systems(Startup, create_openxr_events.after(create_action_entities)) .run(); @@ -61,45 +60,7 @@ fn setup_scene( #[derive(Resource, Default)] struct TestAction { - action: Option>, -} - -fn create_action( - mut writer: EventWriter, - instance: ResMut, - mut test: ResMut, - mut set_writer: EventWriter, -) { - let name = "test"; - let pretty_name = "pretty test"; - let priority = u32::MIN; - //create action set - let set: openxr::ActionSet = instance - .create_action_set(name, pretty_name, priority) - .unwrap(); - - let action_name = "action_name"; - let localized_name = "localized_name"; - //create new action from action set - let bool_action: openxr::Action = set - .create_action::(action_name, localized_name, &[]) - .unwrap(); - - //interaction profile - let profile = Cow::from("/interaction_profiles/valve/index_controller"); - //bindings - let binding = vec![Cow::from("/user/hand/right/input/a/click")]; - let sugestion = OxrSuggestActionBinding { - action: bool_action.as_raw(), - interaction_profile: profile, - bindings: binding, - }; - - //finally send the suggestion - writer.send(sugestion); - set_writer.send(OxrAttachActionSet(set.clone())); - - test.action = Some(bool_action); + action: Option>, } fn read_action( @@ -107,7 +68,7 @@ fn read_action( test: ResMut, attached: ResMut, ) { - //maybe sync before? + //sync before let why = &attached .sets .iter() @@ -119,7 +80,7 @@ fn read_action( Err(_) => error!("sync error"), } - //now check the action? + //now check the action let action = &test.action; match action { Some(act) => { @@ -146,7 +107,7 @@ struct CreateActionSet { struct CreateAction { action_name: Cow<'static, str>, localized_name: Cow<'static, str>, - action_type: ActionType, + action_type: bevy_xr::actions::ActionType, } #[derive(Component)] @@ -169,7 +130,7 @@ fn create_action_entities(mut commands: Commands) { .spawn(CreateAction { action_name: "action_name".into(), localized_name: "localized_name".into(), - action_type: ActionType::BOOLEAN_INPUT, + action_type: bevy_xr::actions::ActionType::Float, }) .id(); @@ -177,7 +138,7 @@ fn create_action_entities(mut commands: Commands) { let binding = commands .spawn(CreateBinding { profile: "/interaction_profiles/valve/index_controller".into(), - binding: "/user/hand/right/input/a/click".into(), + binding: "/user/hand/right/input/thumbstick/y".into(), }) .id(); @@ -188,9 +149,9 @@ fn create_action_entities(mut commands: Commands) { } fn create_openxr_events( - ActionSetsQuery: Query<(&CreateActionSet, &Children)>, - ActionsQuery: Query<(&CreateAction, &Children)>, - BindingsQuery: Query<&CreateBinding>, + action_sets_query: Query<(&CreateActionSet, &Children)>, + actions_query: Query<(&CreateAction, &Children)>, + bindings_query: Query<&CreateBinding>, instance: ResMut, mut binding_writer: EventWriter, mut attach_writer: EventWriter, @@ -200,43 +161,105 @@ fn create_openxr_events( //lets create some sets! //we gonna need a collection of these sets for later // let mut ActionSets = HashMap::new(); - for (set, children) in ActionSetsQuery.iter() { + for (set, children) in action_sets_query.iter() { //create action set let action_set: openxr::ActionSet = instance .create_action_set(&set.name, &set.pretty_name, set.priority) .unwrap(); - // ActionSets.insert(set.name.clone(), action_set); //since the actions are made from the sets lets go for &child in children.iter() { //first get the action entity and stuff - let (create_action, bindings) = ActionsQuery.get(child).unwrap(); + let (create_action, bindings) = actions_query.get(child).unwrap(); //lets create dat actions - let bool_action: openxr::Action = action_set - .create_action::( - &create_action.action_name, - &create_action.localized_name, - &[], - ) - .unwrap(); - //TODO remove this crap - test.action = Some(bool_action.clone()); - //since we need actions for bindings lets go!! - for &bind in bindings.iter() { - //interaction profile - //get the binding entity and stuff - let create_binding = BindingsQuery.get(bind).unwrap(); - let profile = Cow::from(create_binding.profile.clone()); - //bindings - let binding = vec![Cow::from(create_binding.binding.clone())]; - let sugestion = OxrSuggestActionBinding { - action: bool_action.as_raw(), - interaction_profile: profile, - bindings: binding, - }; - //finally send the suggestion - binding_writer.send(sugestion); - } + match create_action.action_type { + bevy_xr::actions::ActionType::Bool => { + let action: openxr::Action = action_set + .create_action::( + &create_action.action_name, + &create_action.localized_name, + &[], + ) + .unwrap(); + //please put this in a function so I dont go crazy + //TODO remove this crap + // test.action = Some(action.clone()); + //since we need actions for bindings lets go!! + for &bind in bindings.iter() { + //interaction profile + //get the binding entity and stuff + let create_binding = bindings_query.get(bind).unwrap(); + let profile = Cow::from(create_binding.profile.clone()); + //bindings + let binding = vec![Cow::from(create_binding.binding.clone())]; + let sugestion = OxrSuggestActionBinding { + action: action.as_raw(), + interaction_profile: profile, + bindings: binding, + }; + //finally send the suggestion + binding_writer.send(sugestion); + } + } + bevy_xr::actions::ActionType::Float => { + let action: openxr::Action = action_set + .create_action::( + &create_action.action_name, + &create_action.localized_name, + &[], + ) + .unwrap(); + + //please put this in a function so I dont go crazy + //TODO remove this crap + test.action = Some(action.clone()); + //since we need actions for bindings lets go!! + for &bind in bindings.iter() { + //interaction profile + //get the binding entity and stuff + let create_binding = bindings_query.get(bind).unwrap(); + let profile = Cow::from(create_binding.profile.clone()); + //bindings + let binding = vec![Cow::from(create_binding.binding.clone())]; + let sugestion = OxrSuggestActionBinding { + action: action.as_raw(), + interaction_profile: profile, + bindings: binding, + }; + //finally send the suggestion + binding_writer.send(sugestion); + } + } + bevy_xr::actions::ActionType::Vector => { + let action: openxr::Action = action_set + .create_action::( + &create_action.action_name, + &create_action.localized_name, + &[], + ) + .unwrap(); + + //please put this in a function so I dont go crazy + //TODO remove this crap + // test.action = Some(action.clone()); + //since we need actions for bindings lets go!! + for &bind in bindings.iter() { + //interaction profile + //get the binding entity and stuff + let create_binding = bindings_query.get(bind).unwrap(); + let profile = Cow::from(create_binding.profile.clone()); + //bindings + let binding = vec![Cow::from(create_binding.binding.clone())]; + let sugestion = OxrSuggestActionBinding { + action: action.as_raw(), + interaction_profile: profile, + bindings: binding, + }; + //finally send the suggestion + binding_writer.send(sugestion); + } + } + }; } attach_writer.send(OxrAttachActionSet(action_set)); From 4e279e3197f9ff9e51a6dbf30824975bd7bdfdc2 Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Thu, 16 May 2024 13:08:37 -0400 Subject: [PATCH 05/17] reading inputs with marker components --- crates/bevy_openxr/examples/actions.rs | 111 +++++++++++++------------ 1 file changed, 60 insertions(+), 51 deletions(-) diff --git a/crates/bevy_openxr/examples/actions.rs b/crates/bevy_openxr/examples/actions.rs index f45e49f..9c9ca71 100644 --- a/crates/bevy_openxr/examples/actions.rs +++ b/crates/bevy_openxr/examples/actions.rs @@ -2,22 +2,21 @@ use std::borrow::Cow; -use bevy::{prelude::*, scene::ron::value::Float}; +use bevy::prelude::*; use bevy_openxr::{ action_binding::OxrSuggestActionBinding, action_set_attaching::{AttachedActionSets, OxrAttachActionSet}, add_xr_plugins, resources::{OxrInstance, OxrSession}, }; -use openxr::{ActionType, ActiveActionSet, Path, Vector2f}; +use openxr::{ActiveActionSet, Path, Vector2f}; fn main() { App::new() .add_plugins(add_xr_plugins(DefaultPlugins)) .add_plugins(bevy_xr_utils::hand_gizmos::HandGizmosPlugin) .add_systems(Startup, setup_scene) - .init_resource::() - .add_systems(Update, read_action) + .add_systems(Update, read_action_with_marker_component) .add_systems(Startup, create_action_entities) .add_systems(Startup, create_openxr_events.after(create_action_entities)) .run(); @@ -58,44 +57,6 @@ fn setup_scene( }); } -#[derive(Resource, Default)] -struct TestAction { - action: Option>, -} - -fn read_action( - session: ResMut, - test: ResMut, - attached: ResMut, -) { - //sync before - let why = &attached - .sets - .iter() - .map(|v| ActiveActionSet::from(v)) - .collect::>(); - let sync = session.sync_actions(&why[..]); - match sync { - Ok(_) => info!("sync ok"), - Err(_) => error!("sync error"), - } - - //now check the action - let action = &test.action; - match action { - Some(act) => { - let thing = act.state(&session, Path::NULL); - match thing { - Ok(a) => { - info!("action state: {:?}", a); - } - Err(_) => info!("error getting state"), - } - } - None => info!("no action"), - } -} - #[derive(Component)] struct CreateActionSet { name: Cow<'static, str>, @@ -116,6 +77,14 @@ struct CreateBinding { binding: Cow<'static, str>, } +#[derive(Component)] +struct ActionReference { + action: openxr::Action, +} + +#[derive(Component)] +struct CustomActionMarker; + fn create_action_entities(mut commands: Commands) { //create a set let set = commands @@ -127,11 +96,14 @@ fn create_action_entities(mut commands: Commands) { .id(); //create an action let action = commands - .spawn(CreateAction { - action_name: "action_name".into(), - localized_name: "localized_name".into(), - action_type: bevy_xr::actions::ActionType::Float, - }) + .spawn(( + CreateAction { + action_name: "action_name".into(), + localized_name: "localized_name".into(), + action_type: bevy_xr::actions::ActionType::Float, + }, + CustomActionMarker, //lets try a marker component + )) .id(); //create a binding @@ -155,8 +127,8 @@ fn create_openxr_events( instance: ResMut, mut binding_writer: EventWriter, mut attach_writer: EventWriter, - //please remove this - mut test: ResMut, + //not my favorite way of doing this + mut commands: Commands, ) { //lets create some sets! //we gonna need a collection of these sets for later @@ -211,8 +183,10 @@ fn create_openxr_events( .unwrap(); //please put this in a function so I dont go crazy - //TODO remove this crap - test.action = Some(action.clone()); + //insert a reference for later + commands.entity(child).insert(ActionReference { + action: action.clone(), + }); //since we need actions for bindings lets go!! for &bind in bindings.iter() { //interaction profile @@ -265,3 +239,38 @@ fn create_openxr_events( attach_writer.send(OxrAttachActionSet(action_set)); } } + +fn read_action_with_marker_component( + action_query: Query<&ActionReference, With>, + session: ResMut, + attached: ResMut, +) { + //first we need to sync our actions + let why = &attached + .sets + .iter() + .map(|v| ActiveActionSet::from(v)) + .collect::>(); + let sync = session.sync_actions(&why[..]); + match sync { + Ok(_) => info!("sync ok"), + Err(_) => error!("sync error"), + } + + //now for the actual checking + let action = action_query.get_single(); + match action { + Ok(reference) => { + let state = reference.action.state(&session, Path::NULL); + match state { + Ok(a) => { + info!("action state: {:?}", a); + } + Err(_) => info!("error getting state"), + } + } + Err(_) => { + info!("no action") + } + } +} From 0edf8cf9fe2417c46f049a09edbfe90757146cd9 Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Wed, 22 May 2024 22:38:38 -0400 Subject: [PATCH 06/17] more changes --- crates/bevy_openxr/examples/actions.rs | 198 +++++++++++++++++++++---- crates/bevy_xr/src/actions.rs | 1 + 2 files changed, 171 insertions(+), 28 deletions(-) diff --git a/crates/bevy_openxr/examples/actions.rs b/crates/bevy_openxr/examples/actions.rs index 9c9ca71..5011da9 100644 --- a/crates/bevy_openxr/examples/actions.rs +++ b/crates/bevy_openxr/examples/actions.rs @@ -16,9 +16,18 @@ fn main() { .add_plugins(add_xr_plugins(DefaultPlugins)) .add_plugins(bevy_xr_utils::hand_gizmos::HandGizmosPlugin) .add_systems(Startup, setup_scene) - .add_systems(Update, read_action_with_marker_component) .add_systems(Startup, create_action_entities) .add_systems(Startup, create_openxr_events.after(create_action_entities)) + .add_systems(Update, sync_actions) + .add_systems( + Update, + sync_and_update_action_states_f32.after(sync_actions), + ) + .add_systems( + Update, + sync_and_update_action_states_bool.after(sync_actions), + ) + .add_systems(Update, read_action_with_marker_component.after(sync_and_update_action_states_f32)) .run(); } @@ -78,10 +87,20 @@ struct CreateBinding { } #[derive(Component)] -struct ActionReference { +struct Actionf32Reference { action: openxr::Action, } +#[derive(Component)] +struct ActionBooleference { + action: openxr::Action, +} + +#[derive(Component)] +struct ActionVector2fReference { + action: openxr::Action, +} + #[derive(Component)] struct CustomActionMarker; @@ -118,6 +137,31 @@ fn create_action_entities(mut commands: Commands) { //TODO look into a better system commands.entity(action).add_child(binding); commands.entity(set).add_child(action); + + //create an action + let action = commands + .spawn(( + CreateAction { + action_name: "action_name_bool".into(), + localized_name: "localized_name_bool".into(), + action_type: bevy_xr::actions::ActionType::Bool, + }, + CustomActionMarker, //lets try a marker component + )) + .id(); + + //create a binding + let binding = commands + .spawn(CreateBinding { + profile: "/interaction_profiles/valve/index_controller".into(), + binding: "/user/hand/right/input/a/click".into(), + }) + .id(); + + //add action to set, this isnt the best + //TODO look into a better system + commands.entity(action).add_child(binding); + commands.entity(set).add_child(action); } fn create_openxr_events( @@ -154,8 +198,18 @@ fn create_openxr_events( ) .unwrap(); //please put this in a function so I dont go crazy - //TODO remove this crap - // test.action = Some(action.clone()); + //insert a reference for later + commands.entity(child).insert(( + ActionBooleference { + action: action.clone(), + }, + MyActionState::Bool(ActionStateBool { + current_state: false, + changed_since_last_sync: false, + last_change_time: i64::MIN, + is_active: false, + }), + )); //since we need actions for bindings lets go!! for &bind in bindings.iter() { //interaction profile @@ -184,9 +238,17 @@ fn create_openxr_events( //please put this in a function so I dont go crazy //insert a reference for later - commands.entity(child).insert(ActionReference { - action: action.clone(), - }); + commands.entity(child).insert(( + Actionf32Reference { + action: action.clone(), + }, + MyActionState::Float(ActionStateFloat { + current_state: 0.0, + changed_since_last_sync: false, + last_change_time: i64::MIN, + is_active: false, + }), + )); //since we need actions for bindings lets go!! for &bind in bindings.iter() { //interaction profile @@ -214,8 +276,18 @@ fn create_openxr_events( .unwrap(); //please put this in a function so I dont go crazy - //TODO remove this crap - // test.action = Some(action.clone()); + //insert a reference for later + commands.entity(child).insert(( + ActionVector2fReference { + action: action.clone(), + }, + MyActionState::Vector(ActionStateVector { + current_state: [0.0, 0.0], + changed_since_last_sync: false, + last_change_time: i64::MIN, + is_active: false, + }), + )); //since we need actions for bindings lets go!! for &bind in bindings.iter() { //interaction profile @@ -240,11 +312,7 @@ fn create_openxr_events( } } -fn read_action_with_marker_component( - action_query: Query<&ActionReference, With>, - session: ResMut, - attached: ResMut, -) { +fn sync_actions(session: Res, attached: Res) { //first we need to sync our actions let why = &attached .sets @@ -256,21 +324,95 @@ fn read_action_with_marker_component( Ok(_) => info!("sync ok"), Err(_) => error!("sync error"), } - - //now for the actual checking - let action = action_query.get_single(); - match action { - Ok(reference) => { - let state = reference.action.state(&session, Path::NULL); - match state { - Ok(a) => { - info!("action state: {:?}", a); - } - Err(_) => info!("error getting state"), +} + +fn sync_and_update_action_states_f32( + session: Res, + mut f32_query: Query<(&Actionf32Reference, &mut MyActionState)>, +) { + //now we do the action state for f32 + for (reference, mut silly_state) in f32_query.iter_mut() { + let state = reference.action.state(&session, Path::NULL); + match state { + Ok(s) => { + info!("we found a state"); + let new_state = MyActionState::Float(ActionStateFloat { + current_state: s.current_state, + changed_since_last_sync: s.changed_since_last_sync, + last_change_time: s.last_change_time.as_nanos(), + is_active: s.is_active, + }); + + *silly_state = new_state; + } + Err(_) => { + info!("error getting action state"); } - } - Err(_) => { - info!("no action") } } } + +fn sync_and_update_action_states_bool( + session: Res, + mut f32_query: Query<(&ActionBooleference, &mut MyActionState)>, +) { + //now we do the action state for f32 + for (reference, mut silly_state) in f32_query.iter_mut() { + let state = reference.action.state(&session, Path::NULL); + match state { + Ok(s) => { + info!("we found a state"); + let new_state = MyActionState::Bool(ActionStateBool { + current_state: s.current_state, + changed_since_last_sync: s.changed_since_last_sync, + last_change_time: s.last_change_time.as_nanos(), + is_active: s.is_active, + }); + + *silly_state = new_state; + } + Err(_) => { + info!("error getting action state"); + } + } + } +} + +fn read_action_with_marker_component( + mut action_query: Query<&MyActionState, With>, +) { + //now for the actual checking + for state in action_query.iter_mut() { + info!("action state is: {:?}", state); + } +} + +//the things i do for bad prototyping and lack of understanding +#[derive(Component, Debug)] +pub enum MyActionState { + Bool(ActionStateBool), + Float(ActionStateFloat), + Vector(ActionStateVector), +} + +#[derive(Debug)] +pub struct ActionStateBool { + pub current_state: bool, + pub changed_since_last_sync: bool, + pub last_change_time: i64, + pub is_active: bool, +} +#[derive(Debug)] +pub struct ActionStateFloat { + pub current_state: f32, + pub changed_since_last_sync: bool, + pub last_change_time: i64, + pub is_active: bool, +} +#[derive(Debug)] +pub struct ActionStateVector { + pub current_state: [f32; 2], + pub changed_since_last_sync: bool, + pub last_change_time: i64, + pub is_active: bool, +} diff --git a/crates/bevy_xr/src/actions.rs b/crates/bevy_xr/src/actions.rs index cb256cb..b73fa6d 100644 --- a/crates/bevy_xr/src/actions.rs +++ b/crates/bevy_xr/src/actions.rs @@ -21,6 +21,7 @@ impl Plugin for ActionPlugin { } } +#[derive(Debug)] pub enum ActionType { Bool, Float, From 99b11eb675f0b350277018a5ad80877f3e9eb08b Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Wed, 22 May 2024 23:18:23 -0400 Subject: [PATCH 07/17] got vectors working --- crates/bevy_openxr/examples/actions.rs | 134 +++++++++++++++++-------- 1 file changed, 92 insertions(+), 42 deletions(-) diff --git a/crates/bevy_openxr/examples/actions.rs b/crates/bevy_openxr/examples/actions.rs index 5011da9..0aed586 100644 --- a/crates/bevy_openxr/examples/actions.rs +++ b/crates/bevy_openxr/examples/actions.rs @@ -5,7 +5,7 @@ use std::borrow::Cow; use bevy::prelude::*; use bevy_openxr::{ action_binding::OxrSuggestActionBinding, - action_set_attaching::{AttachedActionSets, OxrAttachActionSet}, + action_set_attaching::OxrAttachActionSet, add_xr_plugins, resources::{OxrInstance, OxrSession}, }; @@ -18,16 +18,24 @@ fn main() { .add_systems(Startup, setup_scene) .add_systems(Startup, create_action_entities) .add_systems(Startup, create_openxr_events.after(create_action_entities)) - .add_systems(Update, sync_actions) + .add_systems(Update, sync_active_action_sets) .add_systems( Update, - sync_and_update_action_states_f32.after(sync_actions), + sync_and_update_action_states_f32.after(sync_active_action_sets), ) .add_systems( Update, - sync_and_update_action_states_bool.after(sync_actions), + sync_and_update_action_states_bool.after(sync_active_action_sets), ) - .add_systems(Update, read_action_with_marker_component.after(sync_and_update_action_states_f32)) + .add_systems( + Update, + sync_and_update_action_states_vector.after(sync_active_action_sets), + ) + .add_systems( + Update, + read_action_with_marker_component.after(sync_and_update_action_states_f32), + ) + .run(); } @@ -73,6 +81,15 @@ struct CreateActionSet { priority: u32, } +#[derive(Component, Clone)] +struct OXRActionSet(openxr::ActionSet); + +#[derive(Component)] +struct AttachedActionSet; + +#[derive(Component)] +struct ActiveSet; + #[derive(Component)] struct CreateAction { action_name: Cow<'static, str>, @@ -107,11 +124,14 @@ struct CustomActionMarker; fn create_action_entities(mut commands: Commands) { //create a set let set = commands - .spawn(CreateActionSet { - name: "test".into(), - pretty_name: "pretty test".into(), - priority: u32::MIN, - }) + .spawn(( + CreateActionSet { + name: "test".into(), + pretty_name: "pretty test".into(), + priority: u32::MIN, + }, + ActiveSet, //marker to indicate we want this synced + )) .id(); //create an action let action = commands @@ -119,7 +139,7 @@ fn create_action_entities(mut commands: Commands) { CreateAction { action_name: "action_name".into(), localized_name: "localized_name".into(), - action_type: bevy_xr::actions::ActionType::Float, + action_type: bevy_xr::actions::ActionType::Vector, }, CustomActionMarker, //lets try a marker component )) @@ -129,7 +149,7 @@ fn create_action_entities(mut commands: Commands) { let binding = commands .spawn(CreateBinding { profile: "/interaction_profiles/valve/index_controller".into(), - binding: "/user/hand/right/input/thumbstick/y".into(), + binding: "/user/hand/right/input/thumbstick".into(), }) .id(); @@ -138,34 +158,34 @@ fn create_action_entities(mut commands: Commands) { commands.entity(action).add_child(binding); commands.entity(set).add_child(action); - //create an action - let action = commands - .spawn(( - CreateAction { - action_name: "action_name_bool".into(), - localized_name: "localized_name_bool".into(), - action_type: bevy_xr::actions::ActionType::Bool, - }, - CustomActionMarker, //lets try a marker component - )) - .id(); + // //create an action + // let action = commands + // .spawn(( + // CreateAction { + // action_name: "action_name_bool".into(), + // localized_name: "localized_name_bool".into(), + // action_type: bevy_xr::actions::ActionType::Bool, + // }, + // CustomActionMarker, //lets try a marker component + // )) + // .id(); - //create a binding - let binding = commands - .spawn(CreateBinding { - profile: "/interaction_profiles/valve/index_controller".into(), - binding: "/user/hand/right/input/a/click".into(), - }) - .id(); + // //create a binding + // let binding = commands + // .spawn(CreateBinding { + // profile: "/interaction_profiles/valve/index_controller".into(), + // binding: "/user/hand/right/input/a/click".into(), + // }) + // .id(); - //add action to set, this isnt the best - //TODO look into a better system - commands.entity(action).add_child(binding); - commands.entity(set).add_child(action); + // //add action to set, this isnt the best + // //TODO look into a better system + // commands.entity(action).add_child(binding); + // commands.entity(set).add_child(action); } fn create_openxr_events( - action_sets_query: Query<(&CreateActionSet, &Children)>, + action_sets_query: Query<(&CreateActionSet, &Children, Entity)>, actions_query: Query<(&CreateAction, &Children)>, bindings_query: Query<&CreateBinding>, instance: ResMut, @@ -177,11 +197,14 @@ fn create_openxr_events( //lets create some sets! //we gonna need a collection of these sets for later // let mut ActionSets = HashMap::new(); - for (set, children) in action_sets_query.iter() { + for (set, children, id) in action_sets_query.iter() { //create action set let action_set: openxr::ActionSet = instance .create_action_set(&set.name, &set.pretty_name, set.priority) .unwrap(); + //now that we have the action set we need to put it back onto the entity for later + let oxr_action_set = OXRActionSet(action_set.clone()); + commands.entity(id).insert(oxr_action_set); //since the actions are made from the sets lets go for &child in children.iter() { @@ -312,14 +335,15 @@ fn create_openxr_events( } } -fn sync_actions(session: Res, attached: Res) { - //first we need to sync our actions - let why = &attached - .sets +fn sync_active_action_sets( + session: Res, + active_action_set_query: Query<&OXRActionSet, With>, +) { + let active_sets = active_action_set_query .iter() - .map(|v| ActiveActionSet::from(v)) + .map(|v| ActiveActionSet::from(&v.0)) .collect::>(); - let sync = session.sync_actions(&why[..]); + let sync = session.sync_actions(&active_sets[..]); match sync { Ok(_) => info!("sync ok"), Err(_) => error!("sync error"), @@ -378,6 +402,32 @@ fn sync_and_update_action_states_bool( } } +fn sync_and_update_action_states_vector( + session: Res, + mut vector_query: Query<(&ActionVector2fReference, &mut MyActionState)>, +) { + //now we do the action state for f32 + for (reference, mut silly_state) in vector_query.iter_mut() { + let state = reference.action.state(&session, Path::NULL); + match state { + Ok(s) => { + info!("we found a state"); + let new_state = MyActionState::Vector(ActionStateVector { + current_state: [s.current_state.x, s.current_state.y], + changed_since_last_sync: s.changed_since_last_sync, + last_change_time: s.last_change_time.as_nanos(), + is_active: s.is_active, + }); + + *silly_state = new_state; + } + Err(_) => { + info!("error getting action state"); + } + } + } +} + fn read_action_with_marker_component( mut action_query: Query<&MyActionState, With>, ) { From 468610c26e40175b1da41642b533665e3ff7480d Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Wed, 22 May 2024 23:45:55 -0400 Subject: [PATCH 08/17] movement happens but is wrong, its global --- crates/bevy_openxr/examples/actions.rs | 88 +++++++++++++++----------- 1 file changed, 52 insertions(+), 36 deletions(-) diff --git a/crates/bevy_openxr/examples/actions.rs b/crates/bevy_openxr/examples/actions.rs index 0aed586..df6953f 100644 --- a/crates/bevy_openxr/examples/actions.rs +++ b/crates/bevy_openxr/examples/actions.rs @@ -2,11 +2,12 @@ use std::borrow::Cow; -use bevy::prelude::*; +use bevy::{math::vec3, prelude::*}; use bevy_openxr::{ action_binding::OxrSuggestActionBinding, action_set_attaching::OxrAttachActionSet, add_xr_plugins, + init::OxrTrackingRoot, resources::{OxrInstance, OxrSession}, }; use openxr::{ActiveActionSet, Path, Vector2f}; @@ -35,7 +36,10 @@ fn main() { Update, read_action_with_marker_component.after(sync_and_update_action_states_f32), ) - + .add_systems( + Update, + handle_flight_input.after(sync_and_update_action_states_f32), + ) .run(); } @@ -84,8 +88,9 @@ struct CreateActionSet { #[derive(Component, Clone)] struct OXRActionSet(openxr::ActionSet); -#[derive(Component)] -struct AttachedActionSet; +//I want to use this to indicate when an action set is attached +// #[derive(Component)] +// struct AttachedActionSet; #[derive(Component)] struct ActiveSet; @@ -119,15 +124,15 @@ struct ActionVector2fReference { } #[derive(Component)] -struct CustomActionMarker; +struct FlightActionMarker; fn create_action_entities(mut commands: Commands) { //create a set let set = commands .spawn(( CreateActionSet { - name: "test".into(), - pretty_name: "pretty test".into(), + name: "flight".into(), + pretty_name: "pretty flight set".into(), priority: u32::MIN, }, ActiveSet, //marker to indicate we want this synced @@ -137,11 +142,11 @@ fn create_action_entities(mut commands: Commands) { let action = commands .spawn(( CreateAction { - action_name: "action_name".into(), - localized_name: "localized_name".into(), + action_name: "flight_input".into(), + localized_name: "flight_input_localized".into(), action_type: bevy_xr::actions::ActionType::Vector, }, - CustomActionMarker, //lets try a marker component + FlightActionMarker, //lets try a marker component )) .id(); @@ -157,31 +162,6 @@ fn create_action_entities(mut commands: Commands) { //TODO look into a better system commands.entity(action).add_child(binding); commands.entity(set).add_child(action); - - // //create an action - // let action = commands - // .spawn(( - // CreateAction { - // action_name: "action_name_bool".into(), - // localized_name: "localized_name_bool".into(), - // action_type: bevy_xr::actions::ActionType::Bool, - // }, - // CustomActionMarker, //lets try a marker component - // )) - // .id(); - - // //create a binding - // let binding = commands - // .spawn(CreateBinding { - // profile: "/interaction_profiles/valve/index_controller".into(), - // binding: "/user/hand/right/input/a/click".into(), - // }) - // .id(); - - // //add action to set, this isnt the best - // //TODO look into a better system - // commands.entity(action).add_child(binding); - // commands.entity(set).add_child(action); } fn create_openxr_events( @@ -429,7 +409,7 @@ fn sync_and_update_action_states_vector( } fn read_action_with_marker_component( - mut action_query: Query<&MyActionState, With>, + mut action_query: Query<&MyActionState, With>, ) { //now for the actual checking for state in action_query.iter_mut() { @@ -437,6 +417,42 @@ fn read_action_with_marker_component( } } +//lets add some flycam stuff +fn handle_flight_input( + action_query: Query<&MyActionState, With>, + mut oxr_root: Query<&mut Transform, With>, + time: Res { } } -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] pub enum ActionType { Bool, Float, diff --git a/crates/bevy_xr_utils/Cargo.toml b/crates/bevy_xr_utils/Cargo.toml index 8f929ae..3b622ac 100644 --- a/crates/bevy_xr_utils/Cargo.toml +++ b/crates/bevy_xr_utils/Cargo.toml @@ -9,4 +9,4 @@ edition = "2021" bevy.workspace = true bevy_xr.path = "../bevy_xr" openxr = "0.18.0" -bevy_openxr.path = "../bevy_openxr" \ No newline at end of file +bevy_openxr.path = "../bevy_openxr" diff --git a/crates/bevy_xr_utils/src/xr_utils_actions.rs b/crates/bevy_xr_utils/src/xr_utils_actions.rs index dac6d07..4a0cef5 100644 --- a/crates/bevy_xr_utils/src/xr_utils_actions.rs +++ b/crates/bevy_xr_utils/src/xr_utils_actions.rs @@ -1,3 +1,58 @@ +//! This plugin and module are here to ease the creation of actions withing openxr +//! The general idea is any plugin can create entities in startup before XRUtilsActionSystemSet::CreateEvents +//! this plugin will then create the neccessary actions sets, actions, and bindings and get them ready for use. +//! +//! example creating actions +//! +//! //create a set +//! let set = commands +//! .spawn(( +//! XRUtilsActionSet { +//! name: "flight".into(), +//! pretty_name: "pretty flight set".into(), +//! priority: u32::MIN, +//! }, +//! ActiveSet, //marker to indicate we want this synced +//! )) +//! .id(); +//! //create an action +//! let action = commands +//! .spawn(( +//! XRUtilsAction { +//! action_name: "flight_input".into(), +//! localized_name: "flight_input_localized".into(), +//! action_type: bevy_xr::actions::ActionType::Vector, +//! }, +//! FlightActionMarker, //lets try a marker component +//! )) +//! .id(); +//! +//! //create a binding +//! let binding = commands +//! .spawn(XRUtilsBinding { +//! profile: "/interaction_profiles/valve/index_controller".into(), +//! binding: "/user/hand/right/input/thumbstick".into(), +//! }) +//! .id(); +//! +//! //add action to set, this isnt the best +//! //TODO look into a better system +//! commands.entity(action).add_child(binding); +//! commands.entity(set).add_child(action); +//! +//! then you can read the action states after XRUtilsActionSystemSet::SyncActionStates +//! for example +//! +//! fn read_action_with_marker_component( +//! mut action_query: Query<&XRUtilsActionState, With>, +//! ) { +//! //now for the actual checking +//! for state in action_query.iter_mut() { +//! info!("action state is: {:?}", state); +//! } +//! } +//! +//! use bevy::prelude::*; use bevy_openxr::{ action_binding::OxrSuggestActionBinding, From dd24b95264f7d89da05d445554ac0aadfa96529f Mon Sep 17 00:00:00 2001 From: Jay Christy Date: Thu, 30 May 2024 23:47:07 -0400 Subject: [PATCH 17/17] changed to ambient light for better performance --- crates/bevy_openxr/examples/actions.rs | 29 ++++++++++++-------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/crates/bevy_openxr/examples/actions.rs b/crates/bevy_openxr/examples/actions.rs index 936e1fa..cf09c3a 100644 --- a/crates/bevy_openxr/examples/actions.rs +++ b/crates/bevy_openxr/examples/actions.rs @@ -1,14 +1,11 @@ // a simple example showing basic actions using the xr utils actions use bevy::{math::vec3, prelude::*}; use bevy_openxr::{ - add_xr_plugins, - helper_traits::ToQuat, - init::OxrTrackingRoot, - resources::OxrViews, + add_xr_plugins, helper_traits::ToQuat, init::OxrTrackingRoot, resources::OxrViews, }; use bevy_xr_utils::xr_utils_actions::{ - ActiveSet, XRUtilsAction, XRUtilsActionSet, - XRUtilsActionState, XRUtilsActionSystemSet, XRUtilsActionsPlugin, XRUtilsBinding, + ActiveSet, XRUtilsAction, XRUtilsActionSet, XRUtilsActionState, XRUtilsActionSystemSet, + XRUtilsActionsPlugin, XRUtilsBinding, }; fn main() { @@ -16,7 +13,10 @@ fn main() { .add_plugins(add_xr_plugins(DefaultPlugins)) .add_plugins(bevy_xr_utils::hand_gizmos::HandGizmosPlugin) .add_systems(Startup, setup_scene) - .add_systems(Startup, create_action_entities.before(XRUtilsActionSystemSet::CreateEvents)) + .add_systems( + Startup, + create_action_entities.before(XRUtilsActionSystemSet::CreateEvents), + ) .add_plugins(XRUtilsActionsPlugin) .add_systems( Update, @@ -26,6 +26,11 @@ fn main() { Update, handle_flight_input.after(XRUtilsActionSystemSet::SyncActionStates), ) + // Realtime lighting is expensive, use ambient light instead + .insert_resource(AmbientLight { + color: Default::default(), + brightness: 500.0, + }) .run(); } @@ -49,15 +54,7 @@ fn setup_scene( 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()