Merge branch 'webxr-refactor' into example_actions
This commit is contained in:
@@ -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"] }
|
||||||
|
|||||||
@@ -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()
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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()
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
|
pub mod handtracking;
|
||||||
#[cfg(feature = "passthrough")]
|
#[cfg(feature = "passthrough")]
|
||||||
pub mod passthrough;
|
pub mod passthrough;
|
||||||
pub mod handtracking;
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
@@ -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;
|
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
@@ -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()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user