more rendering code
This commit is contained in:
@@ -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::<XrRoot>::default(),
|
||||
ExtractResourcePlugin::<XrTime>::default(),
|
||||
ExtractResourcePlugin::<XrStatus>::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::<BeginXrSession>()),
|
||||
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<Entity, (With<OpenXrTracker>, Without<Parent>)>,
|
||||
mut commands: Commands,
|
||||
tracking_root_query: Query<Entity, With<OpenXrTrackingRoot>>,
|
||||
) {
|
||||
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<OpenXrTrackingRoot>>,
|
||||
) {
|
||||
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.
|
||||
|
||||
@@ -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::<XrView>::default(),
|
||||
ExtractResourcePlugin::<XrViews>::default(),
|
||||
))
|
||||
app.add_plugins((ExtractResourcePlugin::<XrViews>::default(),))
|
||||
.add_systems(
|
||||
First,
|
||||
PreUpdate,
|
||||
(
|
||||
init_views.run_if(resource_added::<XrGraphicsInfo>),
|
||||
wait_frame.run_if(session_running),
|
||||
locate_views.run_if(session_running),
|
||||
update_views.run_if(session_running),
|
||||
)
|
||||
.after(begin_xr_session),
|
||||
)
|
||||
.add_systems(PreUpdate, 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<XrCamera>>,
|
||||
mut view_entities: ResMut<XrViews>,
|
||||
pub fn locate_views(
|
||||
session: Res<XrSession>,
|
||||
stage: Res<XrStage>,
|
||||
time: Res<XrTime>,
|
||||
mut openxr_views: Local<Vec<openxr::View>>,
|
||||
mut openxr_views: ResMut<XrViews>,
|
||||
) {
|
||||
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,14 +133,17 @@ pub fn update_views(
|
||||
}
|
||||
(false, false) => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_views(
|
||||
mut query: Query<(&mut Transform, &mut XrProjection, &XrCamera)>,
|
||||
views: ResMut<XrViews>,
|
||||
) {
|
||||
for (mut transform, mut projection, camera) in query.iter_mut() {
|
||||
let Some(view) = views.get(camera.0 as usize) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
@@ -152,6 +154,24 @@ pub fn update_views(
|
||||
let translation = Vec3::new(x, y, z);
|
||||
transform.translation = translation;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_views_render_world(
|
||||
views: Res<crate::resources::XrViews>,
|
||||
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)
|
||||
|
||||
@@ -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<openxr::View>);
|
||||
|
||||
@@ -30,7 +30,10 @@ impl Plugin for XrCameraPlugin {
|
||||
.after(TransformSystem::TransformPropagate)
|
||||
.before(VisibilitySystems::UpdatePerspectiveFrusta),
|
||||
);
|
||||
app.add_plugins(ExtractComponentPlugin::<XrProjection>::default());
|
||||
app.add_plugins((
|
||||
ExtractComponentPlugin::<XrProjection>::default(),
|
||||
ExtractComponentPlugin::<XrCamera>::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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user