fix camera jitter

This commit is contained in:
awtterpip
2024-03-14 19:40:50 -05:00
parent ec2a538010
commit e1d5de1a94
3 changed files with 52 additions and 48 deletions

View File

@@ -2,11 +2,13 @@ use bevy::{
prelude::*, prelude::*,
render::{ render::{
camera::{ManualTextureView, ManualTextureViewHandle, ManualTextureViews, RenderTarget}, camera::{ManualTextureView, ManualTextureViewHandle, ManualTextureViews, RenderTarget},
extract_component::{ExtractComponent, ExtractComponentPlugin},
extract_resource::ExtractResourcePlugin,
renderer::render_system, renderer::render_system,
Render, RenderApp, RenderSet, Render, RenderApp, RenderSet,
}, },
}; };
use bevy_xr::camera::{XrCameraBundle, XrProjection, XrView}; use bevy_xr::camera::{XrCamera, XrCameraBundle, XrProjection};
use openxr::{CompositionLayerFlags, ViewStateFlags}; use openxr::{CompositionLayerFlags, ViewStateFlags};
use crate::resources::*; use crate::resources::*;
@@ -18,7 +20,11 @@ pub struct XrRenderPlugin;
impl Plugin for XrRenderPlugin { impl Plugin for XrRenderPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_systems( app.add_plugins((
ExtractComponentPlugin::<XrView>::default(),
ExtractResourcePlugin::<XrViews>::default(),
))
.add_systems(
First, First,
( (
init_views.run_if(resource_added::<XrGraphicsInfo>), init_views.run_if(resource_added::<XrGraphicsInfo>),
@@ -42,6 +48,9 @@ impl Plugin for XrRenderPlugin {
} }
} }
#[derive(Component, ExtractComponent, Clone)]
pub struct XrView(pub openxr::View);
pub const XR_TEXTURE_INDEX: u32 = 3383858418; pub const XR_TEXTURE_INDEX: u32 = 3383858418;
// TODO: have cameras initialized externally and then recieved by this function. // TODO: have cameras initialized externally and then recieved by this function.
@@ -62,15 +71,15 @@ pub fn init_views(
add_texture_view(&mut manual_texture_views, temp_tex, &graphics_info, index); add_texture_view(&mut manual_texture_views, temp_tex, &graphics_info, index);
let entity = commands let entity = commands
.spawn(XrCameraBundle { .spawn((XrCameraBundle {
camera: Camera { camera: Camera {
target: RenderTarget::TextureView(view_handle), target: RenderTarget::TextureView(view_handle),
..Default::default() ..Default::default()
}, },
..Default::default() ..Default::default()
}) },))
.id(); .id();
views.push(entity); views.push((entity, default()));
} }
commands.insert_resource(XrViews(views)); commands.insert_resource(XrViews(views));
} }
@@ -86,27 +95,49 @@ pub fn wait_frame(mut frame_waiter: ResMut<XrFrameWaiter>, mut commands: Command
} }
pub fn update_views( pub fn update_views(
mut views: Query<(&mut Transform, &mut XrProjection), With<XrView>>, mut views: Query<(&mut Transform, &mut XrProjection), With<XrCamera>>,
view_entities: Res<XrViews>, mut view_entities: ResMut<XrViews>,
session: Res<XrSession>, session: Res<XrSession>,
stage: Res<XrStage>, stage: Res<XrStage>,
time: Res<XrTime>, time: Res<XrTime>,
mut openxr_views: Local<Vec<openxr::View>>,
) { ) {
let _span = info_span!("xr_wait_frame"); let _span = info_span!("xr_wait_frame");
let (_flags, xr_views) = session let (flags, xr_views) = session
.locate_views( .locate_views(
openxr::ViewConfigurationType::PRIMARY_STEREO, openxr::ViewConfigurationType::PRIMARY_STEREO,
**time, **time,
&stage, &stage,
) )
.expect("Failed to locate views"); .expect("Failed to locate views");
if openxr_views.len() != xr_views.len() {
openxr_views.resize(xr_views.len(), default());
}
match (
flags & ViewStateFlags::ORIENTATION_VALID == ViewStateFlags::ORIENTATION_VALID,
flags & ViewStateFlags::POSITION_VALID == ViewStateFlags::POSITION_VALID,
) {
(true, true) => *openxr_views = xr_views,
(true, false) => {
for (i, view) in openxr_views.iter_mut().enumerate() {
view.pose.orientation = xr_views[i].pose.orientation;
}
}
(false, true) => {
for (i, view) in openxr_views.iter_mut().enumerate() {
view.pose.position = xr_views[i].pose.position;
}
}
(false, false) => {}
}
for (i, view) in xr_views.iter().enumerate() { for (i, view) in openxr_views.iter().enumerate() {
if let Some((mut transform, mut projection)) = view_entities if let Some(((mut transform, mut projection), mut xr_view)) = view_entities
.0 .0
.get(i) .get_mut(i)
.and_then(|entity| views.get_mut(*entity).ok()) .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); let projection_matrix = calculate_projection(projection.near, view.fov);
projection.projection_matrix = projection_matrix; projection.projection_matrix = projection_matrix;
@@ -267,37 +298,10 @@ pub fn end_frame(
stage: Res<XrStage>, stage: Res<XrStage>,
display_time: Res<XrTime>, display_time: Res<XrTime>,
graphics_info: Res<XrGraphicsInfo>, graphics_info: Res<XrGraphicsInfo>,
mut openxr_views: Local<Vec<openxr::View>>, openxr_views: Res<XrViews>,
) { ) {
let _span = info_span!("xr_end_frame"); let _span = info_span!("xr_end_frame");
swapchain.release_image().unwrap(); swapchain.release_image().unwrap();
let (flags, views) = session
.locate_views(
openxr::ViewConfigurationType::PRIMARY_STEREO,
**display_time,
&stage,
)
.expect("Failed to locate views");
if openxr_views.len() != views.len() {
openxr_views.resize(views.len(), default());
}
match (
flags & ViewStateFlags::ORIENTATION_VALID == ViewStateFlags::ORIENTATION_VALID,
flags & ViewStateFlags::POSITION_VALID == ViewStateFlags::POSITION_VALID,
) {
(true, true) => *openxr_views = views,
(true, false) => {
for (i, view) in openxr_views.iter_mut().enumerate() {
view.pose.orientation = views[i].pose.orientation;
}
}
(false, true) => {
for (i, view) in openxr_views.iter_mut().enumerate() {
view.pose.position = views[i].pose.position;
}
}
(false, false) => {}
}
let rect = openxr::Rect2Di { let rect = openxr::Rect2Di {
offset: openxr::Offset2Di { x: 0, y: 0 }, offset: openxr::Offset2Di { x: 0, y: 0 },
extent: openxr::Extent2Di { extent: openxr::Extent2Di {
@@ -314,8 +318,8 @@ pub fn end_frame(
.space(&stage) .space(&stage)
.views(&[ .views(&[
CompositionLayerProjectionView::new() CompositionLayerProjectionView::new()
.pose(openxr_views[0].pose) .pose(openxr_views.0[0].1.pose)
.fov(openxr_views[0].fov) .fov(openxr_views.0[0].1.fov)
.sub_image( .sub_image(
SwapchainSubImage::new() SwapchainSubImage::new()
.swapchain(&swapchain) .swapchain(&swapchain)
@@ -323,8 +327,8 @@ pub fn end_frame(
.image_rect(rect), .image_rect(rect),
), ),
CompositionLayerProjectionView::new() CompositionLayerProjectionView::new()
.pose(openxr_views[1].pose) .pose(openxr_views.0[1].1.pose)
.fov(openxr_views[1].fov) .fov(openxr_views.0[1].1.fov)
.sub_image( .sub_image(
SwapchainSubImage::new() SwapchainSubImage::new()
.swapchain(&swapchain) .swapchain(&swapchain)

View File

@@ -278,4 +278,4 @@ pub struct XrGraphicsInfo {
} }
#[derive(Clone, Resource, ExtractResource)] #[derive(Clone, Resource, ExtractResource)]
pub struct XrViews(pub Vec<Entity>); pub struct XrViews(pub Vec<(Entity, openxr::View)>);

View File

@@ -52,7 +52,7 @@ impl Default for XrProjection {
/// Marker component for an XR view. It is the backends responsibility to update this. /// Marker component for an XR view. It is the backends responsibility to update this.
#[derive(Clone, Copy, Component, Debug, Default)] #[derive(Clone, Copy, Component, Debug, Default)]
pub struct XrView; pub struct XrCamera;
impl CameraProjection for XrProjection { impl CameraProjection for XrProjection {
fn get_projection_matrix(&self) -> Mat4 { fn get_projection_matrix(&self) -> Mat4 {
@@ -106,7 +106,7 @@ pub struct XrCameraBundle {
pub color_grading: ColorGrading, pub color_grading: ColorGrading,
pub exposure: Exposure, pub exposure: Exposure,
pub main_texture_usages: CameraMainTextureUsages, pub main_texture_usages: CameraMainTextureUsages,
pub view: XrView, pub view: XrCamera,
} }
impl Default for XrCameraBundle { impl Default for XrCameraBundle {
@@ -125,7 +125,7 @@ impl Default for XrCameraBundle {
exposure: Default::default(), exposure: Default::default(),
main_texture_usages: Default::default(), main_texture_usages: Default::default(),
dither: DebandDither::Enabled, dither: DebandDither::Enabled,
view: XrView, view: XrCamera,
} }
} }
} }