From 9a556289deb81b69ed9000f815b384f094aa0621 Mon Sep 17 00:00:00 2001 From: awtterpip Date: Thu, 14 Mar 2024 21:34:42 -0500 Subject: [PATCH] more rendering code --- crates/bevy_openxr/src/init.rs | 68 ++++++++++++++- crates/bevy_openxr/src/render.rs | 128 ++++++++++++++++------------ crates/bevy_openxr/src/resources.rs | 4 +- crates/bevy_xr/src/camera.rs | 11 ++- 4 files changed, 148 insertions(+), 63 deletions(-) diff --git a/crates/bevy_openxr/src/init.rs b/crates/bevy_openxr/src/init.rs index 8fbdeb8..cfdcb3a 100644 --- a/crates/bevy_openxr/src/init.rs +++ b/crates/bevy_openxr/src/init.rs @@ -1,17 +1,25 @@ -use bevy::app::{App, First, Plugin}; +use bevy::app::{App, First, Plugin, PostUpdate}; +use bevy::ecs::component::Component; +use bevy::ecs::entity::Entity; use bevy::ecs::event::EventWriter; +use bevy::ecs::query::{With, Without}; use bevy::ecs::schedule::common_conditions::{not, on_event}; use bevy::ecs::schedule::IntoSystemConfigs; -use bevy::ecs::system::{Commands, Res, ResMut, Resource}; +use bevy::ecs::system::{Commands, Query, Res, ResMut, Resource}; use bevy::ecs::world::World; -use bevy::log::{error, info}; +use bevy::hierarchy::{BuildChildren, Parent}; +use bevy::log::{error, info, warn}; use bevy::math::{uvec2, UVec2}; +use bevy::prelude::{Deref, DerefMut}; +use bevy::render::extract_component::{ExtractComponent, ExtractComponentPlugin}; use bevy::render::extract_resource::ExtractResourcePlugin; use bevy::render::renderer::{ RenderAdapter, RenderAdapterInfo, RenderDevice, RenderInstance, RenderQueue, }; use bevy::render::settings::RenderCreation; use bevy::render::{ExtractSchedule, MainWorld, RenderApp, RenderPlugin}; +use bevy::transform::components::GlobalTransform; +use bevy::transform::{TransformBundle, TransformSystem}; use bevy_xr::session::{ BeginXrSession, CreateXrSession, XrInstanceCreated, XrInstanceDestroyed, XrSessionState, }; @@ -140,6 +148,7 @@ fn init_xr(config: &XrInitPlugin, app: &mut App) -> Result<()> { ), synchronous_pipeline_compilation: config.synchronous_pipeline_compilation, }, + ExtractComponentPlugin::::default(), ExtractResourcePlugin::::default(), ExtractResourcePlugin::::default(), )) @@ -165,9 +174,14 @@ fn init_xr(config: &XrInitPlugin, app: &mut App) -> Result<()> { begin_xr_session .run_if(session_ready) .run_if(on_event::()), + adopt_open_xr_trackers, ) .chain(), ) + .add_systems( + PostUpdate, + update_root_transform_components.after(TransformSystem::TransformPropagate), + ) .sub_app_mut(RenderApp) .insert_resource(instance) .insert_resource(SystemId(system_id)) @@ -176,9 +190,57 @@ fn init_xr(config: &XrInitPlugin, app: &mut App) -> Result<()> { transfer_xr_resources.run_if(not(session_running)), ); + app.world + .spawn((TransformBundle::default(), OpenXrTrackingRoot)); + Ok(()) } +#[derive(Component, ExtractComponent, Clone, Deref, DerefMut, Default)] +pub struct XrRoot(pub GlobalTransform); + +#[derive(Component)] +/// This is the root location of the playspace. Moving this entity around moves the rest of the playspace around. +pub struct OpenXrTrackingRoot; + +#[derive(Component)] +/// Marker component for any entities that should be children of [`OpenXrTrackingRoot`] +pub struct OpenXrTracker; + +pub fn adopt_open_xr_trackers( + query: Query, Without)>, + mut commands: Commands, + tracking_root_query: Query>, +) { + let root = tracking_root_query.get_single(); + match root { + Ok(root) => { + // info!("root is"); + for tracker in query.iter() { + info!("we got a new tracker"); + commands.entity(root).add_child(tracker); + } + } + Err(_) => info!("root isnt spawned yet?"), + } +} + +fn update_root_transform_components( + mut component_query: Query<&mut XrRoot>, + root_query: Query<&GlobalTransform, With>, +) { + let root = match root_query.get_single() { + Ok(v) => v, + Err(err) => { + warn!("No or too many XrTracking Roots: {}", err); + return; + } + }; + component_query + .par_iter_mut() + .for_each(|mut root_transform| **root_transform = *root); +} + /// This is used to store information from startup that is needed to create the session after the instance has been created. struct XrSessionInitConfig { /// List of blend modes the openxr session can use. If [None], pick the first available blend mode. diff --git a/crates/bevy_openxr/src/render.rs b/crates/bevy_openxr/src/render.rs index 0c0948c..a2acb67 100644 --- a/crates/bevy_openxr/src/render.rs +++ b/crates/bevy_openxr/src/render.rs @@ -2,17 +2,17 @@ use bevy::{ prelude::*, render::{ camera::{ManualTextureView, ManualTextureViewHandle, ManualTextureViews, RenderTarget}, - extract_component::{ExtractComponent, ExtractComponentPlugin}, extract_resource::ExtractResourcePlugin, renderer::render_system, + view::ExtractedView, Render, RenderApp, RenderSet, }, }; use bevy_xr::camera::{XrCamera, XrCameraBundle, XrProjection}; use openxr::{CompositionLayerFlags, ViewStateFlags}; -use crate::resources::*; -use crate::{init::begin_xr_session, layer_builder::*}; +use crate::{init::OpenXrTracker, resources::*}; +use crate::{init::XrRoot, layer_builder::*}; use crate::init::session_running; @@ -20,24 +20,27 @@ pub struct XrRenderPlugin; impl Plugin for XrRenderPlugin { fn build(&self, app: &mut App) { - app.add_plugins(( - ExtractComponentPlugin::::default(), - ExtractResourcePlugin::::default(), - )) - .add_systems( - First, - ( - init_views.run_if(resource_added::), - wait_frame.run_if(session_running), - ) - .after(begin_xr_session), - ) - .add_systems(PreUpdate, update_views.run_if(session_running)); + app.add_plugins((ExtractResourcePlugin::::default(),)) + .add_systems( + PreUpdate, + ( + init_views.run_if(resource_added::), + wait_frame.run_if(session_running), + locate_views.run_if(session_running), + update_views.run_if(session_running), + ) + .chain(), + ); // .add_systems(Startup, init_views); app.sub_app_mut(RenderApp).add_systems( Render, ( - insert_texture_views + ( + locate_views, + update_views_render_world, + insert_texture_views, + ) + .chain() .in_set(RenderSet::PrepareAssets) .before(render_system), end_frame.in_set(RenderSet::Cleanup), @@ -47,9 +50,6 @@ impl Plugin for XrRenderPlugin { } } -#[derive(Component, ExtractComponent, Clone)] -pub struct XrView(pub openxr::View); - pub const XR_TEXTURE_INDEX: u32 = 3383858418; // TODO: have cameras initialized externally and then recieved by this function. @@ -69,16 +69,19 @@ pub fn init_views( let view_handle = add_texture_view(&mut manual_texture_views, temp_tex, &graphics_info, index); - let entity = commands - .spawn((XrCameraBundle { + commands.spawn(( + XrCameraBundle { camera: Camera { target: RenderTarget::TextureView(view_handle), ..Default::default() }, + view: XrCamera(index), ..Default::default() - },)) - .id(); - views.push((entity, default())); + }, + OpenXrTracker, + XrRoot::default(), + )); + views.push(default()); } commands.insert_resource(XrViews(views)); } @@ -92,21 +95,17 @@ pub fn wait_frame( let state = frame_waiter.wait().expect("Failed to wait frame"); // Here we insert the predicted display time for when this frame will be displayed. // TODO: don't add predicted_display_period if pipelined rendering plugin not enabled - commands.insert_resource(XrTime(openxr::Time::from_nanos( - state.predicted_display_time.as_nanos(), - ))); + commands.insert_resource(XrTime(state.predicted_display_time)); frame_stream.begin().expect("Failed to begin frame"); } -pub fn update_views( - mut views: Query<(&mut Transform, &mut XrProjection), With>, - mut view_entities: ResMut, +pub fn locate_views( session: Res, stage: Res, time: Res, - mut openxr_views: Local>, + mut openxr_views: ResMut, ) { - let _span = info_span!("xr_update_views"); + let _span = info_span!("xr_locate_views"); let (flags, xr_views) = session .locate_views( openxr::ViewConfigurationType::PRIMARY_STEREO, @@ -121,7 +120,7 @@ pub fn update_views( flags & ViewStateFlags::ORIENTATION_VALID == ViewStateFlags::ORIENTATION_VALID, flags & ViewStateFlags::POSITION_VALID == ViewStateFlags::POSITION_VALID, ) { - (true, true) => *openxr_views = xr_views, + (true, true) => *openxr_views = XrViews(xr_views), (true, false) => { for (i, view) in openxr_views.iter_mut().enumerate() { view.pose.orientation = xr_views[i].pose.orientation; @@ -134,24 +133,45 @@ pub fn update_views( } (false, false) => {} } +} - for (i, view) in openxr_views.iter().enumerate() { - if let Some(((mut transform, mut projection), xr_view)) = view_entities - .0 - .get_mut(i) - .and_then(|(entity, view)| views.get_mut(*entity).ok().map(|res| (res, view))) - { - *xr_view = *view; - let projection_matrix = calculate_projection(projection.near, view.fov); - projection.projection_matrix = projection_matrix; +pub fn update_views( + mut query: Query<(&mut Transform, &mut XrProjection, &XrCamera)>, + views: ResMut, +) { + for (mut transform, mut projection, camera) in query.iter_mut() { + let Some(view) = views.get(camera.0 as usize) else { + continue; + }; - let openxr::Quaternionf { x, y, z, w } = view.pose.orientation; - let rotation = Quat::from_xyzw(x, y, z, w); - transform.rotation = rotation; - let openxr::Vector3f { x, y, z } = view.pose.position; - let translation = Vec3::new(x, y, z); - transform.translation = translation; - } + let projection_matrix = calculate_projection(projection.near, view.fov); + projection.projection_matrix = projection_matrix; + + let openxr::Quaternionf { x, y, z, w } = view.pose.orientation; + let rotation = Quat::from_xyzw(x, y, z, w); + transform.rotation = rotation; + let openxr::Vector3f { x, y, z } = view.pose.position; + let translation = Vec3::new(x, y, z); + transform.translation = translation; + } +} + +pub fn update_views_render_world( + views: Res, + mut query: Query<(&mut ExtractedView, &XrRoot, &XrCamera)>, +) { + for (mut extracted_view, root, camera) in query.iter_mut() { + let Some(view) = views.get(camera.0 as usize) else { + continue; + }; + let mut transform = Transform::IDENTITY; + let openxr::Quaternionf { x, y, z, w } = view.pose.orientation; + let rotation = Quat::from_xyzw(x, y, z, w); + transform.rotation = rotation; + let openxr::Vector3f { x, y, z } = view.pose.position; + let translation = Vec3::new(x, y, z); + transform.translation = translation; + extracted_view.transform = root.mul_transform(transform); } } @@ -317,8 +337,8 @@ pub fn end_frame( .space(&stage) .views(&[ CompositionLayerProjectionView::new() - .pose(openxr_views.0[0].1.pose) - .fov(openxr_views.0[0].1.fov) + .pose(openxr_views.0[0].pose) + .fov(openxr_views.0[0].fov) .sub_image( SwapchainSubImage::new() .swapchain(&swapchain) @@ -326,8 +346,8 @@ pub fn end_frame( .image_rect(rect), ), CompositionLayerProjectionView::new() - .pose(openxr_views.0[1].1.pose) - .fov(openxr_views.0[1].1.fov) + .pose(openxr_views.0[1].pose) + .fov(openxr_views.0[1].fov) .sub_image( SwapchainSubImage::new() .swapchain(&swapchain) diff --git a/crates/bevy_openxr/src/resources.rs b/crates/bevy_openxr/src/resources.rs index cf798cf..535862c 100644 --- a/crates/bevy_openxr/src/resources.rs +++ b/crates/bevy_openxr/src/resources.rs @@ -278,5 +278,5 @@ pub struct XrGraphicsInfo { pub format: wgpu::TextureFormat, } -#[derive(Clone, Resource, ExtractResource)] -pub struct XrViews(pub Vec<(Entity, openxr::View)>); +#[derive(Clone, Resource, ExtractResource, Deref, DerefMut)] +pub struct XrViews(pub Vec); diff --git a/crates/bevy_xr/src/camera.rs b/crates/bevy_xr/src/camera.rs index 47f40b0..1ba93bf 100644 --- a/crates/bevy_xr/src/camera.rs +++ b/crates/bevy_xr/src/camera.rs @@ -30,7 +30,10 @@ impl Plugin for XrCameraPlugin { .after(TransformSystem::TransformPropagate) .before(VisibilitySystems::UpdatePerspectiveFrusta), ); - app.add_plugins(ExtractComponentPlugin::::default()); + app.add_plugins(( + ExtractComponentPlugin::::default(), + ExtractComponentPlugin::::default(), + )); } } @@ -51,8 +54,8 @@ impl Default for XrProjection { } /// Marker component for an XR view. It is the backends responsibility to update this. -#[derive(Clone, Copy, Component, Debug, Default)] -pub struct XrCamera; +#[derive(Clone, Copy, Component, ExtractComponent, Debug, Default)] +pub struct XrCamera(pub u32); impl CameraProjection for XrProjection { fn get_projection_matrix(&self) -> Mat4 { @@ -125,7 +128,7 @@ impl Default for XrCameraBundle { exposure: Default::default(), main_texture_usages: Default::default(), dither: DebandDither::Enabled, - view: XrCamera, + view: XrCamera(0), } } }