more rendering code

This commit is contained in:
awtterpip
2024-03-14 21:34:42 -05:00
parent 9b39148e67
commit 9a556289de
4 changed files with 148 additions and 63 deletions

View File

@@ -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.

View File

@@ -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;
@@ -153,6 +155,24 @@ pub fn update_views(
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);
}
}
fn calculate_projection(near_z: f32, fov: openxr::Fovf) -> Mat4 {
@@ -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)

View File

@@ -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>);

View File

@@ -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),
}
}
}