Merge branch 'webxr-refactor' into example_actions

This commit is contained in:
ForTehLose
2024-05-30 22:31:01 -04:00
committed by GitHub
15 changed files with 105 additions and 84 deletions

View File

@@ -12,6 +12,10 @@ passthrough = []
[dev-dependencies] [dev-dependencies]
bevy_xr_utils.path = "../bevy_xr_utils" bevy_xr_utils.path = "../bevy_xr_utils"
[target.'cfg(target_os = "android")'.dependencies]
ndk-context = "0.1"
jni = "0.20"
# bevy can't be placed behind target or proc macros won't work properly # bevy can't be placed behind target or proc macros won't work properly
[dependencies] [dependencies]
bevy.workspace = true bevy.workspace = true
@@ -28,6 +32,7 @@ ash = { version = "0.37.3", optional = true }
[target.'cfg(target_family = "unix")'.dependencies] [target.'cfg(target_family = "unix")'.dependencies]
openxr = { version = "0.18.0", features = ["mint"] } openxr = { version = "0.18.0", features = ["mint"] }
wgpu = { version = "0.19.3", features = ["vulkan-portability"] }
[target.'cfg(target_family = "windows")'.dependencies] [target.'cfg(target_family = "windows")'.dependencies]
openxr = { version = "0.18.0", features = ["mint", "static"] } openxr = { version = "0.18.0", features = ["mint", "static"] }

View File

@@ -39,7 +39,8 @@ fn setup(
}, },
transform: Transform::from_xyz(4.0, 8.0, 4.0), transform: Transform::from_xyz(4.0, 8.0, 4.0),
..default() ..default()
}); commands.spawn(Camera3dBundle { });
commands.spawn(Camera3dBundle {
transform: Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y), transform: Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
..default() ..default()
}); });

View File

@@ -21,7 +21,12 @@ fn main() {
synchronous_pipeline_compilation: default(), synchronous_pipeline_compilation: default(),
})) }))
.add_plugins(bevy_xr_utils::hand_gizmos::HandGizmosPlugin) .add_plugins(bevy_xr_utils::hand_gizmos::HandGizmosPlugin)
.insert_resource(Msaa::Off)
.add_systems(Startup, setup) .add_systems(Startup, setup)
.insert_resource(AmbientLight {
color: Default::default(),
brightness: 500.0,
})
.insert_resource(ClearColor(Color::NONE)) .insert_resource(ClearColor(Color::NONE))
.run(); .run();
} }
@@ -46,13 +51,4 @@ fn setup(
transform: Transform::from_xyz(0.0, 0.5, 0.0), transform: Transform::from_xyz(0.0, 0.5, 0.0),
..default() ..default()
}); });
// light
commands.spawn(PointLightBundle {
point_light: PointLight {
shadows_enabled: true,
..default()
},
transform: Transform::from_xyz(4.0, 8.0, 4.0),
..default()
});
} }

View File

@@ -14,10 +14,14 @@ impl Plugin for OxrActionAttachingPlugin {
fn attach_sets(session: Res<OxrSession>, mut events: EventReader<OxrAttachActionSet>) { fn attach_sets(session: Res<OxrSession>, mut events: EventReader<OxrAttachActionSet>) {
let sets = events.read().map(|v| &v.0).collect::<Vec<_>>(); let sets = events.read().map(|v| &v.0).collect::<Vec<_>>();
if sets.is_empty() {return;} if sets.is_empty() {
return;
}
info!("attaching {} sessions", sets.len()); info!("attaching {} sessions", sets.len());
match session.attach_action_sets(&sets) { match session.attach_action_sets(&sets) {
Ok(_) => {info!("attached sessions!")} Ok(_) => {
info!("attached sessions!")
}
Err(openxr::sys::Result::ERROR_ACTIONSETS_ALREADY_ATTACHED) => { Err(openxr::sys::Result::ERROR_ACTIONSETS_ALREADY_ATTACHED) => {
error!("Action Sets Already attached!"); error!("Action Sets Already attached!");
} }

View File

@@ -1,4 +1,5 @@
use bevy::prelude::*; use bevy::prelude::*;
use bevy_xr::hands::{LeftHand, RightHand};
use bevy_xr::{ use bevy_xr::{
hands::{HandBone, HandBoneRadius}, hands::{HandBone, HandBoneRadius},
session::{session_running, status_changed_to, XrStatus}, session::{session_running, status_changed_to, XrStatus},
@@ -74,11 +75,22 @@ fn spawn_default_hands(
let mut right_bones = [Entity::PLACEHOLDER; 26]; let mut right_bones = [Entity::PLACEHOLDER; 26];
for bone in HandBone::get_all_bones() { for bone in HandBone::get_all_bones() {
let bone_left = cmds let bone_left = cmds
.spawn((SpatialBundle::default(), bone, HandBoneRadius(0.0))) .spawn((
SpatialBundle::default(),
bone,
HandBoneRadius(0.0),
LeftHand,
))
.id(); .id();
let bone_right = cmds let bone_right = cmds
.spawn((SpatialBundle::default(), bone, HandBoneRadius(0.0))) .spawn((
SpatialBundle::default(),
bone,
HandBoneRadius(0.0),
RightHand,
))
.id(); .id();
cmds.entity(root).push_children(&[bone_left]);
cmds.entity(root).push_children(&[bone_right]); cmds.entity(root).push_children(&[bone_right]);
left_bones[bone as usize] = bone_left; left_bones[bone as usize] = bone_left;
right_bones[bone as usize] = bone_right; right_bones[bone as usize] = bone_right;
@@ -87,11 +99,13 @@ fn spawn_default_hands(
DefaultHandTracker, DefaultHandTracker,
OxrHandTracker(tracker_left), OxrHandTracker(tracker_left),
OxrHandBoneEntities(left_bones), OxrHandBoneEntities(left_bones),
LeftHand,
)); ));
cmds.spawn(( cmds.spawn((
DefaultHandTracker, DefaultHandTracker,
OxrHandTracker(tracker_right), OxrHandTracker(tracker_right),
OxrHandBoneEntities(right_bones), OxrHandBoneEntities(right_bones),
RightHand,
)); ));
} }

View File

@@ -1,3 +1,3 @@
pub mod handtracking;
#[cfg(feature = "passthrough")] #[cfg(feature = "passthrough")]
pub mod passthrough; pub mod passthrough;
pub mod handtracking;

View File

@@ -17,6 +17,7 @@ use self::{
pub mod action_binding; pub mod action_binding;
pub mod action_set_attaching; pub mod action_set_attaching;
pub mod action_set_syncing;
pub mod error; pub mod error;
mod exts; mod exts;
pub mod features; pub mod features;
@@ -28,7 +29,6 @@ pub mod reference_space;
pub mod render; pub mod render;
pub mod resources; pub mod resources;
pub mod types; pub mod types;
pub mod action_set_syncing;
pub fn add_xr_plugins<G: PluginGroup>(plugins: G) -> PluginGroupBuilder { pub fn add_xr_plugins<G: PluginGroup>(plugins: G) -> PluginGroupBuilder {
plugins plugins

View File

@@ -10,14 +10,17 @@ use bevy::{
}, },
transform::TransformSystem, transform::TransformSystem,
}; };
use bevy_xr::{camera::{XrCamera, XrCameraBundle, XrProjection}, session::session_running}; use bevy_xr::{
camera::{XrCamera, XrCameraBundle, XrProjection},
session::session_running,
};
use openxr::ViewStateFlags; use openxr::ViewStateFlags;
use crate::{reference_space::OxrPrimaryReferenceSpace, resources::*};
use crate::{ use crate::{
init::{session_started, OxrPreUpdateSet, OxrTrackingRoot}, init::{session_started, OxrPreUpdateSet, OxrTrackingRoot},
layer_builder::ProjectionLayer, layer_builder::ProjectionLayer,
}; };
use crate::{reference_space::OxrPrimaryReferenceSpace, resources::*};
pub struct OxrRenderPlugin; pub struct OxrRenderPlugin;
@@ -28,7 +31,6 @@ impl Plugin for OxrRenderPlugin {
PreUpdate, PreUpdate,
( (
init_views.run_if(resource_added::<OxrGraphicsInfo>), init_views.run_if(resource_added::<OxrGraphicsInfo>),
wait_frame.run_if(session_started),
locate_views.run_if(session_running), locate_views.run_if(session_running),
update_views.run_if(session_running), update_views.run_if(session_running),
) )
@@ -41,7 +43,8 @@ impl Plugin for OxrRenderPlugin {
.chain() .chain()
.run_if(session_running) .run_if(session_running)
.before(TransformSystem::TransformPropagate), .before(TransformSystem::TransformPropagate),
); )
.add_systems(Last, wait_frame.run_if(session_started));
app.sub_app_mut(RenderApp) app.sub_app_mut(RenderApp)
.add_systems( .add_systems(
Render, Render,
@@ -350,11 +353,23 @@ pub fn begin_frame(mut frame_stream: ResMut<OxrFrameStream>) {
pub fn release_image(mut swapchain: ResMut<OxrSwapchain>) { pub fn release_image(mut swapchain: ResMut<OxrSwapchain>) {
let _span = info_span!("xr_release_image"); let _span = info_span!("xr_release_image");
#[cfg(target_os = "android")]
{
let ctx = ndk_context::android_context();
let vm = unsafe { jni::JavaVM::from_raw(ctx.vm().cast()) }.unwrap();
let env = vm.attach_current_thread_as_daemon();
}
swapchain.release_image().unwrap(); swapchain.release_image().unwrap();
} }
pub fn end_frame(world: &mut World) { pub fn end_frame(world: &mut World) {
let _span = info_span!("xr_end_frame"); let _span = info_span!("xr_end_frame");
#[cfg(target_os = "android")]
{
let ctx = ndk_context::android_context();
let vm = unsafe { jni::JavaVM::from_raw(ctx.vm().cast()) }.unwrap();
let env = vm.attach_current_thread_as_daemon();
}
world.resource_scope::<OxrFrameStream, ()>(|world, mut frame_stream| { world.resource_scope::<OxrFrameStream, ()>(|world, mut frame_stream| {
let mut layers = vec![]; let mut layers = vec![];
for layer in world.resource::<OxrRenderLayers>().iter() { for layer in world.resource::<OxrRenderLayers>().iter() {

View File

@@ -0,0 +1 @@

View File

@@ -1,11 +1,11 @@
use proc_macro::TokenStream; use proc_macro::TokenStream;
use proc_macro2::Span; use proc_macro2::Span;
use quote::quote; use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated; use syn::punctuated::Punctuated;
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::token::{Comma, Eq}; use syn::token::{Comma, Eq};
use syn::{parse_macro_input, parse_quote, AttrStyle, DeriveInput, Expr, Type}; use syn::{parse_macro_input, parse_quote, AttrStyle, DeriveInput, Expr, Type};
use syn::parse::{Parse, ParseStream};
mod kw { mod kw {
syn::custom_keyword!(action_type); syn::custom_keyword!(action_type);
@@ -36,7 +36,6 @@ impl Parse for AttributeInput {
} }
} }
#[proc_macro_derive(Action, attributes(action))] #[proc_macro_derive(Action, attributes(action))]
pub fn derive_action(input: TokenStream) -> TokenStream { pub fn derive_action(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput); let input = parse_macro_input!(input as DeriveInput);
@@ -44,9 +43,17 @@ pub fn derive_action(input: TokenStream) -> TokenStream {
let mut attributes = vec![]; let mut attributes = vec![];
for attribute in input.attrs { for attribute in input.attrs {
if let AttrStyle::Inner(token) = attribute.style { if let AttrStyle::Inner(token) = attribute.style {
return TokenStream::from(syn::Error::new(token.span, "This derive macro does not accept inner attributes").to_compile_error()); return TokenStream::from(
syn::Error::new(
token.span,
"This derive macro does not accept inner attributes",
)
.to_compile_error(),
);
}; };
let parsed_attributes = match attribute.parse_args_with(Punctuated::<AttributeInput, Comma>::parse_terminated) { let parsed_attributes = match attribute
.parse_args_with(Punctuated::<AttributeInput, Comma>::parse_terminated)
{
Ok(inner) => inner, Ok(inner) => inner,
Err(e) => return TokenStream::from(e.to_compile_error()), Err(e) => return TokenStream::from(e.to_compile_error()),
}; };
@@ -61,27 +68,39 @@ pub fn derive_action(input: TokenStream) -> TokenStream {
match attribute { match attribute {
AttributeInput::Kind(ty, span) => { AttributeInput::Kind(ty, span) => {
if kind.is_some() { if kind.is_some() {
return syn::Error::new(span, "attribute 'action_type' is defined more than once").to_compile_error().into(); return syn::Error::new(
span,
"attribute 'action_type' is defined more than once",
)
.to_compile_error()
.into();
} }
kind = Some(ty); kind = Some(ty);
}, }
AttributeInput::Name(expr, span) => { AttributeInput::Name(expr, span) => {
if name.is_some() { if name.is_some() {
return syn::Error::new(span, "attribute 'name' is defined more than once").to_compile_error().into(); return syn::Error::new(span, "attribute 'name' is defined more than once")
.to_compile_error()
.into();
} }
name = Some(expr); name = Some(expr);
}, }
AttributeInput::PrettyName(expr, span) => { AttributeInput::PrettyName(expr, span) => {
if pretty_name.is_some() { if pretty_name.is_some() {
return syn::Error::new(span, "attribute 'pretty_name' is defined more than once").to_compile_error().into(); return syn::Error::new(
span,
"attribute 'pretty_name' is defined more than once",
)
.to_compile_error()
.into();
} }
pretty_name = Some(expr); pretty_name = Some(expr);
},
} }
}; }
}
if kind.is_none() { if kind.is_none() {
panic!("action_type isn't specified") panic!("action_type isn't specified")

View File

@@ -1,7 +1,17 @@
use bevy::{ecs::component::Component, math::bool, prelude::{Deref, DerefMut}}; use bevy::{
ecs::component::Component,
math::bool,
prelude::{Deref, DerefMut},
};
#[derive(Clone, Copy, Component, Debug)]
pub struct LeftHand;
#[derive(Clone, Copy, Component, Debug)]
pub struct RightHand;
#[repr(transparent)] #[repr(transparent)]
#[derive(Clone, Copy, Component, Debug,DerefMut,Deref)] #[derive(Clone, Copy, Component, Debug, DerefMut, Deref)]
pub struct HandBoneRadius(pub f32); pub struct HandBoneRadius(pub f32);
#[repr(u8)] #[repr(u8)]

View File

@@ -1,5 +1,5 @@
pub mod actions; pub mod actions;
pub mod camera; pub mod camera;
pub mod hands;
pub mod session; pub mod session;
pub mod types; pub mod types;
pub mod hands;

View File

@@ -89,7 +89,9 @@ pub fn handle_session(
} }
/// A [`Condition`](bevy::ecs::schedule::Condition) that allows the system to run when the xr status changed to a specific [`XrStatus`]. /// A [`Condition`](bevy::ecs::schedule::Condition) that allows the system to run when the xr status changed to a specific [`XrStatus`].
pub fn status_changed_to(status: XrStatus) -> impl FnMut(EventReader<XrStatusChanged>) -> bool + Clone { pub fn status_changed_to(
status: XrStatus,
) -> impl FnMut(EventReader<XrStatusChanged>) -> bool + Clone {
move |mut reader: EventReader<XrStatusChanged>| { move |mut reader: EventReader<XrStatusChanged>| {
reader.read().any(|new_status| new_status.0 == status) reader.read().any(|new_status| new_status.0 == status)
} }

View File

@@ -2,5 +2,5 @@ use bevy::math::{Quat, Vec3};
pub struct Pose { pub struct Pose {
pub position: Vec3, pub position: Vec3,
pub orientation: Quat pub orientation: Quat,
} }

View File

@@ -1,46 +0,0 @@
//! A simple 3D scene with light shining over a cube sitting on a plane.
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.run();
}
/// set up a simple 3D scene
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// 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()
});
// camera
commands.spawn(Camera3dBundle {
transform: Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
..default()
});
}