input refactor
This commit is contained in:
14
src/xr_input/controllers.rs
Normal file
14
src/xr_input/controllers.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
use openxr::{Action, ActionTy};
|
||||
|
||||
pub struct Touchable<T: ActionTy> {
|
||||
pub inner: Action<T>,
|
||||
pub touch: Action<bool>,
|
||||
}
|
||||
pub struct Handed<T> {
|
||||
pub left: T,
|
||||
pub right: T,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum XrControllerType {
|
||||
OculusTouch,
|
||||
}
|
||||
88
src/xr_input/mod.rs
Normal file
88
src/xr_input/mod.rs
Normal file
@@ -0,0 +1,88 @@
|
||||
pub mod controllers;
|
||||
pub mod oculus_touch;
|
||||
pub mod xr_camera;
|
||||
|
||||
use crate::resources::XrSession;
|
||||
use crate::xr_input::controllers::XrControllerType;
|
||||
use crate::xr_input::oculus_touch::{setup_oculus_controller, ActionSets};
|
||||
use crate::xr_input::xr_camera::{
|
||||
xr_camera_head_sync, Eye, XRProjection, XrCameraBundle, XrCamerasBundle,
|
||||
};
|
||||
use bevy::app::{App, PostUpdate, Startup};
|
||||
use bevy::log::{info, warn};
|
||||
use bevy::prelude::IntoSystemConfigs;
|
||||
use bevy::prelude::{
|
||||
Commands, Component, IntoSystemSetConfigs, Plugin, PreUpdate, Quat, Res, Resource, Vec3,
|
||||
};
|
||||
use bevy::render::camera::CameraProjectionPlugin;
|
||||
use bevy::render::view::{update_frusta, VisibilitySystems};
|
||||
use bevy::transform::TransformSystem;
|
||||
use openxr::{Action, ActionSet, ActionTy};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct OpenXrInput {
|
||||
pub controller_type: XrControllerType,
|
||||
}
|
||||
impl OpenXrInput {
|
||||
pub fn new(controller_type: XrControllerType) -> Self {
|
||||
Self { controller_type }
|
||||
}
|
||||
}
|
||||
|
||||
impl Plugin for OpenXrInput {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_plugins(CameraProjectionPlugin::<XRProjection>::default());
|
||||
match self.controller_type {
|
||||
XrControllerType::OculusTouch => {
|
||||
app.add_systems(Startup, setup_oculus_controller);
|
||||
}
|
||||
}
|
||||
app.add_systems(PreUpdate, action_set_system);
|
||||
app.add_systems(PreUpdate, xr_camera_head_sync);
|
||||
app.add_systems(
|
||||
PostUpdate,
|
||||
update_frusta::<XRProjection>
|
||||
.after(TransformSystem::TransformPropagate)
|
||||
.before(VisibilitySystems::UpdatePerspectiveFrusta),
|
||||
);
|
||||
app.add_systems(Startup, setup_xr_cameras);
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_xr_cameras(mut commands: Commands) {
|
||||
commands.spawn(XrCameraBundle::new(Eye::Right));
|
||||
commands.spawn(XrCameraBundle::new(Eye::Left));
|
||||
}
|
||||
|
||||
fn action_set_system(action_sets: Res<ActionSets>, session: Res<XrSession>) {
|
||||
let mut active_action_sets = vec![];
|
||||
for i in &action_sets.0 {
|
||||
active_action_sets.push(openxr::ActiveActionSet::new(i));
|
||||
}
|
||||
info!("action sets: {:#?}", action_sets.0.len());
|
||||
match session.sync_actions(&active_action_sets) {
|
||||
Err(err) => {
|
||||
warn!("{}", err);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Vec3Conv {
|
||||
fn to_vec3(&self) -> Vec3;
|
||||
}
|
||||
|
||||
impl Vec3Conv for openxr::Vector3f {
|
||||
fn to_vec3(&self) -> Vec3 {
|
||||
Vec3::new(self.x, self.y, self.z)
|
||||
}
|
||||
}
|
||||
pub trait QuatConv {
|
||||
fn to_quat(&self) -> Quat;
|
||||
}
|
||||
|
||||
impl QuatConv for openxr::Quaternionf {
|
||||
fn to_quat(&self) -> Quat {
|
||||
Quat::from_xyzw(self.x, self.y, self.z, self.w)
|
||||
}
|
||||
}
|
||||
254
src/xr_input/oculus_touch.rs
Normal file
254
src/xr_input/oculus_touch.rs
Normal file
@@ -0,0 +1,254 @@
|
||||
use crate::resources::{XrInstance, XrSession};
|
||||
use crate::xr_input::controllers::{Handed, Touchable};
|
||||
use crate::FutureXrResources;
|
||||
use bevy::prelude::{Commands, Res, Resource};
|
||||
use openxr::{Action, ActionSet, AnyGraphics, Binding, Haptic, Instance, Posef, Session, Space};
|
||||
use std::any::Any;
|
||||
|
||||
pub fn setup_oculus_controller(
|
||||
mut commands: Commands,
|
||||
instance: Res<XrInstance>,
|
||||
session: Res<XrSession>,
|
||||
) {
|
||||
let mut action_sets = vec![];
|
||||
let oculus_controller = OculusController::new(
|
||||
Instance::clone(&instance),
|
||||
Session::clone(&session),
|
||||
&mut action_sets,
|
||||
)
|
||||
.unwrap();
|
||||
session
|
||||
.attach_action_sets(&action_sets.iter().map(|a| a).collect::<Vec<_>>())
|
||||
.unwrap();
|
||||
commands.insert_resource(oculus_controller);
|
||||
commands.insert_resource(ActionSets(action_sets));
|
||||
}
|
||||
|
||||
#[derive(Resource, Clone)]
|
||||
pub struct ActionSets(pub Vec<ActionSet>);
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct OculusController {
|
||||
pub grip_space: Handed<Space>,
|
||||
pub aim_space: Handed<Space>,
|
||||
pub grip_pose: Action<Posef>,
|
||||
pub aim_pose: Action<Posef>,
|
||||
pub squeeze: Action<f32>,
|
||||
pub trigger: Touchable<f32>,
|
||||
pub haptic_feedback: Action<Haptic>,
|
||||
pub x_button: Touchable<bool>,
|
||||
pub y_button: Touchable<bool>,
|
||||
pub menu_button: Action<bool>,
|
||||
pub a_button: Touchable<bool>,
|
||||
pub b_button: Touchable<bool>,
|
||||
pub thumbstick_x: Action<f32>,
|
||||
pub thumbstick_y: Action<f32>,
|
||||
pub thumbstick_touch: Action<bool>,
|
||||
pub thumbstick_click: Action<bool>,
|
||||
pub thumbrest_touch: Action<bool>,
|
||||
}
|
||||
impl OculusController {
|
||||
pub fn new(
|
||||
instance: Instance,
|
||||
session: Session<AnyGraphics>,
|
||||
action_sets: &mut Vec<ActionSet>,
|
||||
) -> anyhow::Result<Self> {
|
||||
let action_set =
|
||||
instance.create_action_set("oculus_input", "Oculus Touch Controller Input", 0)?;
|
||||
let left_path = instance.string_to_path("/user/hand/left").unwrap();
|
||||
let right_path = instance.string_to_path("/user/hand/right").unwrap();
|
||||
let hands = [left_path, right_path];
|
||||
let grip_pose = action_set.create_action::<Posef>("hand_pose", "Hand Pose", &hands)?;
|
||||
let aim_pose = action_set.create_action::<Posef>("pointer_pose", "Pointer Pose", &hands)?;
|
||||
|
||||
let this = OculusController {
|
||||
grip_space: Handed {
|
||||
left: grip_pose.create_space(session.clone(), right_path, Posef::IDENTITY)?,
|
||||
right: grip_pose.create_space(session.clone(), left_path, Posef::IDENTITY)?,
|
||||
},
|
||||
aim_space: Handed {
|
||||
left: aim_pose.create_space(session.clone(), right_path, Posef::IDENTITY)?,
|
||||
right: aim_pose.create_space(session.clone(), left_path, Posef::IDENTITY)?,
|
||||
},
|
||||
grip_pose,
|
||||
aim_pose,
|
||||
squeeze: action_set.create_action("squeeze", "Grip Pull", &hands)?,
|
||||
trigger: Touchable {
|
||||
inner: action_set.create_action("trigger", "Trigger Pull", &hands)?,
|
||||
touch: action_set.create_action("trigger_touched", "Trigger Touch", &hands)?,
|
||||
},
|
||||
haptic_feedback: action_set.create_action(
|
||||
"haptic_feedback",
|
||||
"Haptic Feedback",
|
||||
&hands,
|
||||
)?,
|
||||
x_button: Touchable {
|
||||
inner: action_set.create_action("x_button", "X Button", &[])?,
|
||||
touch: action_set.create_action("x_button_touch", "X Button Touch", &[])?,
|
||||
},
|
||||
y_button: Touchable {
|
||||
inner: action_set.create_action("y_button", "Y Button", &[])?,
|
||||
touch: action_set.create_action("y_button_touch", "Y Button Touch", &[])?,
|
||||
},
|
||||
menu_button: action_set.create_action("menu_button", "Menu Button", &[])?,
|
||||
a_button: Touchable {
|
||||
inner: action_set.create_action("a_button", "A Button", &[])?,
|
||||
touch: action_set.create_action("a_button_touch", "A Button Touch", &[])?,
|
||||
},
|
||||
b_button: Touchable {
|
||||
inner: action_set.create_action("b_button", "B Button", &[])?,
|
||||
touch: action_set.create_action("b_button_touch", "B Button Touch", &[])?,
|
||||
},
|
||||
thumbstick_x: action_set.create_action("thumbstick_x", "Thumbstick X", &hands)?,
|
||||
thumbstick_y: action_set.create_action("thumbstick_y", "Thumbstick Y", &hands)?,
|
||||
thumbstick_touch: action_set.create_action(
|
||||
"thumbstick_touch",
|
||||
"Thumbstick Touch",
|
||||
&hands,
|
||||
)?,
|
||||
thumbstick_click: action_set.create_action(
|
||||
"thumbstick_click",
|
||||
"Thumbstick Click",
|
||||
&hands,
|
||||
)?,
|
||||
thumbrest_touch: action_set.create_action(
|
||||
"thumbrest_touch",
|
||||
"Thumbrest Touch",
|
||||
&hands,
|
||||
)?,
|
||||
};
|
||||
let i = instance;
|
||||
i.suggest_interaction_profile_bindings(
|
||||
i.string_to_path("/interaction_profiles/oculus/touch_controller")?,
|
||||
&[
|
||||
Binding::new(
|
||||
&this.grip_pose,
|
||||
i.string_to_path("/user/hand/left/input/grip/pose")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.grip_pose,
|
||||
i.string_to_path("/user/hand/right/input/grip/pose")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.aim_pose,
|
||||
i.string_to_path("/user/hand/left/input/aim/pose")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.aim_pose,
|
||||
i.string_to_path("/user/hand/left/input/aim/pose")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.squeeze,
|
||||
i.string_to_path("/user/hand/left/input/squeeze/value")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.squeeze,
|
||||
i.string_to_path("/user/hand/right/input/squeeze/value")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.trigger.inner,
|
||||
i.string_to_path("/user/hand/right/input/trigger/value")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.trigger.inner,
|
||||
i.string_to_path("/user/hand/left/input/trigger/value")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.trigger.touch,
|
||||
i.string_to_path("/user/hand/right/input/trigger/touch")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.trigger.touch,
|
||||
i.string_to_path("/user/hand/left/input/trigger/touch")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.haptic_feedback,
|
||||
i.string_to_path("/user/hand/right/output/haptic")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.haptic_feedback,
|
||||
i.string_to_path("/user/hand/left/output/haptic")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.x_button.inner,
|
||||
i.string_to_path("/user/hand/left/input/x/click")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.x_button.touch,
|
||||
i.string_to_path("/user/hand/left/input/x/touch")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.y_button.inner,
|
||||
i.string_to_path("/user/hand/left/input/y/click")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.y_button.touch,
|
||||
i.string_to_path("/user/hand/left/input/y/touch")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.menu_button,
|
||||
i.string_to_path("/user/hand/left/input/menu/click")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.a_button.inner,
|
||||
i.string_to_path("/user/hand/right/input/a/click")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.a_button.touch,
|
||||
i.string_to_path("/user/hand/right/input/a/touch")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.b_button.inner,
|
||||
i.string_to_path("/user/hand/right/input/b/click")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.b_button.touch,
|
||||
i.string_to_path("/user/hand/right/input/b/touch")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.thumbstick_x,
|
||||
i.string_to_path("/user/hand/left/input/thumbstick/x")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.thumbstick_x,
|
||||
i.string_to_path("/user/hand/right/input/thumbstick/x")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.thumbstick_y,
|
||||
i.string_to_path("/user/hand/left/input/thumbstick/y")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.thumbstick_y,
|
||||
i.string_to_path("/user/hand/right/input/thumbstick/y")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.thumbstick_click,
|
||||
i.string_to_path("/user/hand/left/input/thumbstick/click")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.thumbstick_click,
|
||||
i.string_to_path("/user/hand/right/input/thumbstick/click")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.thumbstick_touch,
|
||||
i.string_to_path("/user/hand/left/input/thumbstick/touch")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.thumbstick_touch,
|
||||
i.string_to_path("/user/hand/right/input/thumbstick/touch")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.thumbrest_touch,
|
||||
i.string_to_path("/user/hand/left/input/thumbrest/touch")?,
|
||||
),
|
||||
Binding::new(
|
||||
&this.thumbrest_touch,
|
||||
i.string_to_path("/user/hand/right/input/thumbrest/touch")?,
|
||||
),
|
||||
],
|
||||
)?;
|
||||
|
||||
action_sets.push(action_set);
|
||||
Ok(this)
|
||||
}
|
||||
}
|
||||
239
src/xr_input/xr_camera.rs
Normal file
239
src/xr_input/xr_camera.rs
Normal file
@@ -0,0 +1,239 @@
|
||||
use crate::xr_input::{QuatConv, Vec3Conv};
|
||||
use crate::{LEFT_XR_TEXTURE_HANDLE, RIGHT_XR_TEXTURE_HANDLE};
|
||||
use bevy::core_pipeline::tonemapping::{DebandDither, Tonemapping};
|
||||
use bevy::prelude::*;
|
||||
use bevy::render::camera::{CameraProjection, CameraRenderGraph, RenderTarget};
|
||||
use bevy::render::primitives::Frustum;
|
||||
use bevy::render::view::{ColorGrading, VisibleEntities};
|
||||
use openxr::Fovf;
|
||||
|
||||
#[derive(Bundle)]
|
||||
pub struct XrCamerasBundle {
|
||||
pub left: XrCameraBundle,
|
||||
pub right: XrCameraBundle,
|
||||
}
|
||||
impl XrCamerasBundle {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
impl Default for XrCamerasBundle {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
left: XrCameraBundle::new(Eye::Left),
|
||||
right: XrCameraBundle::new(Eye::Right),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Bundle)]
|
||||
pub struct XrCameraBundle {
|
||||
pub camera: Camera,
|
||||
pub camera_render_graph: CameraRenderGraph,
|
||||
pub xr_projection: XRProjection,
|
||||
pub visible_entities: VisibleEntities,
|
||||
pub frustum: Frustum,
|
||||
pub transform: Transform,
|
||||
pub global_transform: GlobalTransform,
|
||||
pub camera_3d: Camera3d,
|
||||
pub tonemapping: Tonemapping,
|
||||
pub dither: DebandDither,
|
||||
pub color_grading: ColorGrading,
|
||||
pub xr_camera_type: XrCameraType,
|
||||
}
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Component)]
|
||||
pub enum XrCameraType {
|
||||
Xr(Eye),
|
||||
Flatscreen,
|
||||
}
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
||||
pub enum Eye {
|
||||
Left = 0,
|
||||
Right = 1,
|
||||
}
|
||||
|
||||
impl XrCameraBundle {
|
||||
pub fn new(eye: Eye) -> Self {
|
||||
Self {
|
||||
camera: Camera {
|
||||
order: -1,
|
||||
target: RenderTarget::TextureView(match eye {
|
||||
Eye::Left => LEFT_XR_TEXTURE_HANDLE,
|
||||
Eye::Right => RIGHT_XR_TEXTURE_HANDLE,
|
||||
}),
|
||||
viewport: None,
|
||||
..default()
|
||||
},
|
||||
camera_render_graph: CameraRenderGraph::new(bevy::core_pipeline::core_3d::graph::NAME),
|
||||
xr_projection: Default::default(),
|
||||
visible_entities: Default::default(),
|
||||
frustum: Default::default(),
|
||||
transform: Default::default(),
|
||||
global_transform: Default::default(),
|
||||
camera_3d: Default::default(),
|
||||
tonemapping: Default::default(),
|
||||
dither: DebandDither::Enabled,
|
||||
color_grading: Default::default(),
|
||||
xr_camera_type: XrCameraType::Xr(eye),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Component, Reflect)]
|
||||
#[reflect(Component, Default)]
|
||||
pub struct XRProjection {
|
||||
pub near: f32,
|
||||
pub far: f32,
|
||||
#[reflect(ignore)]
|
||||
pub fov: Fovf,
|
||||
}
|
||||
|
||||
impl Default for XRProjection {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
near: 0.1,
|
||||
far: 1000.,
|
||||
fov: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl XRProjection {
|
||||
pub fn new(near: f32, far: f32, fov: Fovf) -> Self {
|
||||
XRProjection { near, far, fov }
|
||||
}
|
||||
}
|
||||
|
||||
impl CameraProjection for XRProjection {
|
||||
// =============================================================================
|
||||
// math code adapted from
|
||||
// https://github.com/KhronosGroup/OpenXR-SDK-Source/blob/master/src/common/xr_linear.h
|
||||
// Copyright (c) 2017 The Khronos Group Inc.
|
||||
// Copyright (c) 2016 Oculus VR, LLC.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// =============================================================================
|
||||
fn get_projection_matrix(&self) -> Mat4 {
|
||||
// symmetric perspective for debugging
|
||||
// let x_fov = (self.fov.angle_left.abs() + self.fov.angle_right.abs());
|
||||
// let y_fov = (self.fov.angle_up.abs() + self.fov.angle_down.abs());
|
||||
// return Mat4::perspective_infinite_reverse_rh(y_fov, x_fov / y_fov, self.near);
|
||||
|
||||
let fov = self.fov;
|
||||
let is_vulkan_api = false; // FIXME wgpu probably abstracts this
|
||||
let near_z = self.near;
|
||||
let far_z = -1.; // use infinite proj
|
||||
// let far_z = self.far;
|
||||
|
||||
let tan_angle_left = fov.angle_left.tan();
|
||||
let tan_angle_right = fov.angle_right.tan();
|
||||
|
||||
let tan_angle_down = fov.angle_down.tan();
|
||||
let tan_angle_up = fov.angle_up.tan();
|
||||
|
||||
let tan_angle_width = tan_angle_right - tan_angle_left;
|
||||
|
||||
// Set to tanAngleDown - tanAngleUp for a clip space with positive Y
|
||||
// down (Vulkan). Set to tanAngleUp - tanAngleDown for a clip space with
|
||||
// positive Y up (OpenGL / D3D / Metal).
|
||||
// const float tanAngleHeight =
|
||||
// graphicsApi == GRAPHICS_VULKAN ? (tanAngleDown - tanAngleUp) : (tanAngleUp - tanAngleDown);
|
||||
let tan_angle_height = if is_vulkan_api {
|
||||
tan_angle_down - tan_angle_up
|
||||
} else {
|
||||
tan_angle_up - tan_angle_down
|
||||
};
|
||||
|
||||
// Set to nearZ for a [-1,1] Z clip space (OpenGL / OpenGL ES).
|
||||
// Set to zero for a [0,1] Z clip space (Vulkan / D3D / Metal).
|
||||
// const float offsetZ =
|
||||
// (graphicsApi == GRAPHICS_OPENGL || graphicsApi == GRAPHICS_OPENGL_ES) ? nearZ : 0;
|
||||
// FIXME handle enum of graphics apis
|
||||
let offset_z = 0.;
|
||||
|
||||
let mut cols: [f32; 16] = [0.0; 16];
|
||||
|
||||
if far_z <= near_z {
|
||||
// place the far plane at infinity
|
||||
cols[0] = 2. / tan_angle_width;
|
||||
cols[4] = 0.;
|
||||
cols[8] = (tan_angle_right + tan_angle_left) / tan_angle_width;
|
||||
cols[12] = 0.;
|
||||
|
||||
cols[1] = 0.;
|
||||
cols[5] = 2. / tan_angle_height;
|
||||
cols[9] = (tan_angle_up + tan_angle_down) / tan_angle_height;
|
||||
cols[13] = 0.;
|
||||
|
||||
cols[2] = 0.;
|
||||
cols[6] = 0.;
|
||||
cols[10] = -1.;
|
||||
cols[14] = -(near_z + offset_z);
|
||||
|
||||
cols[3] = 0.;
|
||||
cols[7] = 0.;
|
||||
cols[11] = -1.;
|
||||
cols[15] = 0.;
|
||||
|
||||
// bevy uses the _reverse_ infinite projection
|
||||
// https://dev.theomader.com/depth-precision/
|
||||
let z_reversal = Mat4::from_cols_array_2d(&[
|
||||
[1f32, 0., 0., 0.],
|
||||
[0., 1., 0., 0.],
|
||||
[0., 0., -1., 0.],
|
||||
[0., 0., 1., 1.],
|
||||
]);
|
||||
|
||||
return z_reversal * Mat4::from_cols_array(&cols);
|
||||
} else {
|
||||
// normal projection
|
||||
cols[0] = 2. / tan_angle_width;
|
||||
cols[4] = 0.;
|
||||
cols[8] = (tan_angle_right + tan_angle_left) / tan_angle_width;
|
||||
cols[12] = 0.;
|
||||
|
||||
cols[1] = 0.;
|
||||
cols[5] = 2. / tan_angle_height;
|
||||
cols[9] = (tan_angle_up + tan_angle_down) / tan_angle_height;
|
||||
cols[13] = 0.;
|
||||
|
||||
cols[2] = 0.;
|
||||
cols[6] = 0.;
|
||||
cols[10] = -(far_z + offset_z) / (far_z - near_z);
|
||||
cols[14] = -(far_z * (near_z + offset_z)) / (far_z - near_z);
|
||||
|
||||
cols[3] = 0.;
|
||||
cols[7] = 0.;
|
||||
cols[11] = -1.;
|
||||
cols[15] = 0.;
|
||||
}
|
||||
|
||||
Mat4::from_cols_array(&cols)
|
||||
}
|
||||
|
||||
fn update(&mut self, _width: f32, _height: f32) {}
|
||||
|
||||
fn far(&self) -> f32 {
|
||||
self.far
|
||||
}
|
||||
}
|
||||
|
||||
pub fn xr_camera_head_sync(
|
||||
views: ResMut<crate::resources::XrViews>,
|
||||
mut query: Query<(&mut Transform, &XrCameraType, &mut XRProjection)>,
|
||||
) {
|
||||
let mut f = || -> Option<()> {
|
||||
for (mut transform, camera_type, mut xr_projection) in query.iter_mut() {
|
||||
let view_idx = match camera_type {
|
||||
XrCameraType::Xr(eye) => *eye as usize,
|
||||
XrCameraType::Flatscreen => return None,
|
||||
};
|
||||
let v = views.lock().unwrap();
|
||||
let view = v.get(view_idx)?;
|
||||
xr_projection.fov = view.fov;
|
||||
transform.rotation = view.pose.orientation.to_quat();
|
||||
transform.translation = view.pose.position.to_vec3();
|
||||
}
|
||||
Some(())
|
||||
};
|
||||
let _ = f();
|
||||
}
|
||||
Reference in New Issue
Block a user