Fix directional light shadows: take two
This PR aims to do the same as #180, but hopefully without making future WebXR compat more annoying. get_frustum_corners() is now implemented properly, directly from the projection matrix. I believe it should work with the existing OpenXR code, but I cannot test this with any WebXR implementations with "sheared projection matrices", because I am continuing to doubt whether that even exists. I also added unit tests, which involved a decent amount of code shuffling regardless. The original implementation from #180 is left in as a control in the test code.
This commit is contained in:
@@ -10,7 +10,7 @@ use bevy::{
|
||||
transform::TransformSystem,
|
||||
};
|
||||
use bevy_mod_xr::{
|
||||
camera::{XrCamera, XrProjection, XrViewInit},
|
||||
camera::{calculate_projection, Fov, XrCamera, XrProjection, XrViewInit},
|
||||
session::{
|
||||
XrFirst, XrHandleEvents, XrPreDestroySession, XrRenderSet, XrRootTransform,
|
||||
XrSessionCreated,
|
||||
@@ -252,7 +252,15 @@ pub fn update_views(
|
||||
continue;
|
||||
};
|
||||
|
||||
let projection_matrix = calculate_projection(projection.near, view.fov);
|
||||
let projection_matrix = calculate_projection(
|
||||
projection.near,
|
||||
Fov {
|
||||
angle_left: view.fov.angle_left,
|
||||
angle_right: view.fov.angle_right,
|
||||
angle_down: view.fov.angle_down,
|
||||
angle_up: view.fov.angle_up,
|
||||
},
|
||||
);
|
||||
projection.projection_matrix = projection_matrix;
|
||||
|
||||
let openxr::Quaternionf { x, y, z, w } = view.pose.orientation;
|
||||
@@ -284,102 +292,6 @@ pub fn update_views_render_world(
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_projection(near_z: f32, fov: openxr::Fovf) -> 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 is_vulkan_api = false; // FIXME wgpu probably abstracts this
|
||||
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)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// Images inserted into texture views here should not be written to until [`wait_image`] is ran
|
||||
pub fn insert_texture_views(
|
||||
|
||||
Reference in New Issue
Block a user