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::event::EventWriter;
|
||||||
|
use bevy::ecs::query::{With, Without};
|
||||||
use bevy::ecs::schedule::common_conditions::{not, on_event};
|
use bevy::ecs::schedule::common_conditions::{not, on_event};
|
||||||
use bevy::ecs::schedule::IntoSystemConfigs;
|
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::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::math::{uvec2, UVec2};
|
||||||
|
use bevy::prelude::{Deref, DerefMut};
|
||||||
|
use bevy::render::extract_component::{ExtractComponent, ExtractComponentPlugin};
|
||||||
use bevy::render::extract_resource::ExtractResourcePlugin;
|
use bevy::render::extract_resource::ExtractResourcePlugin;
|
||||||
use bevy::render::renderer::{
|
use bevy::render::renderer::{
|
||||||
RenderAdapter, RenderAdapterInfo, RenderDevice, RenderInstance, RenderQueue,
|
RenderAdapter, RenderAdapterInfo, RenderDevice, RenderInstance, RenderQueue,
|
||||||
};
|
};
|
||||||
use bevy::render::settings::RenderCreation;
|
use bevy::render::settings::RenderCreation;
|
||||||
use bevy::render::{ExtractSchedule, MainWorld, RenderApp, RenderPlugin};
|
use bevy::render::{ExtractSchedule, MainWorld, RenderApp, RenderPlugin};
|
||||||
|
use bevy::transform::components::GlobalTransform;
|
||||||
|
use bevy::transform::{TransformBundle, TransformSystem};
|
||||||
use bevy_xr::session::{
|
use bevy_xr::session::{
|
||||||
BeginXrSession, CreateXrSession, XrInstanceCreated, XrInstanceDestroyed, XrSessionState,
|
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,
|
synchronous_pipeline_compilation: config.synchronous_pipeline_compilation,
|
||||||
},
|
},
|
||||||
|
ExtractComponentPlugin::<XrRoot>::default(),
|
||||||
ExtractResourcePlugin::<XrTime>::default(),
|
ExtractResourcePlugin::<XrTime>::default(),
|
||||||
ExtractResourcePlugin::<XrStatus>::default(),
|
ExtractResourcePlugin::<XrStatus>::default(),
|
||||||
))
|
))
|
||||||
@@ -165,9 +174,14 @@ fn init_xr(config: &XrInitPlugin, app: &mut App) -> Result<()> {
|
|||||||
begin_xr_session
|
begin_xr_session
|
||||||
.run_if(session_ready)
|
.run_if(session_ready)
|
||||||
.run_if(on_event::<BeginXrSession>()),
|
.run_if(on_event::<BeginXrSession>()),
|
||||||
|
adopt_open_xr_trackers,
|
||||||
)
|
)
|
||||||
.chain(),
|
.chain(),
|
||||||
)
|
)
|
||||||
|
.add_systems(
|
||||||
|
PostUpdate,
|
||||||
|
update_root_transform_components.after(TransformSystem::TransformPropagate),
|
||||||
|
)
|
||||||
.sub_app_mut(RenderApp)
|
.sub_app_mut(RenderApp)
|
||||||
.insert_resource(instance)
|
.insert_resource(instance)
|
||||||
.insert_resource(SystemId(system_id))
|
.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)),
|
transfer_xr_resources.run_if(not(session_running)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
app.world
|
||||||
|
.spawn((TransformBundle::default(), OpenXrTrackingRoot));
|
||||||
|
|
||||||
Ok(())
|
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.
|
/// This is used to store information from startup that is needed to create the session after the instance has been created.
|
||||||
struct XrSessionInitConfig {
|
struct XrSessionInitConfig {
|
||||||
/// List of blend modes the openxr session can use. If [None], pick the first available blend mode.
|
/// List of blend modes the openxr session can use. If [None], pick the first available blend mode.
|
||||||
|
|||||||
@@ -2,17 +2,17 @@ use bevy::{
|
|||||||
prelude::*,
|
prelude::*,
|
||||||
render::{
|
render::{
|
||||||
camera::{ManualTextureView, ManualTextureViewHandle, ManualTextureViews, RenderTarget},
|
camera::{ManualTextureView, ManualTextureViewHandle, ManualTextureViews, RenderTarget},
|
||||||
extract_component::{ExtractComponent, ExtractComponentPlugin},
|
|
||||||
extract_resource::ExtractResourcePlugin,
|
extract_resource::ExtractResourcePlugin,
|
||||||
renderer::render_system,
|
renderer::render_system,
|
||||||
|
view::ExtractedView,
|
||||||
Render, RenderApp, RenderSet,
|
Render, RenderApp, RenderSet,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use bevy_xr::camera::{XrCamera, XrCameraBundle, XrProjection};
|
use bevy_xr::camera::{XrCamera, XrCameraBundle, XrProjection};
|
||||||
use openxr::{CompositionLayerFlags, ViewStateFlags};
|
use openxr::{CompositionLayerFlags, ViewStateFlags};
|
||||||
|
|
||||||
use crate::resources::*;
|
use crate::{init::OpenXrTracker, resources::*};
|
||||||
use crate::{init::begin_xr_session, layer_builder::*};
|
use crate::{init::XrRoot, layer_builder::*};
|
||||||
|
|
||||||
use crate::init::session_running;
|
use crate::init::session_running;
|
||||||
|
|
||||||
@@ -20,24 +20,27 @@ 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_plugins((
|
app.add_plugins((ExtractResourcePlugin::<XrViews>::default(),))
|
||||||
ExtractComponentPlugin::<XrView>::default(),
|
.add_systems(
|
||||||
ExtractResourcePlugin::<XrViews>::default(),
|
PreUpdate,
|
||||||
))
|
(
|
||||||
.add_systems(
|
init_views.run_if(resource_added::<XrGraphicsInfo>),
|
||||||
First,
|
wait_frame.run_if(session_running),
|
||||||
(
|
locate_views.run_if(session_running),
|
||||||
init_views.run_if(resource_added::<XrGraphicsInfo>),
|
update_views.run_if(session_running),
|
||||||
wait_frame.run_if(session_running),
|
)
|
||||||
)
|
.chain(),
|
||||||
.after(begin_xr_session),
|
);
|
||||||
)
|
|
||||||
.add_systems(PreUpdate, update_views.run_if(session_running));
|
|
||||||
// .add_systems(Startup, init_views);
|
// .add_systems(Startup, init_views);
|
||||||
app.sub_app_mut(RenderApp).add_systems(
|
app.sub_app_mut(RenderApp).add_systems(
|
||||||
Render,
|
Render,
|
||||||
(
|
(
|
||||||
insert_texture_views
|
(
|
||||||
|
locate_views,
|
||||||
|
update_views_render_world,
|
||||||
|
insert_texture_views,
|
||||||
|
)
|
||||||
|
.chain()
|
||||||
.in_set(RenderSet::PrepareAssets)
|
.in_set(RenderSet::PrepareAssets)
|
||||||
.before(render_system),
|
.before(render_system),
|
||||||
end_frame.in_set(RenderSet::Cleanup),
|
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;
|
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.
|
||||||
@@ -69,16 +69,19 @@ pub fn init_views(
|
|||||||
let view_handle =
|
let view_handle =
|
||||||
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
|
commands.spawn((
|
||||||
.spawn((XrCameraBundle {
|
XrCameraBundle {
|
||||||
camera: Camera {
|
camera: Camera {
|
||||||
target: RenderTarget::TextureView(view_handle),
|
target: RenderTarget::TextureView(view_handle),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
view: XrCamera(index),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},))
|
},
|
||||||
.id();
|
OpenXrTracker,
|
||||||
views.push((entity, default()));
|
XrRoot::default(),
|
||||||
|
));
|
||||||
|
views.push(default());
|
||||||
}
|
}
|
||||||
commands.insert_resource(XrViews(views));
|
commands.insert_resource(XrViews(views));
|
||||||
}
|
}
|
||||||
@@ -92,21 +95,17 @@ pub fn wait_frame(
|
|||||||
let state = frame_waiter.wait().expect("Failed to 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.
|
// 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
|
// TODO: don't add predicted_display_period if pipelined rendering plugin not enabled
|
||||||
commands.insert_resource(XrTime(openxr::Time::from_nanos(
|
commands.insert_resource(XrTime(state.predicted_display_time));
|
||||||
state.predicted_display_time.as_nanos(),
|
|
||||||
)));
|
|
||||||
frame_stream.begin().expect("Failed to begin frame");
|
frame_stream.begin().expect("Failed to begin frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_views(
|
pub fn locate_views(
|
||||||
mut views: Query<(&mut Transform, &mut XrProjection), With<XrCamera>>,
|
|
||||||
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>>,
|
mut openxr_views: ResMut<XrViews>,
|
||||||
) {
|
) {
|
||||||
let _span = info_span!("xr_update_views");
|
let _span = info_span!("xr_locate_views");
|
||||||
let (flags, xr_views) = session
|
let (flags, xr_views) = session
|
||||||
.locate_views(
|
.locate_views(
|
||||||
openxr::ViewConfigurationType::PRIMARY_STEREO,
|
openxr::ViewConfigurationType::PRIMARY_STEREO,
|
||||||
@@ -121,7 +120,7 @@ pub fn update_views(
|
|||||||
flags & ViewStateFlags::ORIENTATION_VALID == ViewStateFlags::ORIENTATION_VALID,
|
flags & ViewStateFlags::ORIENTATION_VALID == ViewStateFlags::ORIENTATION_VALID,
|
||||||
flags & ViewStateFlags::POSITION_VALID == ViewStateFlags::POSITION_VALID,
|
flags & ViewStateFlags::POSITION_VALID == ViewStateFlags::POSITION_VALID,
|
||||||
) {
|
) {
|
||||||
(true, true) => *openxr_views = xr_views,
|
(true, true) => *openxr_views = XrViews(xr_views),
|
||||||
(true, false) => {
|
(true, false) => {
|
||||||
for (i, view) in openxr_views.iter_mut().enumerate() {
|
for (i, view) in openxr_views.iter_mut().enumerate() {
|
||||||
view.pose.orientation = xr_views[i].pose.orientation;
|
view.pose.orientation = xr_views[i].pose.orientation;
|
||||||
@@ -134,24 +133,45 @@ pub fn update_views(
|
|||||||
}
|
}
|
||||||
(false, false) => {}
|
(false, false) => {}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (i, view) in openxr_views.iter().enumerate() {
|
pub fn update_views(
|
||||||
if let Some(((mut transform, mut projection), xr_view)) = view_entities
|
mut query: Query<(&mut Transform, &mut XrProjection, &XrCamera)>,
|
||||||
.0
|
views: ResMut<XrViews>,
|
||||||
.get_mut(i)
|
) {
|
||||||
.and_then(|(entity, view)| views.get_mut(*entity).ok().map(|res| (res, view)))
|
for (mut transform, mut projection, camera) in query.iter_mut() {
|
||||||
{
|
let Some(view) = views.get(camera.0 as usize) else {
|
||||||
*xr_view = *view;
|
continue;
|
||||||
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 projection_matrix = calculate_projection(projection.near, view.fov);
|
||||||
let rotation = Quat::from_xyzw(x, y, z, w);
|
projection.projection_matrix = projection_matrix;
|
||||||
transform.rotation = rotation;
|
|
||||||
let openxr::Vector3f { x, y, z } = view.pose.position;
|
let openxr::Quaternionf { x, y, z, w } = view.pose.orientation;
|
||||||
let translation = Vec3::new(x, y, z);
|
let rotation = Quat::from_xyzw(x, y, z, w);
|
||||||
transform.translation = translation;
|
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<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)
|
.space(&stage)
|
||||||
.views(&[
|
.views(&[
|
||||||
CompositionLayerProjectionView::new()
|
CompositionLayerProjectionView::new()
|
||||||
.pose(openxr_views.0[0].1.pose)
|
.pose(openxr_views.0[0].pose)
|
||||||
.fov(openxr_views.0[0].1.fov)
|
.fov(openxr_views.0[0].fov)
|
||||||
.sub_image(
|
.sub_image(
|
||||||
SwapchainSubImage::new()
|
SwapchainSubImage::new()
|
||||||
.swapchain(&swapchain)
|
.swapchain(&swapchain)
|
||||||
@@ -326,8 +346,8 @@ pub fn end_frame(
|
|||||||
.image_rect(rect),
|
.image_rect(rect),
|
||||||
),
|
),
|
||||||
CompositionLayerProjectionView::new()
|
CompositionLayerProjectionView::new()
|
||||||
.pose(openxr_views.0[1].1.pose)
|
.pose(openxr_views.0[1].pose)
|
||||||
.fov(openxr_views.0[1].1.fov)
|
.fov(openxr_views.0[1].fov)
|
||||||
.sub_image(
|
.sub_image(
|
||||||
SwapchainSubImage::new()
|
SwapchainSubImage::new()
|
||||||
.swapchain(&swapchain)
|
.swapchain(&swapchain)
|
||||||
|
|||||||
@@ -278,5 +278,5 @@ pub struct XrGraphicsInfo {
|
|||||||
pub format: wgpu::TextureFormat,
|
pub format: wgpu::TextureFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Resource, ExtractResource)]
|
#[derive(Clone, Resource, ExtractResource, Deref, DerefMut)]
|
||||||
pub struct XrViews(pub Vec<(Entity, openxr::View)>);
|
pub struct XrViews(pub Vec<openxr::View>);
|
||||||
|
|||||||
@@ -30,7 +30,10 @@ impl Plugin for XrCameraPlugin {
|
|||||||
.after(TransformSystem::TransformPropagate)
|
.after(TransformSystem::TransformPropagate)
|
||||||
.before(VisibilitySystems::UpdatePerspectiveFrusta),
|
.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.
|
/// Marker component for an XR view. It is the backends responsibility to update this.
|
||||||
#[derive(Clone, Copy, Component, Debug, Default)]
|
#[derive(Clone, Copy, Component, ExtractComponent, Debug, Default)]
|
||||||
pub struct XrCamera;
|
pub struct XrCamera(pub u32);
|
||||||
|
|
||||||
impl CameraProjection for XrProjection {
|
impl CameraProjection for XrProjection {
|
||||||
fn get_projection_matrix(&self) -> Mat4 {
|
fn get_projection_matrix(&self) -> Mat4 {
|
||||||
@@ -125,7 +128,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: XrCamera,
|
view: XrCamera(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user