From 2efdbec2ca829e82867b1e8c7f47ad51f3054657 Mon Sep 17 00:00:00 2001 From: Schmarni Date: Fri, 27 Dec 2024 05:42:21 +0100 Subject: [PATCH] refactor: improve performance a lot Signed-off-by: Schmarni --- Cargo.toml | 12 ++- codegen/src/lib.rs | 87 +++++++++++++++++++++ src/bevy_plugin.rs | 7 +- src/core/mod.rs | 1 + src/core/queued_mutex.rs | 119 +++++++++++++++++++++++++++++ src/core/scenegraph.rs | 21 ++++- src/main.rs | 9 ++- src/nodes/audio.rs | 10 --- src/nodes/drawable/lines.rs | 35 ++++++--- src/nodes/drawable/model.rs | 21 ----- src/nodes/drawable/text.rs | 19 +++-- src/nodes/input/mod.rs | 2 + src/nodes/mod.rs | 33 +++++--- src/objects/input/sk_controller.rs | 10 ++- src/objects/input/sk_hand.rs | 14 +++- 15 files changed, 328 insertions(+), 72 deletions(-) create mode 100644 src/core/queued_mutex.rs diff --git a/Cargo.toml b/Cargo.toml index 610a4a9..6ff4d21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,11 @@ license = "GPLv2" repository = "https://github.com/StardustXR/stardust-xr-server/" homepage = "https://stardustxr.org" +[patch.crates-io] +tracing-tracy = { git = "https://github.com/nagisa/rust_tracy_client", tag = "tracy-client-v0.17.6" } +tracy-client = { git = "https://github.com/nagisa/rust_tracy_client", tag = "tracy-client-v0.17.6" } +tracy-client-sys = { git = "https://github.com/nagisa/rust_tracy_client", tag = "tracy-client-v0.17.6" } + [workspace] members = ["codegen"] @@ -46,7 +51,12 @@ auto_link_exclude_list = [ ] [dependencies] -bevy = { version = "0.15", features = ["wayland", "mp3", "wav"] } +bevy = { version = "0.15", features = [ + "wayland", + "mp3", + "wav", + "trace_tracy", +] } bevy_mod_xr = { git = "https://github.com/Schmarni-Dev/bevy_openxr", branch = "0.15rc" } bevy_mod_openxr = { git = "https://github.com/Schmarni-Dev/bevy_openxr", branch = "0.15rc" } bevy_xr_utils = { git = "https://github.com/Schmarni-Dev/bevy_openxr", branch = "0.15rc" } diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs index b91087d..eaefca5 100644 --- a/codegen/src/lib.rs +++ b/codegen/src/lib.rs @@ -49,6 +49,93 @@ pub fn codegen_item_panel_protocol(_input: proc_macro::TokenStream) -> proc_macr codegen_protocol(ITEM_PANEL_PROTOCOL) } +#[proc_macro] +pub fn codegen_id_to_name_functions(_input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let mut aspect_map: Vec<(u64, String)> = Vec::new(); + let mut method_map: Vec<(u64, String)> = Vec::new(); + let mut signal_map: Vec<(u64, String)> = Vec::new(); + let protocols = [ + ROOT_PROTOCOL, + NODE_PROTOCOL, + SPATIAL_PROTOCOL, + FIELD_PROTOCOL, + AUDIO_PROTOCOL, + DRAWABLE_PROTOCOL, + INPUT_PROTOCOL, + ITEM_PROTOCOL, + ITEM_CAMERA_PROTOCOL, + ITEM_PANEL_PROTOCOL, + ]; + for aspect in protocols + .into_iter() + .filter_map(|p| Protocol::parse(p).ok()) + .flat_map(|v| v.aspects) + { + aspect_map.push((aspect.id, aspect.name)); + for m in aspect.members.into_iter() { + match m._type { + MemberType::Signal => &mut signal_map, + MemberType::Method => &mut method_map, + } + .push((m.opcode, m.name)); + } + } + + let aspect_id_to_name = aspect_map + .iter() + .map(|(id, name)| { + quote! { + #id => #name, + } + }) + .reduce(fold_tokens); + let aspect_id_to_name_fn = quote! { + pub const fn aspect_id_to_name(id: u64) -> &'static str { + match id { + #aspect_id_to_name + _ => "Unknown" + } + } + }; + let method_id_to_name = method_map + .iter() + .map(|(id, name)| { + quote! { + #id => #name, + } + }) + .reduce(fold_tokens); + let method_id_to_name_fn = quote! { + pub const fn method_id_to_name(id: u64) -> &'static str { + match id { + #method_id_to_name + _ => "Unknown" + } + } + }; + let signal_id_to_name = signal_map + .iter() + .map(|(id, name)| { + quote! { + #id => #name, + } + }) + .reduce(fold_tokens); + let signal_id_to_name_fn = quote! { + pub const fn signal_id_to_name(id: u64) -> &'static str { + match id { + #signal_id_to_name + _ => "Unknown" + } + } + }; + quote! { + #aspect_id_to_name_fn + #method_id_to_name_fn + #signal_id_to_name_fn + }.into() +} + fn codegen_protocol(protocol: &'static str) -> proc_macro::TokenStream { let protocol = Protocol::parse(protocol).unwrap(); let interface = protocol diff --git a/src/bevy_plugin.rs b/src/bevy_plugin.rs index 3434006..df11a7a 100644 --- a/src/bevy_plugin.rs +++ b/src/bevy_plugin.rs @@ -71,9 +71,10 @@ fn yeet_entities( query: Query>, reader: Res, ) { - query - .iter() - .for_each(|e| cmds.entity(e).despawn_recursive()); + query.iter().for_each(|e| { + info!("yeeting component entities"); + cmds.entity(e).despawn_recursive(); + }); reader .0 .try_iter() diff --git a/src/core/mod.rs b/src/core/mod.rs index 594fe29..0239164 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -7,3 +7,4 @@ pub mod registry; pub mod resource; pub mod scenegraph; pub mod task; +pub mod queued_mutex; diff --git a/src/core/queued_mutex.rs b/src/core/queued_mutex.rs new file mode 100644 index 0000000..c1e96da --- /dev/null +++ b/src/core/queued_mutex.rs @@ -0,0 +1,119 @@ +use std::{ + ops::{Deref, DerefMut}, + sync::atomic::Ordering, +}; + +use parking_lot::{ + lock_api::{MutexGuard, RwLockReadGuard}, + Mutex, RawMutex, RawRwLock, RwLock, +}; +use portable_atomic::AtomicU8; + +pub struct QueuedMutex { + mutable: Mutex>, + readers: AtomicU8, + inner: RwLock, +} + +impl Default for QueuedMutex { + fn default() -> Self { + Self::new(T::default()) + } +} + +impl QueuedMutex { + pub const fn new(value: T) -> QueuedMutex { + Self { + mutable: Mutex::new(None), + readers: AtomicU8::new(0), + inner: RwLock::new(value), + } + } + pub fn lock(&self) -> QueuedMutexLockGuard<'_, T> { + let mut guard = self.mutable.lock(); + if guard.is_none() { + guard.replace(self.inner.read().clone()); + } + QueuedMutexLockGuard { mutex: self, guard } + } + pub fn read_now(&self) -> QueuedMutexReadGuard<'_, T> { + let guard = self.inner.read(); + self.readers.add(1, Ordering::Relaxed); + QueuedMutexReadGuard { + mutex: self, + guard: Some(guard), + } + } +} + +pub struct QueuedMutexLockGuard<'a, T: Clone> { + mutex: &'a QueuedMutex, + guard: MutexGuard<'a, RawMutex, Option>, +} +impl Deref for QueuedMutexLockGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + match self.guard.as_ref() { + Some(v) => v, + None => unreachable!(), + } + } +} +impl DerefMut for QueuedMutexLockGuard<'_, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + match self.guard.as_mut() { + Some(v) => v, + None => unreachable!(), + } + } +} + +impl Drop for QueuedMutexLockGuard<'_, T> { + fn drop(&mut self) { + if self.mutex.readers.load(Ordering::Relaxed) != 0 { + return; + } + let mut write_lock = self.mutex.inner.write(); + *write_lock = match self.guard.take() { + Some(v) => v, + None => unreachable!(), + } + } +} + +pub struct QueuedMutexReadGuard<'a, T: Clone> { + mutex: &'a QueuedMutex, + guard: Option>, +} + +impl Deref for QueuedMutexReadGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + match self.guard.as_ref() { + Some(v) => v, + None => unreachable!(), + } + } +} + +impl Drop for QueuedMutexReadGuard<'_, T> { + fn drop(&mut self) { + drop(self.guard.take()); + if self + .mutex + .readers + .fetch_sub(1, Ordering::Relaxed) + .wrapping_sub(1) + != 0 + { + return; + } + + let mut write_lock = self.mutex.inner.write(); + if let Some(v) = self.mutex.mutable.lock().take() { + *write_lock = v + } + } +} diff --git a/src/core/scenegraph.rs b/src/core/scenegraph.rs index 88e50e0..dd33ac0 100644 --- a/src/core/scenegraph.rs +++ b/src/core/scenegraph.rs @@ -16,6 +16,8 @@ use std::sync::{Arc, Weak}; use tokio::sync::oneshot; use tracing::{debug, debug_span}; +stardust_xr_server_codegen::codegen_id_to_name_functions!(); + #[derive(Default)] pub struct Scenegraph { pub(super) client: OnceCell>, @@ -96,7 +98,15 @@ impl scenegraph::Scenegraph for Scenegraph { let Some(client) = self.get_client() else { return Err(ScenegraphError::NodeNotFound); }; - debug_span!("Handle signal", aspect_id, node_id, method).in_scope(|| { + debug_span!( + "Handle signal", + aspect_id, + aspect_name = aspect_id_to_name(aspect_id), + node_id, + method, + signal_name = signal_id_to_name(method) + ) + .in_scope(|| { self.get_node(node_id) .ok_or(ScenegraphError::NodeNotFound)? .send_local_signal( @@ -123,7 +133,14 @@ impl scenegraph::Scenegraph for Scenegraph { let _ = response.send(Err(ScenegraphError::NodeNotFound)); return; }; - debug!(aspect_id, node_id, method, "Handle method"); + debug!( + aspect_id, + aspect_name = aspect_id_to_name(aspect_id), + node_id, + method, + method_name = method_id_to_name(method), + "Handle method" + ); let Some(node) = self.get_node(node_id) else { let _ = response.send(Err(ScenegraphError::NodeNotFound)); return; diff --git a/src/main.rs b/src/main.rs index b607fbd..6b4b972 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,6 +42,7 @@ use bevy_mod_xr::session::{XrFirst, XrPreDestroySession, XrSessionCreated, XrSes use bevy_mod_xr::spaces::XrPrimaryReferenceSpace; use bevy_plugin::{DbusConnection, InputUpdate, StardustBevyPlugin, StardustFirst}; use clap::Parser; +use tracing::level_filters::LevelFilter; use core::client::Client; use core::task; use directories::ProjectDirs; @@ -198,7 +199,7 @@ async fn setup() { let cli_args = cli_args.clone(); let dbus_connection = dbus_connection.clone(); move || { - stereokit_loop( + bevy_loop( sk_ready_notifier, project_dirs, cli_args, @@ -228,7 +229,7 @@ async fn setup() { info!("Cleanly shut down Stardust"); } -fn stereokit_loop( +fn bevy_loop( sk_ready_notifier: Arc, project_dirs: Option, args: CliArgs, @@ -331,6 +332,7 @@ fn stereokit_loop( cams.iter().for_each(|e| { cmds.entity(e).remove::(); }); + let _span = debug_span!("spawn"); cmds.insert_resource(ClearColor(Color::NONE)); } *last_hidden = env_hidden; @@ -392,7 +394,7 @@ fn stereokit_loop( bevy_app.insert_resource(objects); - let bevy_step = |world: &mut World| { + fn bevy_step(world: &mut World) { let _span = debug_span!("Bevy step"); let _span = _span.enter(); // camera::update(token); @@ -428,6 +430,7 @@ fn stereokit_loop( .run_system_cached(should_run_frame_loop) .unwrap_or(true) { + let _span = debug_span!("eeping").entered(); let mut waiter = world.remove_resource::().unwrap(); let state = waiter.wait().unwrap(); world.insert_resource(OxrFrameState(state)); diff --git a/src/nodes/audio.rs b/src/nodes/audio.rs index 5224f18..369f748 100644 --- a/src/nodes/audio.rs +++ b/src/nodes/audio.rs @@ -163,18 +163,8 @@ impl Drop for Sound { } } -<<<<<<< HEAD -======= -<<<<<<< HEAD -create_interface!(AudioInterface); ->>>>>>> 0ec4c0f (refactor: get models fully working) struct AudioInterface; impl InterfaceAspect for AudioInterface { -======= -pub fn update() {} - -impl InterfaceAspect for Interface { ->>>>>>> 2f5c92d (refactor: get models fully working) #[doc = "Create a sound node. WAV and MP3 are supported."] fn create_sound( _node: Arc, diff --git a/src/nodes/drawable/lines.rs b/src/nodes/drawable/lines.rs index e522a29..82421ba 100644 --- a/src/nodes/drawable/lines.rs +++ b/src/nodes/drawable/lines.rs @@ -19,6 +19,7 @@ use glam::{Vec3, Vec3A}; use parking_lot::Mutex; use prisma::Lerp; use std::{collections::VecDeque, sync::Arc}; +use tracing::{debug_span, info}; static LINES_REGISTRY: Registry = Registry::new(); @@ -27,6 +28,7 @@ pub struct Lines { data: Mutex>, } impl Lines { + #[tracing::instrument] pub fn add_to(node: &Arc, lines: Vec) -> Result> { *node .get_aspect::() @@ -34,15 +36,15 @@ impl Lines { .bounding_box_calc .lock() = { if let Ok(lines) = node.get_aspect::() { - Aabb3d::from_point_cloud( - Isometry3d::IDENTITY, + Aabb3d::from_point_cloud(Isometry3d::IDENTITY, { + let _span = debug_span!("add_to data lock").entered(); lines .data .lock() .iter() .flat_map(|line| line.points.iter()) - .map(|point| Vec3A::from(point.point)), - ) + .map(|point| Vec3A::from(point.point)) + }) } else { Aabb3d::new(Vec3A::ZERO, Vec3A::ZERO) } @@ -59,7 +61,9 @@ impl Lines { fn draw(&self, mesh: &mut Mesh, view: &GlobalTransform) -> Transform { let transform_mat = self.space.global_transform(); + let _span = debug_span!("draw data lock").entered(); let data = self.data.lock().clone(); + drop(_span); let global_to_view = view.compute_matrix().inverse(); let local_to_view = transform_mat.inverse() * global_to_view; let view_to_local = local_to_view.inverse(); @@ -139,12 +143,11 @@ struct BevyLinePoint { color: Srgba, thickness: f32, } -impl Aspect for Lines { - const NAME: &'static str = "Lines"; -} impl LinesAspect for Lines { + #[tracing::instrument] fn set_lines(node: Arc, _calling_client: Arc, lines: Vec) -> Result<()> { let lines_aspect = node.get_aspect::()?; + let _span = debug_span!("set_lines data lock").entered(); *lines_aspect.data.lock() = lines; Ok(()) } @@ -167,9 +170,23 @@ pub fn draw_all( ..Default::default() }; let mat_handle = materials.add(material); - for lines in LINES_REGISTRY.get_valid_contents() { + let _span = debug_span!("line registry get valid contents").entered(); + let vec = LINES_REGISTRY.get_valid_contents(); + drop(_span); + info!("len {}", vec.len()); + for lines in vec { + let _span = debug_span!("outer if span").entered(); if let Some(node) = lines.space.node() { - if node.enabled() && !lines.data.lock().is_empty() { + let _span = debug_span!("lines_data lock").entered(); + let w = lines.data.lock().is_empty(); + drop(_span); + let _span = debug_span!("node enabled check").entered(); + let e = node.enabled(); + drop(_span); + let _span = debug_span!("if span").entered(); + if e && !w { + let _span = debug_span!("create line mesh").entered(); + info!("spawning line"); // Does this rebuild the mesh every frame? yes, is this problematic? probably, // would a shader work better? yes, do i care? not right now let mut mesh = Mesh::new( diff --git a/src/nodes/drawable/model.rs b/src/nodes/drawable/model.rs index 5c58cc7..55f8a6f 100644 --- a/src/nodes/drawable/model.rs +++ b/src/nodes/drawable/model.rs @@ -336,18 +336,6 @@ fn create_model_parts_for_loaded_models( *space.bounding_box_calc.lock() = Aabb3d::new(aabb.center, aabb.half_extents); -<<<<<<< HEAD - let model_part = Arc::new(ModelPart { - entity: MainWorldEntity(entity), - path: part_path, - space, - model: Arc::downgrade(model), - pending_material_parameters: Mutex::new(FxHashMap::default()), - pending_material_replacement: Mutex::new(None), - aliases: AliasList::default(), - }); - node.add_aspect_raw(model_part.clone()); -======= let model_part = Arc::new(ModelPart { entity: OnceCell::from(entity), path: part_path, @@ -361,7 +349,6 @@ fn create_model_parts_for_loaded_models( info!("fresh {}", &model_part.path); model_part }); ->>>>>>> 0ec4c0f (refactor: get models fully working) parts.push(model_part.clone()); } cmds.entity(entity).remove::(); @@ -440,13 +427,6 @@ impl ModelAspect for Model { part_path: String, ) -> Result<()> { let model = node.get_aspect::()?; -<<<<<<< HEAD - let parts = model.parts.lock(); - let Some(part) = parts.iter().find(|p| p.path == part_path) else { - let paths = parts.iter().map(|p| &p.path).collect::>(); - bail!("Couldn't find model part at path {part_path}, all available paths: {paths:?}",); - }; -======= let mut parts = model.parts.lock(); let part = parts @@ -476,7 +456,6 @@ impl ModelAspect for Model { parts.push(model_part.clone()); model_part }); ->>>>>>> 0ec4c0f (refactor: get models fully working) Alias::create_with_id( &part.space.node().unwrap(), &calling_client, diff --git a/src/nodes/drawable/text.rs b/src/nodes/drawable/text.rs index 9b5bd25..bdd052a 100644 --- a/src/nodes/drawable/text.rs +++ b/src/nodes/drawable/text.rs @@ -29,6 +29,7 @@ use glam::{vec3, Mat4, Vec2, Vec3}; use once_cell::sync::OnceCell; use parking_lot::Mutex; use std::{ffi::OsStr, path::PathBuf, sync::Arc}; +use tracing::{info, info_span}; use super::{TextAspect, TextStyle}; @@ -68,15 +69,14 @@ fn update_text(mut surface_query: Query<(&mut Transform)>) { else { continue; }; - let data = text.data.lock(); + // let data = text.data.lock(); *transform = Transform::from_matrix( - text.space.global_transform() - * Mat4::from_scale(vec3( - data.character_height, - data.character_height, - data.character_height, - )), + text.space.global_transform(), // * Mat4::from_scale(vec3( + // data.character_height, + // data.character_height, + // data.character_height, + // )), ); } } @@ -90,7 +90,10 @@ fn spawn_text( asset_server: Res, ) { for text in reader.try_iter() { + let _span = info_span!("spawning text").entered(); + let _span2 = info_span!("text data lock").entered(); let data = text.data.lock(); + drop(_span2); let size = Extent3d { width: (512.0 * data.bounds.as_ref().map(|v| v.bounds.x).unwrap_or(1.0)).floor() as u32, height: (512.0 * data.bounds.as_ref().map(|v| v.bounds.y).unwrap_or(1.0)).floor() @@ -168,6 +171,8 @@ fn spawn_text( MeshMaterial3d(mats.add(DefaultMaterial { base_color_texture: Some(image_handle), unlit: true, + // would Cutout be enough here? + alpha_mode: bevy::prelude::AlphaMode::Blend, ..default() })), )) diff --git a/src/nodes/input/mod.rs b/src/nodes/input/mod.rs index 3d01c17..76a2475 100644 --- a/src/nodes/input/mod.rs +++ b/src/nodes/input/mod.rs @@ -8,6 +8,7 @@ mod tip; pub use handler::*; pub use method::*; +use tracing::debug_span; use super::fields::Field; use super::spatial::Spatial; @@ -140,6 +141,7 @@ pub fn process_input() { .clone() // filter out methods without the handler in their handler order .filter(|a| { + let _span = debug_span!("handlder_order lock").entered(); a.handler_order .lock() .iter() diff --git a/src/nodes/mod.rs b/src/nodes/mod.rs index ef3289d..1dca709 100644 --- a/src/nodes/mod.rs +++ b/src/nodes/mod.rs @@ -10,6 +10,7 @@ pub mod spatial; use self::alias::Alias; use crate::core::client::Client; use crate::core::error::{Result, ServerError}; +use crate::core::queued_mutex::QueuedMutex; use crate::core::registry::Registry; use crate::core::scenegraph::MethodResponseSender; use parking_lot::Mutex; @@ -25,6 +26,7 @@ use std::fmt::Debug; use std::os::fd::OwnedFd; use std::sync::{Arc, Weak}; use std::vec::Vec; +use tracing::{debug_span, info}; #[derive(Default)] pub struct Message { @@ -125,17 +127,24 @@ impl Node { )) } pub fn enabled(&self) -> bool { - self.enabled.load(Ordering::Relaxed) - && if let Ok(spatial) = self.get_aspect::() { - spatial - .global_transform() - .to_scale_rotation_translation() - .0 - .length_squared() - > 0.0 - } else { - true - } + let bool = { + let _span = debug_span!("load atomic bool").entered(); + self.enabled.load(Ordering::Relaxed) + }; + bool && if let Ok(spatial) = { + let _span = debug_span!("get spatial aspect").entered(); + self.get_aspect::() + } { + let _span = debug_span!("check if scale is zero").entered(); + spatial + .global_transform() + .to_scale_rotation_translation() + .0 + .length_squared() + > 0.0 + } else { + true + } } pub fn set_enabled(&self, enabled: bool) { self.enabled.store(enabled, Ordering::Relaxed) @@ -324,7 +333,7 @@ pub trait Aspect: Any + Send + Sync + 'static { } #[derive(Default)] -struct Aspects(Mutex>>); +struct Aspects(QueuedMutex>>); impl Aspects { fn add(&self, t: A) -> Arc { let aspect = Arc::new(t); diff --git a/src/objects/input/sk_controller.rs b/src/objects/input/sk_controller.rs index 055d1ef..3f8ef8b 100644 --- a/src/objects/input/sk_controller.rs +++ b/src/objects/input/sk_controller.rs @@ -38,7 +38,7 @@ use openxr::{ActionSet, Posef}; use serde::{Deserialize, Serialize}; use stardust_xr::values::Datamap; use std::{ops::Deref, sync::Arc}; -use tracing::error; +use tracing::{debug_span, error}; use zbus::Connection; #[derive(Default, Debug, Deserialize, Serialize)] @@ -236,11 +236,15 @@ fn spawn_controllers( HandSide::Left => "left", HandSide::Right => "right", }; + let _span = debug_span!("create SpatialRef").entered(); let (spatial, object_handle) = SpatialRef::create( &connection, &("/org/stardustxr/Controller/".to_string() + side), ); + drop(_span); let tip = InputDataType::Tip(Tip::default()); + + let _span = debug_span!("create input method").entered(); let Ok(input) = (|| -> color_eyre::Result> { Ok(InputMethod::add_to( &spatial.node().unwrap(), @@ -250,6 +254,8 @@ fn spawn_controllers( })() else { continue; }; + drop(_span); + let _span = debug_span!("create actions").entered(); let actions = { let set = session .instance() @@ -275,6 +281,8 @@ fn spawn_controllers( .unwrap(), } }; + drop(_span); + let _span = debug_span!("spawn").entered(); cmds.spawn(( SceneRoot(handle.clone()), SkController { diff --git a/src/objects/input/sk_hand.rs b/src/objects/input/sk_hand.rs index 143c928..7b0e2b3 100644 --- a/src/objects/input/sk_hand.rs +++ b/src/objects/input/sk_hand.rs @@ -12,7 +12,10 @@ use crate::objects::{ObjectHandle, SpatialRef}; use crate::DefaultMaterial; use bevy::app::{Plugin, PostUpdate}; use bevy::asset::{AssetServer, Assets, Handle}; -use bevy::prelude::{Commands, Component, Entity, Query, Res, ResMut}; +use bevy::prelude::{ + Commands, Component, Entity, Gizmos, IntoSystemConfigs as _, Query, Res, ResMut, +}; +use bevy::utils::default; use bevy_mod_openxr::helper_traits::{ToQuat, ToVec3}; use bevy_mod_openxr::resources::OxrFrameState; use bevy_mod_openxr::session::OxrSession; @@ -41,6 +44,13 @@ impl Plugin for StardustHandPlugin { fn build(&self, app: &mut bevy::prelude::App) { app.add_systems(XrSessionCreated, create_hands); app.add_systems(PostUpdate, update_hands); + app.add_systems(PostUpdate, draw_hand_gizmos.after(update_hands)); + } +} + +fn draw_hand_gizmos(mut gizmos: Gizmos, query: Query<&SkHand>) { + for hand in query.iter() { + gizmos.axes(hand.palm_spatial.global_transform(), 0.05); } } @@ -87,8 +97,6 @@ fn update_hands( update_joint(&mut finger.intermediate, joints[finger_index + 2]); update_joint(&mut finger.proximal, joints[finger_index + 1]); update_joint(&mut finger.metacarpal, joints[finger_index]); - // Why? - finger.tip.radius = 0.0; } update_joint(&mut hand_input.palm, joints[HandBone::Palm as usize]); hand.palm_spatial