diff --git a/src/xrt/auxiliary/math/CMakeLists.txt b/src/xrt/auxiliary/math/CMakeLists.txt index b536b5972..e1f34b9b1 100644 --- a/src/xrt/auxiliary/math/CMakeLists.txt +++ b/src/xrt/auxiliary/math/CMakeLists.txt @@ -28,6 +28,7 @@ add_library( m_lowpass_integer.hpp m_matrix_2x2.h m_matrix_4x4_f64.h + m_matrix_projection.cpp m_optics.c m_permutation.c m_permutation.h diff --git a/src/xrt/auxiliary/math/m_api.h b/src/xrt/auxiliary/math/m_api.h index 1f7e55b53..58cc4d304 100644 --- a/src/xrt/auxiliary/math/m_api.h +++ b/src/xrt/auxiliary/math/m_api.h @@ -655,6 +655,19 @@ math_matrix_4x4_inverse_view_projection(const struct xrt_matrix_4x4 *view, const struct xrt_matrix_4x4 *projection, struct xrt_matrix_4x4 *result); +/*! + * Compute a projection matrix with settings for Vulkan, it will also have it's + * far plane at infinite and the NDC depth will be reversed. + * + * @relates xrt_matrix_4x4 + * @ingroup aux_math + */ +void +math_matrix_4x4_projection_vulkan_infinite_reverse(const struct xrt_fov *fov, + float near_plane, + struct xrt_matrix_4x4 *result); + + /* * * Pose functions. diff --git a/src/xrt/auxiliary/math/m_matrix_projection.cpp b/src/xrt/auxiliary/math/m_matrix_projection.cpp new file mode 100644 index 000000000..aef842927 --- /dev/null +++ b/src/xrt/auxiliary/math/m_matrix_projection.cpp @@ -0,0 +1,81 @@ +// Copyright 2019-2023, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Matrix function for creating projection matrices. + * @author Jakob Bornecrantz + * @ingroup aux_math + */ + +#include "m_mathinclude.h" +#include "xrt/xrt_defines.h" + + +/* + * + * Helpers. + * + */ + +template +void +calc_vulkan_projection_infinite_reverse(const xrt_fov &fov, Scalar near_plane, ResultType &result) +{ + const Scalar tan_left = static_cast(tan(fov.angle_left)); + const Scalar tan_right = static_cast(tan(fov.angle_right)); + + const Scalar tan_down = static_cast(tan(fov.angle_down)); + const Scalar tan_up = static_cast(tan(fov.angle_up)); + + // This is here for clarity. + const bool vulkan_projection_space_y = true; + + const Scalar tan_width = tan_right - tan_left; + const Scalar tan_height = vulkan_projection_space_y // Projection space y direction: + ? (tan_down - tan_up) // Vulkan Y down + : (tan_up - tan_down); // OpenGL Y up + + const Scalar a11 = 2 / tan_width; + const Scalar a22 = 2 / tan_height; + + const Scalar a31 = (tan_right + tan_left) / tan_width; + const Scalar a32 = (tan_up + tan_down) / tan_height; + + + /* + * Vulkan's Z clip space is [0 .. 1] (OpenGL [-1 .. 0 .. 1]). + * We are using reverse depth for better floating value. + * - Near is 1 + * - Far is 0 (infinite) + * + * https://vincent-p.github.io/posts/vulkan_perspective_matrix/ + */ + + const Scalar a33 = 0; // vulkan = 0, opengl = -1 + const Scalar a34 = -1; + const Scalar a43 = near_plane; // Reverse depth and half vs opengl, `-2 * near_plane`. + + // clang-format off + result = ResultType({ + a11, 0, 0, 0, + 0, a22, 0, 0, + a31, a32, a33, a34, + 0, 0, a43, 0, + }); + // clang-format on +} + + +/* + * + * 'Exported' functions. + * + */ + +extern "C" void +math_matrix_4x4_projection_vulkan_infinite_reverse(const struct xrt_fov *fov, + float near_plane, + struct xrt_matrix_4x4 *result) +{ + calc_vulkan_projection_infinite_reverse(*fov, near_plane, *result); +}