From 57cb0e24887ce975d5bf739d59ef141f91f32f5e Mon Sep 17 00:00:00 2001 From: mrbelowski Date: Wed, 14 Feb 2024 13:51:09 +0000 Subject: [PATCH 01/17] naive symmetric projection for OpenVR --- src/mods/VR.cpp | 1 + src/mods/VR.hpp | 19 ++++++++++++--- src/mods/vr/OverlayComponent.cpp | 6 +++++ src/mods/vr/runtimes/OpenVR.cpp | 42 +++++++++++++++++++++++++++++--- 4 files changed, 61 insertions(+), 7 deletions(-) diff --git a/src/mods/VR.cpp b/src/mods/VR.cpp index 520cd78d..2d921f1b 100644 --- a/src/mods/VR.cpp +++ b/src/mods/VR.cpp @@ -2524,6 +2524,7 @@ void VR::on_draw_sidebar_entry(std::string_view name) { m_compatibility_skip_pip->draw("Skip PostInitProperties"); m_sceneview_compatibility_mode->draw("SceneView Compatibility Mode"); m_extreme_compat_mode->draw("Extreme Compatibility Mode"); + m_force_symmetric_projection->draw("Force Symmetric Projection (OpenVR only)"); ImGui::TreePop(); } diff --git a/src/mods/VR.hpp b/src/mods/VR.hpp index b93ab2fa..bf2473ba 100644 --- a/src/mods/VR.hpp +++ b/src/mods/VR.hpp @@ -54,6 +54,11 @@ class VR : public Mod { GESTURE_HEAD_RIGHT, }; + enum PROJECTION_OVERRIDE : int32_t { + NONE, + FULLY_SYMMETRIC + }; + static const inline std::string s_action_pose = "/actions/default/in/Pose"; static const inline std::string s_action_grip_pose = "/actions/default/in/GripPose"; static const inline std::string s_action_trigger = "/actions/default/in/Trigger"; @@ -102,6 +107,11 @@ class VR : public Mod { }; } + // texture bounds to tell OpenVR which parts of the submitted texture to render (default - use the whole texture). + // Will be modified to accommodate forced symmetrical eye projection + vr::VRTextureBounds_t m_right_bounds{0.0f, 0.0f, 1.0f, 1.0f}; + vr::VRTextureBounds_t m_left_bounds{0.0f, 0.0f, 1.0f, 1.0f}; + void on_config_load(const utility::Config& cfg, bool set_defaults) override; void on_config_save(utility::Config& cfg) override; @@ -564,6 +574,10 @@ class VR : public Mod { return m_extreme_compat_mode->value(); } + auto get_projection_override() const { + return m_force_symmetric_projection->value() ? VR::PROJECTION_OVERRIDE::FULLY_SYMMETRIC : VR::PROJECTION_OVERRIDE::NONE; + } + private: Vector4f get_position_unsafe(uint32_t index) const; Vector4f get_velocity_unsafe(uint32_t index) const; @@ -646,9 +660,6 @@ class VR : public Mod { std::vector m_controllers{}; std::unordered_set m_controllers_set{}; - vr::VRTextureBounds_t m_right_bounds{ 0.0f, 0.0f, 1.0f, 1.0f }; - vr::VRTextureBounds_t m_left_bounds{ 0.0f, 0.0f, 1.0f, 1.0f }; - glm::vec3 m_overlay_rotation{-1.550f, 0.0f, -1.330f}; glm::vec4 m_overlay_position{0.0f, 0.06f, -0.07f, 1.0f}; @@ -789,6 +800,7 @@ class VR : public Mod { const ModToggle::Ptr m_2d_screen_mode{ ModToggle::create(generate_name("2DScreenMode"), false) }; const ModToggle::Ptr m_roomscale_movement{ ModToggle::create(generate_name("RoomscaleMovement"), false) }; const ModToggle::Ptr m_swap_controllers{ ModToggle::create(generate_name("SwapControllerInputs"), false) }; + const ModToggle::Ptr m_force_symmetric_projection{ ModToggle::create(generate_name("ForceSymmetricProjection"), false ) }; // Snap turn settings and globals void gamepad_snapturn(XINPUT_STATE& state); @@ -918,6 +930,7 @@ class VR : public Mod { *m_2d_screen_mode, *m_roomscale_movement, *m_swap_controllers, + *m_force_symmetric_projection, *m_snapturn, *m_snapturn_joystick_deadzone, *m_snapturn_angle, diff --git a/src/mods/vr/OverlayComponent.cpp b/src/mods/vr/OverlayComponent.cpp index 599e6102..e4e9da80 100644 --- a/src/mods/vr/OverlayComponent.cpp +++ b/src/mods/vr/OverlayComponent.cpp @@ -327,6 +327,8 @@ void OverlayComponent::update_slate_openvr() { const auto is_d3d11 = g_framework->get_renderer_type() == Framework::RendererType::D3D11; + // TODO: do the sizing / scaling calculations below need to take into account non-standard VRTextureBounds_t + // when we force a symmetrical eye projection matrix? vr::VRTextureBounds_t bounds{}; bounds.uMin = 0.0f; bounds.uMax = 1.0f; @@ -424,6 +426,8 @@ bool OverlayComponent::update_wrist_overlay_openvr() { // so it doesn't become too intrusive during gameplay const auto scale = m_closed_ui ? 0.25f : 1.0f; + // TODO: do the sizing / scaling calculations below need to take into account non-standard VRTextureBounds_t + // when we force a symmetrical eye projection matrix? vr::VRTextureBounds_t bounds{}; bounds.uMin = last_window_pos.x / render_target_width ; bounds.uMax = (last_window_pos.x + last_window_size.x) / render_target_width; @@ -667,6 +671,8 @@ void OverlayComponent::update_overlay_openvr() { vr::VROverlay()->ShowOverlay(m_overlay_handle); // Show the entire texture + // TODO: do the sizing / scaling calculations below need to take into account non-standard VRTextureBounds_t + // when we force a symmetrical eye projection matrix? vr::VRTextureBounds_t bounds{}; bounds.uMin = 0.0f; bounds.uMax = 1.0f; diff --git a/src/mods/vr/runtimes/OpenVR.cpp b/src/mods/vr/runtimes/OpenVR.cpp index b1b2a8c5..a977d412 100644 --- a/src/mods/vr/runtimes/OpenVR.cpp +++ b/src/mods/vr/runtimes/OpenVR.cpp @@ -178,6 +178,7 @@ VRRuntime::Error OpenVR::consume_events(std::function callback) { return VRRuntime::Error::SUCCESS; } +// TODO: this is called 6 times per tick, which seems a bit generous VRRuntime::Error OpenVR::update_matrices(float nearz, float farz){ std::unique_lock __{ this->eyes_mtx }; const auto local_left = this->hmd->GetEyeToHeadTransform(vr::Eye_Left); @@ -195,11 +196,44 @@ VRRuntime::Error OpenVR::update_matrices(float nearz, float farz){ this->hmd->GetProjectionRaw(vr::Eye_Left, &this->raw_projections[vr::Eye_Left][0], &this->raw_projections[vr::Eye_Left][1], &this->raw_projections[vr::Eye_Left][2], &this->raw_projections[vr::Eye_Left][3]); this->hmd->GetProjectionRaw(vr::Eye_Right, &this->raw_projections[vr::Eye_Right][0], &this->raw_projections[vr::Eye_Right][1], &this->raw_projections[vr::Eye_Right][2], &this->raw_projections[vr::Eye_Right][3]); + // TODO: other flavours of projection - mirrored asymmetric (like the CV1), horizontal symmetry but not vertical, others? + const bool override_projection = VR::get()->get_projection_override() == VR::PROJECTION_OVERRIDE::FULLY_SYMMETRIC; + const auto tan_half_fov = new float[2]; + //SPDLOG_INFO("projection overried {}", override_projection); + if (override_projection) { + tan_half_fov[0] = std::max(std::max(-this->raw_projections[vr::Eye_Left][0], this->raw_projections[vr::Eye_Left][1]), + std::max(-this->raw_projections[vr::Eye_Right][0], this->raw_projections[vr::Eye_Right][1])); + tan_half_fov[1] = std::max(std::max(-this->raw_projections[vr::Eye_Left][2], this->raw_projections[vr::Eye_Left][3]), + std::max(-this->raw_projections[vr::Eye_Right][2], this->raw_projections[vr::Eye_Right][3])); + + VR::get()->m_left_bounds.uMin = 0.5f + 0.5f * this->raw_projections[vr::Eye_Left][0] / tan_half_fov[0]; + VR::get()->m_left_bounds.uMax = 0.5f + 0.5f * this->raw_projections[vr::Eye_Left][1] / tan_half_fov[0]; + VR::get()->m_left_bounds.vMin = 0.5f - 0.5f * this->raw_projections[vr::Eye_Left][3] / tan_half_fov[1]; // bottom then top + VR::get()->m_left_bounds.vMax = 0.5f - 0.5f * this->raw_projections[vr::Eye_Left][2] / tan_half_fov[1]; + + VR::get()->m_right_bounds.uMin = 0.5f + 0.5f * this->raw_projections[vr::Eye_Right][0] / tan_half_fov[0]; + VR::get()->m_right_bounds.uMax = 0.5f + 0.5f * this->raw_projections[vr::Eye_Right][1] / tan_half_fov[0]; + VR::get()->m_right_bounds.vMin = 0.5f - 0.5f * this->raw_projections[vr::Eye_Right][3] / tan_half_fov[1]; // bottom then top + VR::get()->m_right_bounds.vMax = 0.5f - 0.5f * this->raw_projections[vr::Eye_Right][2] / tan_half_fov[1]; + } else { + VR::get()->m_left_bounds.uMin = 0; + VR::get()->m_left_bounds.uMax = 1; + VR::get()->m_left_bounds.vMin = 0; + VR::get()->m_left_bounds.vMax = 1; + VR::get()->m_right_bounds.uMin = 0; + VR::get()->m_right_bounds.uMax = 1; + VR::get()->m_right_bounds.vMin = 0; + VR::get()->m_right_bounds.vMax = 1; + } auto get_mat = [&](vr::EVREye eye) { - const auto left = this->raw_projections[eye][0] * -1.0f; - const auto right = this->raw_projections[eye][1] * -1.0f; - const auto top = this->raw_projections[eye][2] * -1.0f; - const auto bottom = this->raw_projections[eye][3] * -1.0f; + + const auto left = override_projection ? tan_half_fov[0] : this->raw_projections[eye][0] * -1.0f; + const auto right = override_projection ? -tan_half_fov[0] : this->raw_projections[eye][1] * -1.0f; + const auto top = override_projection ? tan_half_fov[1] : this->raw_projections[eye][2] * -1.0f; + const auto bottom = override_projection ? -tan_half_fov[1] : this->raw_projections[eye][3] * -1.0f; + + //SPDLOG_INFO("Original {}, {}, {}, {}", this->raw_projections[eye][0] * -1.0f, this->raw_projections[eye][1] * -1.0f, this->raw_projections[eye][2] * -1.0f, this->raw_projections[eye][3] * -1.0f); + //SPDLOG_INFO("Modified {}, {}, {}, {}", left, right, top, bottom); float sum_rl = (left + right); float sum_tb = (top + bottom); float inv_rl = (1.0f / (left - right)); From 5f337cf3a0523543d0f505693977a629f99b961d Mon Sep 17 00:00:00 2001 From: mrbelowski Date: Wed, 14 Feb 2024 16:53:22 +0000 Subject: [PATCH 02/17] WIP OpenXR symmetric projection --- src/CommitHash.hpp | 6 +-- src/mods/vr/runtimes/OpenXR.cpp | 83 ++++++++++++++++++++++++++++----- src/mods/vr/runtimes/OpenXR.hpp | 4 ++ 3 files changed, 79 insertions(+), 14 deletions(-) diff --git a/src/CommitHash.hpp b/src/CommitHash.hpp index f72e2199..9cdb2510 100644 --- a/src/CommitHash.hpp +++ b/src/CommitHash.hpp @@ -1,4 +1,4 @@ #pragma once -#define UEVR_COMMIT_HASH "3997108934a41fdbb1c6a6e8ff59d7fcd63362ac" -#define UEVR_BUILD_DATE "13.02.2024" -#define UEVR_BUILD_TIME "00:00" +#define UEVR_COMMIT_HASH "88cf65928beb08094c63779a160586d9ce89857e" +#define UEVR_BUILD_DATE "14.02.2024" +#define UEVR_BUILD_TIME "16:52" diff --git a/src/mods/vr/runtimes/OpenXR.cpp b/src/mods/vr/runtimes/OpenXR.cpp index 6afb8e61..50e97f14 100644 --- a/src/mods/vr/runtimes/OpenXR.cpp +++ b/src/mods/vr/runtimes/OpenXR.cpp @@ -471,7 +471,44 @@ VRRuntime::Error OpenXR::update_matrices(float nearz, float farz) { std::unique_lock __{ this->eyes_mtx }; std::unique_lock ___{ this->pose_mtx }; + // TODO: other flavours of projection - mirrored asymmetric (like the CV1), horizontal symmetry but not vertical, others? + const bool override_projection = VR::get()->get_projection_override() == VR::PROJECTION_OVERRIDE::FULLY_SYMMETRIC; + const auto left_top = tan(this->views[0].fov.angleUp); + const auto left_bottom = tan(this->views[0].fov.angleDown); + const auto left_left = tan(this->views[0].fov.angleLeft); + const auto left_right = tan(this->views[0].fov.angleRight); + const auto right_top = tan(this->views[1].fov.angleUp); + const auto right_bottom = tan(this->views[1].fov.angleDown); + const auto right_left = tan(this->views[1].fov.angleLeft); + const auto right_right = tan(this->views[1].fov.angleRight); + // SPDLOG_INFO("projection overried {}", override_projection); + if (override_projection) { + const auto tan_half_fov = new float[2]; + tan_half_fov[0] = std::max(std::max(-left_left, left_right), + std::max(-right_left, right_right)); + tan_half_fov[1] = std::max(std::max(-left_top, left_bottom), + std::max(-right_top, right_bottom)); + + m_left_view_bounds[0] = 0.5f + 0.5f * left_left / tan_half_fov[0]; + m_left_view_bounds[1] = 0.5f + 0.5f * left_right / tan_half_fov[0]; + m_left_view_bounds[2] = 0.5f - 0.5f * left_bottom / tan_half_fov[1]; // bottom then top + m_left_view_bounds[3] = 0.5f - 0.5f * left_top / tan_half_fov[1]; + + m_right_view_bounds[0] = 0.5f + 0.5f * right_left / tan_half_fov[0]; + m_right_view_bounds[1] = 0.5f + 0.5f * right_right / tan_half_fov[0]; + m_right_view_bounds[2] = 0.5f - 0.5f * right_bottom / tan_half_fov[1]; // bottom then top + m_right_view_bounds[3] = 0.5f - 0.5f * right_top / tan_half_fov[1]; + } else { + m_left_view_bounds[0] = 0; + m_left_view_bounds[0] = 1; + m_left_view_bounds[0] = 0; + m_left_view_bounds[0] = 1; + m_right_view_bounds[0] = 0; + m_right_view_bounds[0] = 1; + m_right_view_bounds[0] = 0; + m_right_view_bounds[0] = 1; + } for (auto i = 0; i < 2; ++i) { const auto& pose = this->views[i].pose; const auto& fov = this->views[i].fov; @@ -480,10 +517,10 @@ VRRuntime::Error OpenXR::update_matrices(float nearz, float farz) { //XrMatrix4x4f_CreateProjection((XrMatrix4x4f*)&this->projections[i], GRAPHICS_D3D, tan(fov.angleLeft), tan(fov.angleRight), tan(fov.angleUp), tan(fov.angleDown), nearz, farz); auto get_mat = [&](int eye) { - const auto top = tan(fov.angleUp); - const auto bottom = tan(fov.angleDown); - const auto left = tan(fov.angleLeft); - const auto right = tan(fov.angleRight); + const auto top = eye == 0 ? left_top : right_top; + const auto bottom = eye == 0 ? left_bottom : right_bottom; + const auto left = eye == 0 ? left_left : right_left; + const auto right = eye == 0 ? left_right : right_right; float sum_rl = (right + left); float sum_tb = (top + bottom); @@ -1714,7 +1751,7 @@ XrResult OpenXR::end_frame(const std::vector& qua projection_layer_views.resize(pipelined_stage_views.size(), {XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW}); depth_layers.resize(projection_layer_views.size(), {XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR}); - for (auto i = 0; i < projection_layer_views.size(); ++i) { + for (auto i = 0; i < projection_layer_views.size(); ++i) { Swapchain* swapchain = nullptr; if (is_afr) { @@ -1732,13 +1769,36 @@ XrResult OpenXR::end_frame(const std::vector& qua projection_layer_views[i].fov = pipelined_stage_views[i].fov; projection_layer_views[i].subImage.swapchain = swapchain->handle; - if (is_afr) { + int offset_x = 0, offset_y = 0, extent_x = 0, extent_y = 0; + // if we're working with a double-wide texture, use half the view bounds adjustment (as they apply to a single eye) + float width_factor = is_afr ? 1 : 0.5; + if (i == 0) { + // left eye + offset_x = m_left_view_bounds[0] * swapchain->width * width_factor; + extent_x = m_left_view_bounds[1] * swapchain->width * width_factor; + offset_y = m_left_view_bounds[2] * swapchain->height; + extent_y = m_left_view_bounds[3] * swapchain->height; + } else { + // right eye + offset_x = m_right_view_bounds[0] * swapchain->width * width_factor; + extent_x = m_right_view_bounds[1] * swapchain->width * width_factor; + offset_y = m_right_view_bounds[2] * swapchain->height; + extent_y = m_right_view_bounds[3] * swapchain->height; + if (!is_afr) { + // for double wide move to the right half of the texture: + offset_x += swapchain->width; + } + } + projection_layer_views[i].subImage.imageRect.offset = {offset_x, offset_y}; + projection_layer_views[i].subImage.imageRect.extent = {extent_x, extent_y}; + + /* if (is_afr) { projection_layer_views[i].subImage.imageRect.offset = {0, 0}; projection_layer_views[i].subImage.imageRect.extent = {swapchain->width, swapchain->height}; } else { projection_layer_views[i].subImage.imageRect.offset = {(swapchain->width / 2) * i, 0}; projection_layer_views[i].subImage.imageRect.extent = {swapchain->width / 2, swapchain->height}; - } + }*/ if (has_depth) { Swapchain* depth_swapchain = nullptr; @@ -1756,11 +1816,11 @@ XrResult OpenXR::end_frame(const std::vector& qua depth_layers[i].type = XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR; depth_layers[i].next = nullptr; depth_layers[i].subImage.swapchain = depth_swapchain->handle; - + /* const auto is_afr = VR::get()->is_using_afr(); bool doublewide_depth = true; - if (is_afr /*&& depth_swapchain->width == get_width() && depth_swapchain->height == get_height()*/) { + if (is_afr) { doublewide_depth = false; } @@ -1779,8 +1839,9 @@ XrResult OpenXR::end_frame(const std::vector& qua } else { depth_layers[i].subImage.imageRect.offset = {depth_extent.width * i, 0}; depth_layers[i].subImage.imageRect.extent = depth_extent; - } - + }*/ + depth_layers[i].subImage.imageRect.offset = {offset_x, offset_y}; + depth_layers[i].subImage.imageRect.extent = {std::min(get_width(), extent_x), std::min(get_height(), extent_y)}; depth_layers[i].minDepth = 0.0f; depth_layers[i].maxDepth = 1.0f; auto wtm = VR::get()->get_world_to_meters(); diff --git a/src/mods/vr/runtimes/OpenXR.hpp b/src/mods/vr/runtimes/OpenXR.hpp index 2ad3d60e..62265661 100644 --- a/src/mods/vr/runtimes/OpenXR.hpp +++ b/src/mods/vr/runtimes/OpenXR.hpp @@ -485,5 +485,9 @@ struct OpenXR final : public VRRuntime { "/interaction_profiles/microsoft/motion_controller", "/interaction_profiles/htc/vive_controller", }; + +private: + float m_left_view_bounds[4] = {0, 1, 0, 1}; + float m_right_view_bounds[4] = {0, 1, 0, 1}; }; } \ No newline at end of file From d75110e6ce3409b0614a0b2ef2467b7f30e67a56 Mon Sep 17 00:00:00 2001 From: mrbelowski Date: Wed, 14 Feb 2024 21:56:17 +0000 Subject: [PATCH 03/17] first cut of OpenXR symmetric projection matrices - desparately needs tidying up but appears to work correctly --- src/mods/vr/runtimes/OpenXR.cpp | 113 ++++++++++++++------------------ 1 file changed, 50 insertions(+), 63 deletions(-) diff --git a/src/mods/vr/runtimes/OpenXR.cpp b/src/mods/vr/runtimes/OpenXR.cpp index 50e97f14..0bdfbc5b 100644 --- a/src/mods/vr/runtimes/OpenXR.cpp +++ b/src/mods/vr/runtimes/OpenXR.cpp @@ -473,41 +473,51 @@ VRRuntime::Error OpenXR::update_matrices(float nearz, float farz) { std::unique_lock ___{ this->pose_mtx }; // TODO: other flavours of projection - mirrored asymmetric (like the CV1), horizontal symmetry but not vertical, others? const bool override_projection = VR::get()->get_projection_override() == VR::PROJECTION_OVERRIDE::FULLY_SYMMETRIC; - const auto left_top = tan(this->views[0].fov.angleUp); - const auto left_bottom = tan(this->views[0].fov.angleDown); - const auto left_left = tan(this->views[0].fov.angleLeft); - const auto left_right = tan(this->views[0].fov.angleRight); - const auto right_top = tan(this->views[1].fov.angleUp); - const auto right_bottom = tan(this->views[1].fov.angleDown); - const auto right_left = tan(this->views[1].fov.angleLeft); - const auto right_right = tan(this->views[1].fov.angleRight); + auto left_top = tan(this->views[0].fov.angleUp); + auto left_bottom = tan(this->views[0].fov.angleDown); + auto left_left = tan(this->views[0].fov.angleLeft); + auto left_right = tan(this->views[0].fov.angleRight); + auto right_top = tan(this->views[1].fov.angleUp); + auto right_bottom = tan(this->views[1].fov.angleDown); + auto right_left = tan(this->views[1].fov.angleLeft); + auto right_right = tan(this->views[1].fov.angleRight); // SPDLOG_INFO("projection overried {}", override_projection); if (override_projection) { const auto tan_half_fov = new float[2]; tan_half_fov[0] = std::max(std::max(-left_left, left_right), std::max(-right_left, right_right)); - tan_half_fov[1] = std::max(std::max(-left_top, left_bottom), - std::max(-right_top, right_bottom)); + tan_half_fov[1] = std::max(std::max(left_top, -left_bottom), + std::max(right_top, -right_bottom)); m_left_view_bounds[0] = 0.5f + 0.5f * left_left / tan_half_fov[0]; m_left_view_bounds[1] = 0.5f + 0.5f * left_right / tan_half_fov[0]; - m_left_view_bounds[2] = 0.5f - 0.5f * left_bottom / tan_half_fov[1]; // bottom then top - m_left_view_bounds[3] = 0.5f - 0.5f * left_top / tan_half_fov[1]; + m_left_view_bounds[2] = 0.5f - 0.5f * left_top / tan_half_fov[1]; + m_left_view_bounds[3] = 0.5f - 0.5f * left_bottom / tan_half_fov[1]; m_right_view_bounds[0] = 0.5f + 0.5f * right_left / tan_half_fov[0]; m_right_view_bounds[1] = 0.5f + 0.5f * right_right / tan_half_fov[0]; - m_right_view_bounds[2] = 0.5f - 0.5f * right_bottom / tan_half_fov[1]; // bottom then top - m_right_view_bounds[3] = 0.5f - 0.5f * right_top / tan_half_fov[1]; + m_right_view_bounds[2] = 0.5f - 0.5f * right_top / tan_half_fov[1]; + m_right_view_bounds[3] = 0.5f - 0.5f * right_bottom / tan_half_fov[1]; + + left_left = -tan_half_fov[0]; + left_right = tan_half_fov[0]; + right_left = -tan_half_fov[0]; + right_right = tan_half_fov[0]; + left_top = tan_half_fov[1]; + left_bottom = -tan_half_fov[1]; + right_top = tan_half_fov[1]; + right_bottom = -tan_half_fov[1]; + } else { m_left_view_bounds[0] = 0; - m_left_view_bounds[0] = 1; - m_left_view_bounds[0] = 0; - m_left_view_bounds[0] = 1; + m_left_view_bounds[1] = 1; + m_left_view_bounds[2] = 0; + m_left_view_bounds[3] = 1; m_right_view_bounds[0] = 0; - m_right_view_bounds[0] = 1; - m_right_view_bounds[0] = 0; - m_right_view_bounds[0] = 1; + m_right_view_bounds[1] = 1; + m_right_view_bounds[2] = 0; + m_right_view_bounds[3] = 1; } for (auto i = 0; i < 2; ++i) { const auto& pose = this->views[i].pose; @@ -521,7 +531,11 @@ VRRuntime::Error OpenXR::update_matrices(float nearz, float farz) { const auto bottom = eye == 0 ? left_bottom : right_bottom; const auto left = eye == 0 ? left_left : right_left; const auto right = eye == 0 ? left_right : right_right; - + //SPDLOG_INFO("Original {}, {}, {}, {}", tan(this->views[eye].fov.angleLeft), tan(this->views[eye].fov.angleRight), + // tan(this->views[eye].fov.angleUp), tan(this->views[eye].fov.angleDown)); + //SPDLOG_INFO("Modified {}, {}, {}, {}", left, right, top, bottom); + // this->raw_projections[eye][2] * -1.0f, this->raw_projections[eye][3] * -1.0f); + // SPDLOG_INFO("Modified {}, {}, {}, {}", left, right, top, bottom); float sum_rl = (right + left); float sum_tb = (top + bottom); float inv_rl = (1.0f / (right - left)); @@ -1769,37 +1783,33 @@ XrResult OpenXR::end_frame(const std::vector& qua projection_layer_views[i].fov = pipelined_stage_views[i].fov; projection_layer_views[i].subImage.swapchain = swapchain->handle; - int offset_x = 0, offset_y = 0, extent_x = 0, extent_y = 0; + int32_t offset_x = 0, offset_y = 0, extent_x = 0, extent_y = 0; // if we're working with a double-wide texture, use half the view bounds adjustment (as they apply to a single eye) float width_factor = is_afr ? 1 : 0.5; if (i == 0) { // left eye offset_x = m_left_view_bounds[0] * swapchain->width * width_factor; - extent_x = m_left_view_bounds[1] * swapchain->width * width_factor; + extent_x = m_left_view_bounds[1] * swapchain->width * width_factor - offset_x; offset_y = m_left_view_bounds[2] * swapchain->height; - extent_y = m_left_view_bounds[3] * swapchain->height; + extent_y = m_left_view_bounds[3] * swapchain->height - offset_y; + //SPDLOG_INFO("Left image, width {} height {}, bounds {}, {}, {}, {}", swapchain->width, swapchain->height, + // m_left_view_bounds[0], m_left_view_bounds[1], m_left_view_bounds[2], m_left_view_bounds[3]); + } else { - // right eye - offset_x = m_right_view_bounds[0] * swapchain->width * width_factor; - extent_x = m_right_view_bounds[1] * swapchain->width * width_factor; + // right eye, for double wide move to the right half of the texture: + int32_t left_start = is_afr ? 0 : swapchain->width / 2; + offset_x = left_start + m_right_view_bounds[0] * swapchain->width * width_factor; + extent_x = m_right_view_bounds[1] * swapchain->width * width_factor - m_right_view_bounds[0] * swapchain->width * width_factor; offset_y = m_right_view_bounds[2] * swapchain->height; - extent_y = m_right_view_bounds[3] * swapchain->height; - if (!is_afr) { - // for double wide move to the right half of the texture: - offset_x += swapchain->width; - } + extent_y = m_right_view_bounds[3] * swapchain->height - offset_y; + //SPDLOG_INFO("Right image, width {} height {}, bounds {}, {}, {}, {}", swapchain->width, swapchain->height, + // m_right_view_bounds[0], m_right_view_bounds[1], m_right_view_bounds[2], m_right_view_bounds[3]); } + + //SPDLOG_INFO("image calc {}, {}, {}, {}", offset_x, extent_x, offset_y, extent_y); projection_layer_views[i].subImage.imageRect.offset = {offset_x, offset_y}; projection_layer_views[i].subImage.imageRect.extent = {extent_x, extent_y}; - /* if (is_afr) { - projection_layer_views[i].subImage.imageRect.offset = {0, 0}; - projection_layer_views[i].subImage.imageRect.extent = {swapchain->width, swapchain->height}; - } else { - projection_layer_views[i].subImage.imageRect.offset = {(swapchain->width / 2) * i, 0}; - projection_layer_views[i].subImage.imageRect.extent = {swapchain->width / 2, swapchain->height}; - }*/ - if (has_depth) { Swapchain* depth_swapchain = nullptr; @@ -1816,30 +1826,7 @@ XrResult OpenXR::end_frame(const std::vector& qua depth_layers[i].type = XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR; depth_layers[i].next = nullptr; depth_layers[i].subImage.swapchain = depth_swapchain->handle; - /* - const auto is_afr = VR::get()->is_using_afr(); - bool doublewide_depth = true; - if (is_afr) { - doublewide_depth = false; - } - - XrExtent2Di depth_extent = {depth_swapchain->width, depth_swapchain->height}; - - if (doublewide_depth) { - depth_extent.width /= 2; - } - - depth_extent = {std::min(get_width(), depth_extent.width), std::min(get_height(), depth_extent.height)}; - - if (is_afr) { - // Always the left half of the depth texture. - depth_layers[i].subImage.imageRect.offset = {0, 0}; - depth_layers[i].subImage.imageRect.extent = depth_extent; - } else { - depth_layers[i].subImage.imageRect.offset = {depth_extent.width * i, 0}; - depth_layers[i].subImage.imageRect.extent = depth_extent; - }*/ depth_layers[i].subImage.imageRect.offset = {offset_x, offset_y}; depth_layers[i].subImage.imageRect.extent = {std::min(get_width(), extent_x), std::min(get_height(), extent_y)}; depth_layers[i].minDepth = 0.0f; From d79e5e7416531a9a9c582dc48db0d6c8768bf73c Mon Sep 17 00:00:00 2001 From: mrbelowski Date: Wed, 14 Feb 2024 22:24:34 +0000 Subject: [PATCH 04/17] tweak a calculation the looked upside down (but is hard to tell with Index's almost vertically symmetric projection) --- src/mods/vr/runtimes/OpenVR.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mods/vr/runtimes/OpenVR.cpp b/src/mods/vr/runtimes/OpenVR.cpp index a977d412..26f8c9a9 100644 --- a/src/mods/vr/runtimes/OpenVR.cpp +++ b/src/mods/vr/runtimes/OpenVR.cpp @@ -208,13 +208,13 @@ VRRuntime::Error OpenVR::update_matrices(float nearz, float farz){ VR::get()->m_left_bounds.uMin = 0.5f + 0.5f * this->raw_projections[vr::Eye_Left][0] / tan_half_fov[0]; VR::get()->m_left_bounds.uMax = 0.5f + 0.5f * this->raw_projections[vr::Eye_Left][1] / tan_half_fov[0]; - VR::get()->m_left_bounds.vMin = 0.5f - 0.5f * this->raw_projections[vr::Eye_Left][3] / tan_half_fov[1]; // bottom then top - VR::get()->m_left_bounds.vMax = 0.5f - 0.5f * this->raw_projections[vr::Eye_Left][2] / tan_half_fov[1]; + VR::get()->m_left_bounds.vMin = 0.5f + 0.5f * this->raw_projections[vr::Eye_Left][2] / tan_half_fov[1]; + VR::get()->m_left_bounds.vMax = 0.5f + 0.5f * this->raw_projections[vr::Eye_Left][3] / tan_half_fov[1]; VR::get()->m_right_bounds.uMin = 0.5f + 0.5f * this->raw_projections[vr::Eye_Right][0] / tan_half_fov[0]; VR::get()->m_right_bounds.uMax = 0.5f + 0.5f * this->raw_projections[vr::Eye_Right][1] / tan_half_fov[0]; - VR::get()->m_right_bounds.vMin = 0.5f - 0.5f * this->raw_projections[vr::Eye_Right][3] / tan_half_fov[1]; // bottom then top - VR::get()->m_right_bounds.vMax = 0.5f - 0.5f * this->raw_projections[vr::Eye_Right][2] / tan_half_fov[1]; + VR::get()->m_right_bounds.vMin = 0.5f + 0.5f * this->raw_projections[vr::Eye_Right][2] / tan_half_fov[1]; + VR::get()->m_right_bounds.vMax = 0.5f + 0.5f * this->raw_projections[vr::Eye_Right][3] / tan_half_fov[1]; } else { VR::get()->m_left_bounds.uMin = 0; VR::get()->m_left_bounds.uMax = 1; From 5738af3f164b6d72c22195a2871cc5a6bf5378aa Mon Sep 17 00:00:00 2001 From: mrbelowski Date: Thu, 15 Feb 2024 08:34:23 +0000 Subject: [PATCH 05/17] WIP --- src/CommitHash.hpp | 6 +-- src/mods/VR.cpp | 4 +- src/mods/VR.hpp | 45 ++++++++++++++++++---- src/mods/vr/D3D11Component.cpp | 15 +++++--- src/mods/vr/D3D12Component.cpp | 15 +++++--- src/mods/vr/runtimes/OpenVR.cpp | 62 ++++++++++++++---------------- src/mods/vr/runtimes/OpenXR.cpp | 11 +----- src/mods/vr/runtimes/OpenXR.hpp | 3 -- src/mods/vr/runtimes/VRRuntime.hpp | 3 ++ 9 files changed, 96 insertions(+), 68 deletions(-) diff --git a/src/CommitHash.hpp b/src/CommitHash.hpp index 9cdb2510..79786c97 100644 --- a/src/CommitHash.hpp +++ b/src/CommitHash.hpp @@ -1,4 +1,4 @@ #pragma once -#define UEVR_COMMIT_HASH "88cf65928beb08094c63779a160586d9ce89857e" -#define UEVR_BUILD_DATE "14.02.2024" -#define UEVR_BUILD_TIME "16:52" +#define UEVR_COMMIT_HASH "fe562d052cfacddde933c5314b7a46fcd47615c4" +#define UEVR_BUILD_DATE "15.02.2024" +#define UEVR_BUILD_TIME "07:58" diff --git a/src/mods/VR.cpp b/src/mods/VR.cpp index 2d921f1b..e4e619ce 100644 --- a/src/mods/VR.cpp +++ b/src/mods/VR.cpp @@ -2524,7 +2524,9 @@ void VR::on_draw_sidebar_entry(std::string_view name) { m_compatibility_skip_pip->draw("Skip PostInitProperties"); m_sceneview_compatibility_mode->draw("SceneView Compatibility Mode"); m_extreme_compat_mode->draw("Extreme Compatibility Mode"); - m_force_symmetric_projection->draw("Force Symmetric Projection (OpenVR only)"); + + m_horizontal_projection_override->draw("Horiztonal Projection"); + m_vertical_projection_override->draw("Vertical Projection"); ImGui::TreePop(); } diff --git a/src/mods/VR.hpp b/src/mods/VR.hpp index bf2473ba..077b38fd 100644 --- a/src/mods/VR.hpp +++ b/src/mods/VR.hpp @@ -54,9 +54,21 @@ class VR : public Mod { GESTURE_HEAD_RIGHT, }; - enum PROJECTION_OVERRIDE : int32_t { + enum L3_R3_LONG_PRESS_MODE : int32_t { + TOGGLE_AIM_MODE, + TOGGLE_DISABLE_UOBJECT_HOOK + }; + + enum HORIZONTAL_PROJECTION_OVERRIDE : int32_t { + NONE, + SYMMETRIC, + MIRROR + }; + + enum VERTICAL_PROJECTION_OVERRIDE : int32_t { NONE, - FULLY_SYMMETRIC + SYMMETRIC, + MATCHED }; static const inline std::string s_action_pose = "/actions/default/in/Pose"; @@ -574,8 +586,12 @@ class VR : public Mod { return m_extreme_compat_mode->value(); } - auto get_projection_override() const { - return m_force_symmetric_projection->value() ? VR::PROJECTION_OVERRIDE::FULLY_SYMMETRIC : VR::PROJECTION_OVERRIDE::NONE; + auto get_horiztonal_projection_override() const { + return m_horizontal_projection_override->value(); + } + + auto get_vertical_projection_override() const { + return m_vertical_projection_override->value(); } private: @@ -783,6 +799,19 @@ class VR : public Mod { "Gesture (Head) + Right Joystick", }; + static const inline std::vector s_horizontal_projection_override_names{ + "Raw / default", + "Symmetrical", + "Mirrored", + }; + + static const inline std::vector s_vertical_projection_override_names{ + "Raw / default", + "Symmetrical", + "Matched", + }; + + const ModCombo::Ptr m_log_level{ ModCombo::create(generate_name("LogLevel"), s_log_level_names, SPDLOG_LEVEL_INFO) }; const ModCombo::Ptr m_rendering_method{ ModCombo::create(generate_name("RenderingMethod"), s_rendering_method_names) }; const ModCombo::Ptr m_synced_afr_method{ ModCombo::create(generate_name("SyncedSequentialMethod"), s_synced_afr_method_names, 1) }; const ModToggle::Ptr m_extreme_compat_mode{ ModToggle::create(generate_name("ExtremeCompatibilityMode"), false, true) }; @@ -800,7 +829,8 @@ class VR : public Mod { const ModToggle::Ptr m_2d_screen_mode{ ModToggle::create(generate_name("2DScreenMode"), false) }; const ModToggle::Ptr m_roomscale_movement{ ModToggle::create(generate_name("RoomscaleMovement"), false) }; const ModToggle::Ptr m_swap_controllers{ ModToggle::create(generate_name("SwapControllerInputs"), false) }; - const ModToggle::Ptr m_force_symmetric_projection{ ModToggle::create(generate_name("ForceSymmetricProjection"), false ) }; + const ModCombo::Ptr m_horizontal_projection_override{ModCombo::create(generate_name("HorizontalProjectionOverride"), s_horizontal_projection_override_names)}; + const ModCombo::Ptr m_vertical_projection_override{ModCombo::create(generate_name("VerticalProjectionOverride"), s_vertical_projection_override_names)}; // Snap turn settings and globals void gamepad_snapturn(XINPUT_STATE& state); @@ -930,7 +960,8 @@ class VR : public Mod { *m_2d_screen_mode, *m_roomscale_movement, *m_swap_controllers, - *m_force_symmetric_projection, + *m_horizontal_projection_override, + *m_vertical_projection_override, *m_snapturn, *m_snapturn_joystick_deadzone, *m_snapturn_angle, @@ -1107,4 +1138,4 @@ class VR : public Mod { friend class vrmod::D3D12Component; friend class vrmod::OverlayComponent; friend class FFakeStereoRenderingHook; -}; \ No newline at end of file +}; diff --git a/src/mods/vr/D3D11Component.cpp b/src/mods/vr/D3D11Component.cpp index c8ddefae..b56f5035 100644 --- a/src/mods/vr/D3D11Component.cpp +++ b/src/mods/vr/D3D11Component.cpp @@ -559,8 +559,9 @@ vr::EVRCompositorError D3D11Component::on_frame(VR* vr) { (void*)m_left_eye_tex.Get(), vr::TextureType_DirectX, vr::ColorSpace_Auto, submit_pose }; - - const auto e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &vr->m_left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); + auto const left_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[0][0], runtime->m_view_bounds[0][2], + runtime->m_view_bounds[0][1], runtime->m_view_bounds[0][3]}; + const auto e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); if (e != vr::VRCompositorError_None) { spdlog::error("[VR] VRCompositor failed to submit left eye: {}", (int)e); @@ -710,8 +711,9 @@ vr::EVRCompositorError D3D11Component::on_frame(VR* vr) { (void*)m_left_eye_tex.Get(), vr::TextureType_DirectX, vr::ColorSpace_Auto, submit_pose }; - - e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &vr->m_left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); + auto const left_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[0][0], runtime->m_view_bounds[0][2], + runtime->m_view_bounds[0][1], runtime->m_view_bounds[0][3]}; + e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); if (e != vr::VRCompositorError_None) { spdlog::error("[VR] VRCompositor failed to submit left eye: {}", (int)e); @@ -760,8 +762,9 @@ vr::EVRCompositorError D3D11Component::on_frame(VR* vr) { (void*)m_right_eye_tex.Get(), vr::TextureType_DirectX, vr::ColorSpace_Auto, submit_pose }; - - e = vr::VRCompositor()->Submit(vr::Eye_Right, &right_eye, &vr->m_right_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); + auto const right_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[1][0], runtime->m_view_bounds[1][2], + runtime->m_view_bounds[1][1], runtime->m_view_bounds[1][3]}; + e = vr::VRCompositor()->Submit(vr::Eye_Right, &right_eye, &right_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); runtime->frame_synced = false; bool submitted = true; diff --git a/src/mods/vr/D3D12Component.cpp b/src/mods/vr/D3D12Component.cpp index e2bacc9d..4806173f 100644 --- a/src/mods/vr/D3D12Component.cpp +++ b/src/mods/vr/D3D12Component.cpp @@ -398,8 +398,9 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) { (void*)&left, vr::TextureType_DirectX12, vr::ColorSpace_Auto, submit_pose }; - - auto e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &vr->m_left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); + auto const left_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[0][0], runtime->m_view_bounds[0][2], + runtime->m_view_bounds[0][1], runtime->m_view_bounds[0][3]}; + auto e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); if (e != vr::VRCompositorError_None) { spdlog::error("[VR] VRCompositor failed to submit left eye: {}", (int)e); @@ -496,8 +497,9 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) { (void*)&left, vr::TextureType_DirectX12, vr::ColorSpace_Auto, submit_pose }; - - auto e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &vr->m_left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); + auto const left_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[0][0], runtime->m_view_bounds[0][2], + runtime->m_view_bounds[0][1], runtime->m_view_bounds[0][3]}; + auto e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); if (e != vr::VRCompositorError_None) { spdlog::error("[VR] VRCompositor failed to submit left eye: {}", (int)e); @@ -521,8 +523,9 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) { (void*)&right, vr::TextureType_DirectX12, vr::ColorSpace_Auto, submit_pose }; - - auto e = vr::VRCompositor()->Submit(vr::Eye_Right, &right_eye, &vr->m_right_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); + auto const right_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[1][0], runtime->m_view_bounds[1][2], + runtime->m_view_bounds[1][1], runtime->m_view_bounds[1][3]}; + auto e = vr::VRCompositor()->Submit(vr::Eye_Right, &right_eye, &right_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); runtime->frame_synced = false; if (e != vr::VRCompositorError_None) { diff --git a/src/mods/vr/runtimes/OpenVR.cpp b/src/mods/vr/runtimes/OpenVR.cpp index 26f8c9a9..cb82427a 100644 --- a/src/mods/vr/runtimes/OpenVR.cpp +++ b/src/mods/vr/runtimes/OpenVR.cpp @@ -196,41 +196,37 @@ VRRuntime::Error OpenVR::update_matrices(float nearz, float farz){ this->hmd->GetProjectionRaw(vr::Eye_Left, &this->raw_projections[vr::Eye_Left][0], &this->raw_projections[vr::Eye_Left][1], &this->raw_projections[vr::Eye_Left][2], &this->raw_projections[vr::Eye_Left][3]); this->hmd->GetProjectionRaw(vr::Eye_Right, &this->raw_projections[vr::Eye_Right][0], &this->raw_projections[vr::Eye_Right][1], &this->raw_projections[vr::Eye_Right][2], &this->raw_projections[vr::Eye_Right][3]); - // TODO: other flavours of projection - mirrored asymmetric (like the CV1), horizontal symmetry but not vertical, others? - const bool override_projection = VR::get()->get_projection_override() == VR::PROJECTION_OVERRIDE::FULLY_SYMMETRIC; - const auto tan_half_fov = new float[2]; - //SPDLOG_INFO("projection overried {}", override_projection); - if (override_projection) { - tan_half_fov[0] = std::max(std::max(-this->raw_projections[vr::Eye_Left][0], this->raw_projections[vr::Eye_Left][1]), - std::max(-this->raw_projections[vr::Eye_Right][0], this->raw_projections[vr::Eye_Right][1])); - tan_half_fov[1] = std::max(std::max(-this->raw_projections[vr::Eye_Left][2], this->raw_projections[vr::Eye_Left][3]), - std::max(-this->raw_projections[vr::Eye_Right][2], this->raw_projections[vr::Eye_Right][3])); - - VR::get()->m_left_bounds.uMin = 0.5f + 0.5f * this->raw_projections[vr::Eye_Left][0] / tan_half_fov[0]; - VR::get()->m_left_bounds.uMax = 0.5f + 0.5f * this->raw_projections[vr::Eye_Left][1] / tan_half_fov[0]; - VR::get()->m_left_bounds.vMin = 0.5f + 0.5f * this->raw_projections[vr::Eye_Left][2] / tan_half_fov[1]; - VR::get()->m_left_bounds.vMax = 0.5f + 0.5f * this->raw_projections[vr::Eye_Left][3] / tan_half_fov[1]; - - VR::get()->m_right_bounds.uMin = 0.5f + 0.5f * this->raw_projections[vr::Eye_Right][0] / tan_half_fov[0]; - VR::get()->m_right_bounds.uMax = 0.5f + 0.5f * this->raw_projections[vr::Eye_Right][1] / tan_half_fov[0]; - VR::get()->m_right_bounds.vMin = 0.5f + 0.5f * this->raw_projections[vr::Eye_Right][2] / tan_half_fov[1]; - VR::get()->m_right_bounds.vMax = 0.5f + 0.5f * this->raw_projections[vr::Eye_Right][3] / tan_half_fov[1]; - } else { - VR::get()->m_left_bounds.uMin = 0; - VR::get()->m_left_bounds.uMax = 1; - VR::get()->m_left_bounds.vMin = 0; - VR::get()->m_left_bounds.vMax = 1; - VR::get()->m_right_bounds.uMin = 0; - VR::get()->m_right_bounds.uMax = 1; - VR::get()->m_right_bounds.vMin = 0; - VR::get()->m_right_bounds.vMax = 1; - } + auto& vr = VR::get(); auto get_mat = [&](vr::EVREye eye) { + const auto tan_half_fov = new float[4]; + + // TODO: mirrored + if (vr->get_horiztonal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::SYMMETRIC) { + tan_half_fov[0] = std::max(std::max(-this->raw_projections[eye][0], this->raw_projections[eye][1]), + std::max(-this->raw_projections[eye][0], this->raw_projections[eye][1])); + tan_half_fov[1] = -tan_half_fov[0]; + } else { + tan_half_fov[0] = -this->raw_projections[eye][0]; + tan_half_fov[1] = -this->raw_projections[eye][1]; + } - const auto left = override_projection ? tan_half_fov[0] : this->raw_projections[eye][0] * -1.0f; - const auto right = override_projection ? -tan_half_fov[0] : this->raw_projections[eye][1] * -1.0f; - const auto top = override_projection ? tan_half_fov[1] : this->raw_projections[eye][2] * -1.0f; - const auto bottom = override_projection ? -tan_half_fov[1] : this->raw_projections[eye][3] * -1.0f; + // TODO: matched + if (vr->get_vertical_projection_override() == VR::VERTICAL_PROJECTION_OVERRIDE::SYMMETRIC) { + tan_half_fov[2] = std::max(std::max(-this->raw_projections[eye][2], this->raw_projections[eye][3]), + std::max(-this->raw_projections[eye][2], this->raw_projections[eye][3])); + tan_half_fov[3] = -tan_half_fov[2]; + } else { + tan_half_fov[2] = -this->raw_projections[eye][2]; + tan_half_fov[3] = -this->raw_projections[eye][3]; + } + m_view_bounds[eye][0] = 0.5f + 0.5f * this->raw_projections[eye][0] / tan_half_fov[0]; + m_view_bounds[eye][1] = 0.5f + 0.5f * this->raw_projections[eye][1] / tan_half_fov[1]; + m_view_bounds[eye][2] = 0.5f + 0.5f * this->raw_projections[eye][2] / tan_half_fov[2]; + m_view_bounds[eye][3] = 0.5f + 0.5f * this->raw_projections[eye][3] / tan_half_fov[3]; + const auto left = tan_half_fov[0]; + const auto right = tan_half_fov[1]; + const auto top = tan_half_fov[2]; + const auto bottom = tan_half_fov[3]; //SPDLOG_INFO("Original {}, {}, {}, {}", this->raw_projections[eye][0] * -1.0f, this->raw_projections[eye][1] * -1.0f, this->raw_projections[eye][2] * -1.0f, this->raw_projections[eye][3] * -1.0f); //SPDLOG_INFO("Modified {}, {}, {}, {}", left, right, top, bottom); diff --git a/src/mods/vr/runtimes/OpenXR.cpp b/src/mods/vr/runtimes/OpenXR.cpp index 0bdfbc5b..18739ac0 100644 --- a/src/mods/vr/runtimes/OpenXR.cpp +++ b/src/mods/vr/runtimes/OpenXR.cpp @@ -509,15 +509,8 @@ VRRuntime::Error OpenXR::update_matrices(float nearz, float farz) { right_bottom = -tan_half_fov[1]; } else { - m_left_view_bounds[0] = 0; - m_left_view_bounds[1] = 1; - m_left_view_bounds[2] = 0; - m_left_view_bounds[3] = 1; - - m_right_view_bounds[0] = 0; - m_right_view_bounds[1] = 1; - m_right_view_bounds[2] = 0; - m_right_view_bounds[3] = 1; + set_default_horizontal_view_bounds(); + set_default_vertical_view_bounds(); } for (auto i = 0; i < 2; ++i) { const auto& pose = this->views[i].pose; diff --git a/src/mods/vr/runtimes/OpenXR.hpp b/src/mods/vr/runtimes/OpenXR.hpp index 62265661..929923a4 100644 --- a/src/mods/vr/runtimes/OpenXR.hpp +++ b/src/mods/vr/runtimes/OpenXR.hpp @@ -486,8 +486,5 @@ struct OpenXR final : public VRRuntime { "/interaction_profiles/htc/vive_controller", }; -private: - float m_left_view_bounds[4] = {0, 1, 0, 1}; - float m_right_view_bounds[4] = {0, 1, 0, 1}; }; } \ No newline at end of file diff --git a/src/mods/vr/runtimes/VRRuntime.hpp b/src/mods/vr/runtimes/VRRuntime.hpp index 0ebddec2..a2a2b074 100644 --- a/src/mods/vr/runtimes/VRRuntime.hpp +++ b/src/mods/vr/runtimes/VRRuntime.hpp @@ -193,4 +193,7 @@ struct VRRuntime { uint32_t internal_frame_count{}; uint32_t internal_render_frame_count{}; bool has_render_frame_count{false}; + + // view bounds proportions - left xmin, xmax, ymin, ymax then right xmin, xmax, ymin, ymax + float m_view_bounds[2][4] = {0, 1, 0, 1, 0, 1, 0, 1}; }; \ No newline at end of file From 8cb868ac71a14de1ffc8aa6ede733a165199bfa9 Mon Sep 17 00:00:00 2001 From: mrbelowski Date: Thu, 15 Feb 2024 09:16:08 +0000 Subject: [PATCH 06/17] more WIP - reworked bounds and FOV calculations to reduce mess; still need to verify OpenXR signs --- src/CommitHash.hpp | 4 +- src/mods/VR.hpp | 18 ++--- src/mods/vr/runtimes/OpenVR.cpp | 14 ++-- src/mods/vr/runtimes/OpenXR.cpp | 114 ++++++++++++++------------------ 4 files changed, 66 insertions(+), 84 deletions(-) diff --git a/src/CommitHash.hpp b/src/CommitHash.hpp index 79786c97..0284b091 100644 --- a/src/CommitHash.hpp +++ b/src/CommitHash.hpp @@ -1,4 +1,4 @@ #pragma once -#define UEVR_COMMIT_HASH "fe562d052cfacddde933c5314b7a46fcd47615c4" +#define UEVR_COMMIT_HASH "5738af3f164b6d72c22195a2871cc5a6bf5378aa" #define UEVR_BUILD_DATE "15.02.2024" -#define UEVR_BUILD_TIME "07:58" +#define UEVR_BUILD_TIME "09:14" diff --git a/src/mods/VR.hpp b/src/mods/VR.hpp index 077b38fd..f5aeb399 100644 --- a/src/mods/VR.hpp +++ b/src/mods/VR.hpp @@ -54,21 +54,16 @@ class VR : public Mod { GESTURE_HEAD_RIGHT, }; - enum L3_R3_LONG_PRESS_MODE : int32_t { - TOGGLE_AIM_MODE, - TOGGLE_DISABLE_UOBJECT_HOOK - }; - enum HORIZONTAL_PROJECTION_OVERRIDE : int32_t { - NONE, - SYMMETRIC, - MIRROR + HORIZONTAL_DEFAULT, + HORIZONTAL_SYMMETRIC, + HORIZONTAL_MIRROR }; enum VERTICAL_PROJECTION_OVERRIDE : int32_t { - NONE, - SYMMETRIC, - MATCHED + VERTICAL_DEFAULT, + VERTICAL_SYMMETRIC, + VERTICAL_MATCHED }; static const inline std::string s_action_pose = "/actions/default/in/Pose"; @@ -811,7 +806,6 @@ class VR : public Mod { "Matched", }; - const ModCombo::Ptr m_log_level{ ModCombo::create(generate_name("LogLevel"), s_log_level_names, SPDLOG_LEVEL_INFO) }; const ModCombo::Ptr m_rendering_method{ ModCombo::create(generate_name("RenderingMethod"), s_rendering_method_names) }; const ModCombo::Ptr m_synced_afr_method{ ModCombo::create(generate_name("SyncedSequentialMethod"), s_synced_afr_method_names, 1) }; const ModToggle::Ptr m_extreme_compat_mode{ ModToggle::create(generate_name("ExtremeCompatibilityMode"), false, true) }; diff --git a/src/mods/vr/runtimes/OpenVR.cpp b/src/mods/vr/runtimes/OpenVR.cpp index cb82427a..8190452d 100644 --- a/src/mods/vr/runtimes/OpenVR.cpp +++ b/src/mods/vr/runtimes/OpenVR.cpp @@ -201,9 +201,10 @@ VRRuntime::Error OpenVR::update_matrices(float nearz, float farz){ const auto tan_half_fov = new float[4]; // TODO: mirrored - if (vr->get_horiztonal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::SYMMETRIC) { - tan_half_fov[0] = std::max(std::max(-this->raw_projections[eye][0], this->raw_projections[eye][1]), - std::max(-this->raw_projections[eye][0], this->raw_projections[eye][1])); + if (vr->get_horiztonal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_SYMMETRIC) { + // TODO: don't need to repeat this calculation for each eye + tan_half_fov[0] = std::max(std::max(-this->raw_projections[0][0], this->raw_projections[0][1]), + std::max(-this->raw_projections[1][0], this->raw_projections[1][1])); tan_half_fov[1] = -tan_half_fov[0]; } else { tan_half_fov[0] = -this->raw_projections[eye][0]; @@ -211,9 +212,10 @@ VRRuntime::Error OpenVR::update_matrices(float nearz, float farz){ } // TODO: matched - if (vr->get_vertical_projection_override() == VR::VERTICAL_PROJECTION_OVERRIDE::SYMMETRIC) { - tan_half_fov[2] = std::max(std::max(-this->raw_projections[eye][2], this->raw_projections[eye][3]), - std::max(-this->raw_projections[eye][2], this->raw_projections[eye][3])); + if (vr->get_vertical_projection_override() == VR::VERTICAL_PROJECTION_OVERRIDE::VERTICAL_SYMMETRIC) { + // TODO: don't need to repeat this calculation for each eye + tan_half_fov[2] = std::max(std::max(-this->raw_projections[0][2], this->raw_projections[0][3]), + std::max(-this->raw_projections[1][2], this->raw_projections[1][3])); tan_half_fov[3] = -tan_half_fov[2]; } else { tan_half_fov[2] = -this->raw_projections[eye][2]; diff --git a/src/mods/vr/runtimes/OpenXR.cpp b/src/mods/vr/runtimes/OpenXR.cpp index 18739ac0..40905699 100644 --- a/src/mods/vr/runtimes/OpenXR.cpp +++ b/src/mods/vr/runtimes/OpenXR.cpp @@ -471,47 +471,18 @@ VRRuntime::Error OpenXR::update_matrices(float nearz, float farz) { std::unique_lock __{ this->eyes_mtx }; std::unique_lock ___{ this->pose_mtx }; - // TODO: other flavours of projection - mirrored asymmetric (like the CV1), horizontal symmetry but not vertical, others? - const bool override_projection = VR::get()->get_projection_override() == VR::PROJECTION_OVERRIDE::FULLY_SYMMETRIC; - auto left_top = tan(this->views[0].fov.angleUp); - auto left_bottom = tan(this->views[0].fov.angleDown); - auto left_left = tan(this->views[0].fov.angleLeft); - auto left_right = tan(this->views[0].fov.angleRight); - auto right_top = tan(this->views[1].fov.angleUp); - auto right_bottom = tan(this->views[1].fov.angleDown); - auto right_left = tan(this->views[1].fov.angleLeft); - auto right_right = tan(this->views[1].fov.angleRight); - // SPDLOG_INFO("projection overried {}", override_projection); - if (override_projection) { - const auto tan_half_fov = new float[2]; - tan_half_fov[0] = std::max(std::max(-left_left, left_right), - std::max(-right_left, right_right)); - tan_half_fov[1] = std::max(std::max(left_top, -left_bottom), - std::max(right_top, -right_bottom)); - - m_left_view_bounds[0] = 0.5f + 0.5f * left_left / tan_half_fov[0]; - m_left_view_bounds[1] = 0.5f + 0.5f * left_right / tan_half_fov[0]; - m_left_view_bounds[2] = 0.5f - 0.5f * left_top / tan_half_fov[1]; - m_left_view_bounds[3] = 0.5f - 0.5f * left_bottom / tan_half_fov[1]; - - m_right_view_bounds[0] = 0.5f + 0.5f * right_left / tan_half_fov[0]; - m_right_view_bounds[1] = 0.5f + 0.5f * right_right / tan_half_fov[0]; - m_right_view_bounds[2] = 0.5f - 0.5f * right_top / tan_half_fov[1]; - m_right_view_bounds[3] = 0.5f - 0.5f * right_bottom / tan_half_fov[1]; - - left_left = -tan_half_fov[0]; - left_right = tan_half_fov[0]; - right_left = -tan_half_fov[0]; - right_right = tan_half_fov[0]; - left_top = tan_half_fov[1]; - left_bottom = -tan_half_fov[1]; - right_top = tan_half_fov[1]; - right_bottom = -tan_half_fov[1]; - } else { - set_default_horizontal_view_bounds(); - set_default_vertical_view_bounds(); - } + auto& vr = VR::get(); + + // TODO: check signs + this->raw_projections[0][0] = tan(this->views[0].fov.angleLeft); + this->raw_projections[0][1] = tan(this->views[0].fov.angleRight); + this->raw_projections[0][2] = tan(this->views[0].fov.angleUp); + this->raw_projections[0][3] = tan(this->views[0].fov.angleDown); + this->raw_projections[1][0] = tan(this->views[1].fov.angleLeft); + this->raw_projections[1][1] = tan(this->views[1].fov.angleRight); + this->raw_projections[1][2] = tan(this->views[1].fov.angleUp); + this->raw_projections[1][3] = tan(this->views[1].fov.angleDown); for (auto i = 0; i < 2; ++i) { const auto& pose = this->views[i].pose; const auto& fov = this->views[i].fov; @@ -519,11 +490,40 @@ VRRuntime::Error OpenXR::update_matrices(float nearz, float farz) { // Update projection matrix //XrMatrix4x4f_CreateProjection((XrMatrix4x4f*)&this->projections[i], GRAPHICS_D3D, tan(fov.angleLeft), tan(fov.angleRight), tan(fov.angleUp), tan(fov.angleDown), nearz, farz); + // NOTE the sign convention for left-right is opposite to how it is in OpenVR. Up/down is the same auto get_mat = [&](int eye) { - const auto top = eye == 0 ? left_top : right_top; - const auto bottom = eye == 0 ? left_bottom : right_bottom; - const auto left = eye == 0 ? left_left : right_left; - const auto right = eye == 0 ? left_right : right_right; + const auto tan_half_fov = new float[4]; + + // TODO: mirrored + if (vr->get_horiztonal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_SYMMETRIC) { + // TODO: don't need to repeat this calculation for each eye + tan_half_fov[0] = std::max(std::max(-this->raw_projections[0][0], this->raw_projections[0][1]), + std::max(-this->raw_projections[1][0], this->raw_projections[1][1])); + tan_half_fov[1] = -tan_half_fov[0]; + } else { + tan_half_fov[0] = -this->raw_projections[eye][0]; + tan_half_fov[1] = -this->raw_projections[eye][1]; + } + + // TODO: matched + if (vr->get_vertical_projection_override() == VR::VERTICAL_PROJECTION_OVERRIDE::VERTICAL_SYMMETRIC) { + // TODO: don't need to repeat this calculation for each eye + tan_half_fov[2] = std::max(std::max(-this->raw_projections[0][2], this->raw_projections[0][3]), + std::max(-this->raw_projections[1][2], this->raw_projections[1][3])); + tan_half_fov[3] = -tan_half_fov[2]; + } else { + tan_half_fov[2] = -this->raw_projections[eye][2]; + tan_half_fov[3] = -this->raw_projections[eye][3]; + } + m_view_bounds[eye][0] = 0.5f + 0.5f * this->raw_projections[eye][0] / tan_half_fov[0]; + m_view_bounds[eye][1] = 0.5f + 0.5f * this->raw_projections[eye][1] / tan_half_fov[1]; + m_view_bounds[eye][2] = 0.5f + 0.5f * this->raw_projections[eye][2] / tan_half_fov[2]; + m_view_bounds[eye][3] = 0.5f + 0.5f * this->raw_projections[eye][3] / tan_half_fov[3]; + const auto left = tan_half_fov[0]; + const auto right = tan_half_fov[1]; + const auto top = tan_half_fov[2]; + const auto bottom = tan_half_fov[3]; + //SPDLOG_INFO("Original {}, {}, {}, {}", tan(this->views[eye].fov.angleLeft), tan(this->views[eye].fov.angleRight), // tan(this->views[eye].fov.angleUp), tan(this->views[eye].fov.angleDown)); //SPDLOG_INFO("Modified {}, {}, {}, {}", left, right, top, bottom); @@ -1779,26 +1779,12 @@ XrResult OpenXR::end_frame(const std::vector& qua int32_t offset_x = 0, offset_y = 0, extent_x = 0, extent_y = 0; // if we're working with a double-wide texture, use half the view bounds adjustment (as they apply to a single eye) float width_factor = is_afr ? 1 : 0.5; - if (i == 0) { - // left eye - offset_x = m_left_view_bounds[0] * swapchain->width * width_factor; - extent_x = m_left_view_bounds[1] * swapchain->width * width_factor - offset_x; - offset_y = m_left_view_bounds[2] * swapchain->height; - extent_y = m_left_view_bounds[3] * swapchain->height - offset_y; - //SPDLOG_INFO("Left image, width {} height {}, bounds {}, {}, {}, {}", swapchain->width, swapchain->height, - // m_left_view_bounds[0], m_left_view_bounds[1], m_left_view_bounds[2], m_left_view_bounds[3]); - - } else { - // right eye, for double wide move to the right half of the texture: - int32_t left_start = is_afr ? 0 : swapchain->width / 2; - offset_x = left_start + m_right_view_bounds[0] * swapchain->width * width_factor; - extent_x = m_right_view_bounds[1] * swapchain->width * width_factor - m_right_view_bounds[0] * swapchain->width * width_factor; - offset_y = m_right_view_bounds[2] * swapchain->height; - extent_y = m_right_view_bounds[3] * swapchain->height - offset_y; - //SPDLOG_INFO("Right image, width {} height {}, bounds {}, {}, {}, {}", swapchain->width, swapchain->height, - // m_right_view_bounds[0], m_right_view_bounds[1], m_right_view_bounds[2], m_right_view_bounds[3]); - } - + int32_t left_start = is_afr || i == 0 ? 0 : swapchain->width / 2; + offset_x = left_start + m_view_bounds[i][0] * swapchain->width * width_factor; + extent_x = m_view_bounds[i][1] * swapchain->width * width_factor - offset_x; + offset_y = m_view_bounds[i][2] * swapchain->height; + extent_y = m_view_bounds[i][3] * swapchain->height - offset_y; + //SPDLOG_INFO("image calc {}, {}, {}, {}", offset_x, extent_x, offset_y, extent_y); projection_layer_views[i].subImage.imageRect.offset = {offset_x, offset_y}; projection_layer_views[i].subImage.imageRect.extent = {extent_x, extent_y}; From 4d77aa5fb50a0404c1fa0cb10c813198dfb8283f Mon Sep 17 00:00:00 2001 From: mrbelowski Date: Thu, 15 Feb 2024 09:21:54 +0000 Subject: [PATCH 07/17] wip --- src/mods/vr/runtimes/OpenVR.cpp | 2 ++ src/mods/vr/runtimes/OpenXR.cpp | 58 +++++++++++++++++---------------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/mods/vr/runtimes/OpenVR.cpp b/src/mods/vr/runtimes/OpenVR.cpp index 8190452d..916f6105 100644 --- a/src/mods/vr/runtimes/OpenVR.cpp +++ b/src/mods/vr/runtimes/OpenVR.cpp @@ -230,6 +230,8 @@ VRRuntime::Error OpenVR::update_matrices(float nearz, float farz){ const auto top = tan_half_fov[2]; const auto bottom = tan_half_fov[3]; + // signs : at this point we expect right and top to be negative + //SPDLOG_INFO("Original {}, {}, {}, {}", this->raw_projections[eye][0] * -1.0f, this->raw_projections[eye][1] * -1.0f, this->raw_projections[eye][2] * -1.0f, this->raw_projections[eye][3] * -1.0f); //SPDLOG_INFO("Modified {}, {}, {}, {}", left, right, top, bottom); float sum_rl = (left + right); diff --git a/src/mods/vr/runtimes/OpenXR.cpp b/src/mods/vr/runtimes/OpenXR.cpp index 40905699..9a596d97 100644 --- a/src/mods/vr/runtimes/OpenXR.cpp +++ b/src/mods/vr/runtimes/OpenXR.cpp @@ -494,35 +494,37 @@ VRRuntime::Error OpenXR::update_matrices(float nearz, float farz) { auto get_mat = [&](int eye) { const auto tan_half_fov = new float[4]; - // TODO: mirrored - if (vr->get_horiztonal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_SYMMETRIC) { - // TODO: don't need to repeat this calculation for each eye - tan_half_fov[0] = std::max(std::max(-this->raw_projections[0][0], this->raw_projections[0][1]), - std::max(-this->raw_projections[1][0], this->raw_projections[1][1])); - tan_half_fov[1] = -tan_half_fov[0]; - } else { - tan_half_fov[0] = -this->raw_projections[eye][0]; - tan_half_fov[1] = -this->raw_projections[eye][1]; - } + // TODO: mirrored + if (vr->get_horiztonal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_SYMMETRIC) { + // TODO: don't need to repeat this calculation for each eye + tan_half_fov[0] = std::max(std::max(-this->raw_projections[0][0], this->raw_projections[0][1]), + std::max(-this->raw_projections[1][0], this->raw_projections[1][1])); + tan_half_fov[1] = -tan_half_fov[0]; + } else { + tan_half_fov[0] = -this->raw_projections[eye][0]; + tan_half_fov[1] = -this->raw_projections[eye][1]; + } - // TODO: matched - if (vr->get_vertical_projection_override() == VR::VERTICAL_PROJECTION_OVERRIDE::VERTICAL_SYMMETRIC) { - // TODO: don't need to repeat this calculation for each eye - tan_half_fov[2] = std::max(std::max(-this->raw_projections[0][2], this->raw_projections[0][3]), - std::max(-this->raw_projections[1][2], this->raw_projections[1][3])); - tan_half_fov[3] = -tan_half_fov[2]; - } else { - tan_half_fov[2] = -this->raw_projections[eye][2]; - tan_half_fov[3] = -this->raw_projections[eye][3]; - } - m_view_bounds[eye][0] = 0.5f + 0.5f * this->raw_projections[eye][0] / tan_half_fov[0]; - m_view_bounds[eye][1] = 0.5f + 0.5f * this->raw_projections[eye][1] / tan_half_fov[1]; - m_view_bounds[eye][2] = 0.5f + 0.5f * this->raw_projections[eye][2] / tan_half_fov[2]; - m_view_bounds[eye][3] = 0.5f + 0.5f * this->raw_projections[eye][3] / tan_half_fov[3]; - const auto left = tan_half_fov[0]; - const auto right = tan_half_fov[1]; - const auto top = tan_half_fov[2]; - const auto bottom = tan_half_fov[3]; + // TODO: matched + if (vr->get_vertical_projection_override() == VR::VERTICAL_PROJECTION_OVERRIDE::VERTICAL_SYMMETRIC) { + // TODO: don't need to repeat this calculation for each eye + tan_half_fov[2] = std::max(std::max(-this->raw_projections[0][2], this->raw_projections[0][3]), + std::max(-this->raw_projections[1][2], this->raw_projections[1][3])); + tan_half_fov[3] = -tan_half_fov[2]; + } else { + tan_half_fov[2] = -this->raw_projections[eye][2]; + tan_half_fov[3] = -this->raw_projections[eye][3]; + } + m_view_bounds[eye][0] = 0.5f + 0.5f * this->raw_projections[eye][0] / tan_half_fov[0]; + m_view_bounds[eye][1] = 0.5f + 0.5f * this->raw_projections[eye][1] / tan_half_fov[1]; + m_view_bounds[eye][2] = 0.5f + 0.5f * this->raw_projections[eye][2] / tan_half_fov[2]; + m_view_bounds[eye][3] = 0.5f + 0.5f * this->raw_projections[eye][3] / tan_half_fov[3]; + const auto left = tan_half_fov[0]; + const auto right = tan_half_fov[1]; + const auto top = tan_half_fov[2]; + const auto bottom = tan_half_fov[3]; + + // signs: at this point we expect left[0] and bottom[3] to be negative //SPDLOG_INFO("Original {}, {}, {}, {}", tan(this->views[eye].fov.angleLeft), tan(this->views[eye].fov.angleRight), // tan(this->views[eye].fov.angleUp), tan(this->views[eye].fov.angleDown)); From 5edfab1a35ebf76825d49306216ebf68fa6bd7e8 Mon Sep 17 00:00:00 2001 From: mrbelowski Date: Thu, 15 Feb 2024 09:22:30 +0000 Subject: [PATCH 08/17] wip --- src/mods/vr/runtimes/OpenVR.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mods/vr/runtimes/OpenVR.cpp b/src/mods/vr/runtimes/OpenVR.cpp index 916f6105..a76575fa 100644 --- a/src/mods/vr/runtimes/OpenVR.cpp +++ b/src/mods/vr/runtimes/OpenVR.cpp @@ -230,7 +230,7 @@ VRRuntime::Error OpenVR::update_matrices(float nearz, float farz){ const auto top = tan_half_fov[2]; const auto bottom = tan_half_fov[3]; - // signs : at this point we expect right and top to be negative + // signs : at this point we expect right [1] and bottom [3] to be negative //SPDLOG_INFO("Original {}, {}, {}, {}", this->raw_projections[eye][0] * -1.0f, this->raw_projections[eye][1] * -1.0f, this->raw_projections[eye][2] * -1.0f, this->raw_projections[eye][3] * -1.0f); //SPDLOG_INFO("Modified {}, {}, {}, {}", left, right, top, bottom); From 9d61170ef253005b3638c541322475063b83f6e1 Mon Sep 17 00:00:00 2001 From: mrbelowski Date: Thu, 15 Feb 2024 17:57:35 +0000 Subject: [PATCH 09/17] corrected various calculations; added mirrored projections --- src/mods/vr/runtimes/OpenVR.cpp | 28 ++++++++++----- src/mods/vr/runtimes/OpenXR.cpp | 62 ++++++++++++++++++++------------- 2 files changed, 56 insertions(+), 34 deletions(-) diff --git a/src/mods/vr/runtimes/OpenVR.cpp b/src/mods/vr/runtimes/OpenVR.cpp index a76575fa..04f4471b 100644 --- a/src/mods/vr/runtimes/OpenVR.cpp +++ b/src/mods/vr/runtimes/OpenVR.cpp @@ -195,45 +195,55 @@ VRRuntime::Error OpenVR::update_matrices(float nearz, float farz){ this->hmd->GetProjectionRaw(vr::Eye_Left, &this->raw_projections[vr::Eye_Left][0], &this->raw_projections[vr::Eye_Left][1], &this->raw_projections[vr::Eye_Left][2], &this->raw_projections[vr::Eye_Left][3]); this->hmd->GetProjectionRaw(vr::Eye_Right, &this->raw_projections[vr::Eye_Right][0], &this->raw_projections[vr::Eye_Right][1], &this->raw_projections[vr::Eye_Right][2], &this->raw_projections[vr::Eye_Right][3]); + // SPDLOG_INFO("Original left {}, {}, {}, {}", this->raw_projections[0][0], this->raw_projections[0][1],this->raw_projections[0][2], this->raw_projections[0][3]); + // SPDLOG_INFO("Original right {}, {}, {}, {}", this->raw_projections[1][0], this->raw_projections[1][1],this->raw_projections[1][2], this->raw_projections[1][3]); auto& vr = VR::get(); auto get_mat = [&](vr::EVREye eye) { const auto tan_half_fov = new float[4]; - // TODO: mirrored if (vr->get_horiztonal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_SYMMETRIC) { - // TODO: don't need to repeat this calculation for each eye + // TODO: don't need to repeat this calculation for each eye? tan_half_fov[0] = std::max(std::max(-this->raw_projections[0][0], this->raw_projections[0][1]), std::max(-this->raw_projections[1][0], this->raw_projections[1][1])); tan_half_fov[1] = -tan_half_fov[0]; + } else if (vr->get_horiztonal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_MIRROR) { + float max_outer = std::max(-this->raw_projections[0][0], this->raw_projections[1][1]); + float max_inner = std::max(this->raw_projections[0][1], -this->raw_projections[1][0]); + tan_half_fov[0] = eye == 0 ? max_outer : max_inner; + tan_half_fov[1] = eye == 0 ? -max_inner : -max_outer; } else { tan_half_fov[0] = -this->raw_projections[eye][0]; tan_half_fov[1] = -this->raw_projections[eye][1]; } - // TODO: matched if (vr->get_vertical_projection_override() == VR::VERTICAL_PROJECTION_OVERRIDE::VERTICAL_SYMMETRIC) { - // TODO: don't need to repeat this calculation for each eye + // TODO: don't need to repeat this calculation for each eye? tan_half_fov[2] = std::max(std::max(-this->raw_projections[0][2], this->raw_projections[0][3]), std::max(-this->raw_projections[1][2], this->raw_projections[1][3])); tan_half_fov[3] = -tan_half_fov[2]; + } else if (vr->get_vertical_projection_override() == VR::VERTICAL_PROJECTION_OVERRIDE::VERTICAL_MATCHED) { + + float max_top = std::max(-this->raw_projections[0][2], -this->raw_projections[1][2]); + float max_bottom = std::max(this->raw_projections[0][3], this->raw_projections[1][3]); + tan_half_fov[2] = max_top; + tan_half_fov[3] = -max_bottom; } else { tan_half_fov[2] = -this->raw_projections[eye][2]; tan_half_fov[3] = -this->raw_projections[eye][3]; } m_view_bounds[eye][0] = 0.5f + 0.5f * this->raw_projections[eye][0] / tan_half_fov[0]; - m_view_bounds[eye][1] = 0.5f + 0.5f * this->raw_projections[eye][1] / tan_half_fov[1]; + m_view_bounds[eye][1] = 0.5f - 0.5f * this->raw_projections[eye][1] / tan_half_fov[1]; m_view_bounds[eye][2] = 0.5f + 0.5f * this->raw_projections[eye][2] / tan_half_fov[2]; - m_view_bounds[eye][3] = 0.5f + 0.5f * this->raw_projections[eye][3] / tan_half_fov[3]; + m_view_bounds[eye][3] = 0.5f - 0.5f * this->raw_projections[eye][3] / tan_half_fov[3]; const auto left = tan_half_fov[0]; const auto right = tan_half_fov[1]; const auto top = tan_half_fov[2]; const auto bottom = tan_half_fov[3]; // signs : at this point we expect right [1] and bottom [3] to be negative - - //SPDLOG_INFO("Original {}, {}, {}, {}", this->raw_projections[eye][0] * -1.0f, this->raw_projections[eye][1] * -1.0f, this->raw_projections[eye][2] * -1.0f, this->raw_projections[eye][3] * -1.0f); - //SPDLOG_INFO("Modified {}, {}, {}, {}", left, right, top, bottom); + // SPDLOG_INFO("derived for eye {} {}, {}, {}, {}", eye, left, right, top, bottom); + // SPDLOG_INFO("derived bounds eye {} {}, {}, {}, {}", eye, m_view_bounds[eye][0], m_view_bounds[eye][1], m_view_bounds[eye][2], m_view_bounds[eye][3]); float sum_rl = (left + right); float sum_tb = (top + bottom); float inv_rl = (1.0f / (left - right)); diff --git a/src/mods/vr/runtimes/OpenXR.cpp b/src/mods/vr/runtimes/OpenXR.cpp index 9a596d97..d42022a2 100644 --- a/src/mods/vr/runtimes/OpenXR.cpp +++ b/src/mods/vr/runtimes/OpenXR.cpp @@ -483,6 +483,9 @@ VRRuntime::Error OpenXR::update_matrices(float nearz, float farz) { this->raw_projections[1][1] = tan(this->views[1].fov.angleRight); this->raw_projections[1][2] = tan(this->views[1].fov.angleUp); this->raw_projections[1][3] = tan(this->views[1].fov.angleDown); + // SPDLOG_INFO("Original left {}, {}, {}, {}", this->raw_projections[0][0], this->raw_projections[0][1],this->raw_projections[0][2], this->raw_projections[0][3]); + // SPDLOG_INFO("Original right {}, {}, {}, {}", this->raw_projections[1][0], this->raw_projections[1][1],this->raw_projections[1][2], this->raw_projections[1][3]); + for (auto i = 0; i < 2; ++i) { const auto& pose = this->views[i].pose; const auto& fov = this->views[i].fov; @@ -494,30 +497,38 @@ VRRuntime::Error OpenXR::update_matrices(float nearz, float farz) { auto get_mat = [&](int eye) { const auto tan_half_fov = new float[4]; - // TODO: mirrored if (vr->get_horiztonal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_SYMMETRIC) { - // TODO: don't need to repeat this calculation for each eye - tan_half_fov[0] = std::max(std::max(-this->raw_projections[0][0], this->raw_projections[0][1]), - std::max(-this->raw_projections[1][0], this->raw_projections[1][1])); + // TODO: don't need to repeat this calculation for each eye? + tan_half_fov[0] = -std::max(std::max(-this->raw_projections[0][0], this->raw_projections[0][1]), + std::max(-this->raw_projections[1][0], this->raw_projections[1][1])); tan_half_fov[1] = -tan_half_fov[0]; + } else if (vr->get_horiztonal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_MIRROR) { + float max_outer = std::max(-this->raw_projections[0][0], this->raw_projections[1][1]); + float max_inner = std::max(this->raw_projections[0][1], -this->raw_projections[1][0]); + tan_half_fov[0] = eye == 0 ? -max_outer : -max_inner; + tan_half_fov[1] = eye == 0 ? max_inner : max_outer; } else { - tan_half_fov[0] = -this->raw_projections[eye][0]; - tan_half_fov[1] = -this->raw_projections[eye][1]; + tan_half_fov[0] = this->raw_projections[eye][0]; + tan_half_fov[1] = this->raw_projections[eye][1]; } - // TODO: matched if (vr->get_vertical_projection_override() == VR::VERTICAL_PROJECTION_OVERRIDE::VERTICAL_SYMMETRIC) { - // TODO: don't need to repeat this calculation for each eye - tan_half_fov[2] = std::max(std::max(-this->raw_projections[0][2], this->raw_projections[0][3]), - std::max(-this->raw_projections[1][2], this->raw_projections[1][3])); + // TODO: don't need to repeat this calculation for each eye? + tan_half_fov[2] = std::max(std::max(this->raw_projections[0][2], -this->raw_projections[0][3]), + std::max(this->raw_projections[1][2], -this->raw_projections[1][3])); tan_half_fov[3] = -tan_half_fov[2]; + } else if (vr->get_vertical_projection_override() == VR::VERTICAL_PROJECTION_OVERRIDE::VERTICAL_MATCHED) { + float max_top = std::max(this->raw_projections[0][2], this->raw_projections[1][2]); + float max_bottom = std::max(-this->raw_projections[0][3], -this->raw_projections[1][3]); + tan_half_fov[2] = max_top; + tan_half_fov[3] = -max_bottom; } else { - tan_half_fov[2] = -this->raw_projections[eye][2]; - tan_half_fov[3] = -this->raw_projections[eye][3]; + tan_half_fov[2] = this->raw_projections[eye][2]; + tan_half_fov[3] = this->raw_projections[eye][3]; } - m_view_bounds[eye][0] = 0.5f + 0.5f * this->raw_projections[eye][0] / tan_half_fov[0]; + m_view_bounds[eye][0] = 0.5f - 0.5f * this->raw_projections[eye][0] / tan_half_fov[0]; m_view_bounds[eye][1] = 0.5f + 0.5f * this->raw_projections[eye][1] / tan_half_fov[1]; - m_view_bounds[eye][2] = 0.5f + 0.5f * this->raw_projections[eye][2] / tan_half_fov[2]; + m_view_bounds[eye][2] = 0.5f - 0.5f * this->raw_projections[eye][2] / tan_half_fov[2]; m_view_bounds[eye][3] = 0.5f + 0.5f * this->raw_projections[eye][3] / tan_half_fov[3]; const auto left = tan_half_fov[0]; const auto right = tan_half_fov[1]; @@ -525,12 +536,8 @@ VRRuntime::Error OpenXR::update_matrices(float nearz, float farz) { const auto bottom = tan_half_fov[3]; // signs: at this point we expect left[0] and bottom[3] to be negative - - //SPDLOG_INFO("Original {}, {}, {}, {}", tan(this->views[eye].fov.angleLeft), tan(this->views[eye].fov.angleRight), - // tan(this->views[eye].fov.angleUp), tan(this->views[eye].fov.angleDown)); - //SPDLOG_INFO("Modified {}, {}, {}, {}", left, right, top, bottom); - // this->raw_projections[eye][2] * -1.0f, this->raw_projections[eye][3] * -1.0f); - // SPDLOG_INFO("Modified {}, {}, {}, {}", left, right, top, bottom); + // SPDLOG_INFO("derived for eye {} {}, {}, {}, {}", eye, left, right, top, bottom); + // SPDLOG_INFO("derived bounds eye {} {}, {}, {}, {}", eye, m_view_bounds[eye][0], m_view_bounds[eye][1], m_view_bounds[eye][2], m_view_bounds[eye][3]); float sum_rl = (right + left); float sum_tb = (top + bottom); float inv_rl = (1.0f / (right - left)); @@ -1780,14 +1787,19 @@ XrResult OpenXR::end_frame(const std::vector& qua int32_t offset_x = 0, offset_y = 0, extent_x = 0, extent_y = 0; // if we're working with a double-wide texture, use half the view bounds adjustment (as they apply to a single eye) - float width_factor = is_afr ? 1 : 0.5; - int32_t left_start = is_afr || i == 0 ? 0 : swapchain->width / 2; - offset_x = left_start + m_view_bounds[i][0] * swapchain->width * width_factor; - extent_x = m_view_bounds[i][1] * swapchain->width * width_factor - offset_x; + int texture_area_width = is_afr ? swapchain->width : swapchain->width / 2; + if (is_afr || i == 0) { + offset_x = m_view_bounds[i][0] * texture_area_width; + extent_x = m_view_bounds[i][1] * texture_area_width - offset_x; + } else { + // right eye double-wide + offset_x = texture_area_width + m_view_bounds[i][0] * texture_area_width; + extent_x = m_view_bounds[i][1] * texture_area_width - (offset_x - texture_area_width); + } offset_y = m_view_bounds[i][2] * swapchain->height; extent_y = m_view_bounds[i][3] * swapchain->height - offset_y; - //SPDLOG_INFO("image calc {}, {}, {}, {}", offset_x, extent_x, offset_y, extent_y); + // SPDLOG_INFO("image calc for eye {} {}, {}, {}, {}", i, offset_x, extent_x, offset_y, extent_y); projection_layer_views[i].subImage.imageRect.offset = {offset_x, offset_y}; projection_layer_views[i].subImage.imageRect.extent = {extent_x, extent_y}; From 57a8b38ab419f5a96733ca8828e5d4abc32331ca Mon Sep 17 00:00:00 2001 From: mrbelowski Date: Thu, 15 Feb 2024 18:31:01 +0000 Subject: [PATCH 10/17] add option to grow the render target to accommodate projection cropping with no image quality loss (at the expense of performance) --- src/mods/VR.cpp | 1 + src/mods/VR.hpp | 6 ++++++ src/mods/vr/runtimes/OpenVR.cpp | 18 ++++++++++++++++-- src/mods/vr/runtimes/OpenXR.cpp | 22 ++++++++++++++++++---- 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/mods/VR.cpp b/src/mods/VR.cpp index e4e619ce..6517f75e 100644 --- a/src/mods/VR.cpp +++ b/src/mods/VR.cpp @@ -2527,6 +2527,7 @@ void VR::on_draw_sidebar_entry(std::string_view name) { m_horizontal_projection_override->draw("Horiztonal Projection"); m_vertical_projection_override->draw("Vertical Projection"); + m_grow_rectangle_for_projection_cropping->draw("Scale Render Target"); ImGui::TreePop(); } diff --git a/src/mods/VR.hpp b/src/mods/VR.hpp index f5aeb399..678043c2 100644 --- a/src/mods/VR.hpp +++ b/src/mods/VR.hpp @@ -589,6 +589,10 @@ class VR : public Mod { return m_vertical_projection_override->value(); } + bool should_grow_rectangle_for_projection_cropping() const { + return m_grow_rectangle_for_projection_cropping->value(); + } + private: Vector4f get_position_unsafe(uint32_t index) const; Vector4f get_velocity_unsafe(uint32_t index) const; @@ -825,6 +829,7 @@ class VR : public Mod { const ModToggle::Ptr m_swap_controllers{ ModToggle::create(generate_name("SwapControllerInputs"), false) }; const ModCombo::Ptr m_horizontal_projection_override{ModCombo::create(generate_name("HorizontalProjectionOverride"), s_horizontal_projection_override_names)}; const ModCombo::Ptr m_vertical_projection_override{ModCombo::create(generate_name("VerticalProjectionOverride"), s_vertical_projection_override_names)}; + const ModToggle::Ptr m_grow_rectangle_for_projection_cropping{ModToggle::create(generate_name("GrowRectangleForProjectionCropping"), false)}; // Snap turn settings and globals void gamepad_snapturn(XINPUT_STATE& state); @@ -956,6 +961,7 @@ class VR : public Mod { *m_swap_controllers, *m_horizontal_projection_override, *m_vertical_projection_override, + *m_grow_rectangle_for_projection_cropping, *m_snapturn, *m_snapturn_joystick_deadzone, *m_snapturn_angle, diff --git a/src/mods/vr/runtimes/OpenVR.cpp b/src/mods/vr/runtimes/OpenVR.cpp index 04f4471b..5a1b66ef 100644 --- a/src/mods/vr/runtimes/OpenVR.cpp +++ b/src/mods/vr/runtimes/OpenVR.cpp @@ -136,11 +136,25 @@ VRRuntime::Error OpenVR::update_render_target_size() { } uint32_t OpenVR::get_width() const { - return this->w; + auto width = this->w; + // if we've altered the default projection matrix we'll be cropping the image - if the image bounds are non-standard and + // the setting's enabled, scale the recommended width so the cropped width is the same as the recommended width + if (!(m_view_bounds[0][0] == 0 && m_view_bounds[0][1] == 1 && m_view_bounds[1][0] == 0 && m_view_bounds[1][1] == 1) && + VR::get()->should_grow_rectangle_for_projection_cropping()) { + width = width / std::max(m_view_bounds[0][1] - m_view_bounds[0][0], m_view_bounds[1][1] - m_view_bounds[1][0]); + } + return width; } uint32_t OpenVR::get_height() const { - return this->h; + auto height = this->h; + // if we've altered the default projection matrix we'll be cropping the image - if the image bounds are non-standard and + // the setting's enabled, scale the recommended height so the cropped width is the same as the recommended height + if (!(m_view_bounds[0][2] == 0 && m_view_bounds[0][3] == 1 && m_view_bounds[1][2] == 0 && m_view_bounds[1][3] == 1) && + VR::get()->should_grow_rectangle_for_projection_cropping()) { + height = height / std::max(m_view_bounds[0][3] - m_view_bounds[0][2], m_view_bounds[1][3] - m_view_bounds[1][2]); + } + return height; } VRRuntime::Error OpenVR::consume_events(std::function callback) { diff --git a/src/mods/vr/runtimes/OpenXR.cpp b/src/mods/vr/runtimes/OpenXR.cpp index d42022a2..9462a5b1 100644 --- a/src/mods/vr/runtimes/OpenXR.cpp +++ b/src/mods/vr/runtimes/OpenXR.cpp @@ -382,16 +382,30 @@ uint32_t OpenXR::get_width() const { if (this->view_configs.empty()) { return 0; } - - return (uint32_t)((float)this->view_configs[0].recommendedImageRectWidth * this->resolution_scale->value()); + auto width = (float)this->view_configs[0].recommendedImageRectWidth* this->resolution_scale->value(); + // if we've altered the default projection matrix we'll be cropping the image - if the image bounds are non-standard and + // the setting's enabled, scale the recommended width so the cropped width is the same as the recommended width + if (!(m_view_bounds[0][0] == 0 && m_view_bounds[0][1] == 1 && m_view_bounds[1][0] == 0 && m_view_bounds[1][1] == 1) && + VR::get()->should_grow_rectangle_for_projection_cropping()) { + // Grow the recommended size to account for the cropping needed when altering the projection matrix + width = width / std::max(m_view_bounds[0][1] - m_view_bounds[0][0], m_view_bounds[1][1] - m_view_bounds[1][0]); + } + return (uint32_t)width; } uint32_t OpenXR::get_height() const { if (this->view_configs.empty()) { return 0; } - - return (uint32_t)((float)this->view_configs[0].recommendedImageRectHeight * this->resolution_scale->value()); + auto height = (float)this->view_configs[0].recommendedImageRectHeight * this->resolution_scale->value(); + // if we've altered the default projection matrix we'll be cropping the image - if the image bounds are non-standard and + // the setting's enabled, scale the recommended height so the cropped width is the same as the recommended height + if (!(m_view_bounds[0][2] == 0 && m_view_bounds[0][3] == 1 && m_view_bounds[1][2] == 0 && m_view_bounds[1][3] == 1) && + VR::get()->should_grow_rectangle_for_projection_cropping()) { + // Grow the recommended size to account for the cropping needed when altering the projection matrix + height = height / std::max(m_view_bounds[0][3] - m_view_bounds[0][2], m_view_bounds[1][3] - m_view_bounds[1][2]); + } + return (uint32_t)height; } VRRuntime::Error OpenXR::consume_events(std::function callback) { From 6dc0f16251d93298c1171ed76904158f706e31d0 Mon Sep 17 00:00:00 2001 From: mrbelowski Date: Thu, 15 Feb 2024 18:38:29 +0000 Subject: [PATCH 11/17] revert commit hash change --- src/CommitHash.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CommitHash.hpp b/src/CommitHash.hpp index 0284b091..fc2d36d4 100644 --- a/src/CommitHash.hpp +++ b/src/CommitHash.hpp @@ -1,4 +1,4 @@ #pragma once -#define UEVR_COMMIT_HASH "5738af3f164b6d72c22195a2871cc5a6bf5378aa" -#define UEVR_BUILD_DATE "15.02.2024" -#define UEVR_BUILD_TIME "09:14" +#define UEVR_COMMIT_HASH "3997108934a41fdbb1c6a6e8ff59d7fcd63362ac" +#define UEVR_BUILD_DATE "13.02.2024" +#define UEVR_BUILD_TIME "00:00" From 91d8f35ec71912d6a84f79fdc0e328e2296b1578 Mon Sep 17 00:00:00 2001 From: mrbelowski Date: Thu, 15 Feb 2024 21:42:46 +0000 Subject: [PATCH 12/17] fix memory leak; first part of changes following PR comments --- src/mods/VR.cpp | 2 +- src/mods/VR.hpp | 2 +- src/mods/vr/D3D11Component.cpp | 6 +++--- src/mods/vr/D3D12Component.cpp | 6 +++--- src/mods/vr/runtimes/OpenVR.cpp | 6 +++--- src/mods/vr/runtimes/OpenXR.cpp | 6 +++--- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/mods/VR.cpp b/src/mods/VR.cpp index 6517f75e..181ec3ab 100644 --- a/src/mods/VR.cpp +++ b/src/mods/VR.cpp @@ -2525,7 +2525,7 @@ void VR::on_draw_sidebar_entry(std::string_view name) { m_sceneview_compatibility_mode->draw("SceneView Compatibility Mode"); m_extreme_compat_mode->draw("Extreme Compatibility Mode"); - m_horizontal_projection_override->draw("Horiztonal Projection"); + m_horizontal_projection_override->draw("Horizontal Projection"); m_vertical_projection_override->draw("Vertical Projection"); m_grow_rectangle_for_projection_cropping->draw("Scale Render Target"); ImGui::TreePop(); diff --git a/src/mods/VR.hpp b/src/mods/VR.hpp index 678043c2..54ee3660 100644 --- a/src/mods/VR.hpp +++ b/src/mods/VR.hpp @@ -581,7 +581,7 @@ class VR : public Mod { return m_extreme_compat_mode->value(); } - auto get_horiztonal_projection_override() const { + auto get_horizontal_projection_override() const { return m_horizontal_projection_override->value(); } diff --git a/src/mods/vr/D3D11Component.cpp b/src/mods/vr/D3D11Component.cpp index b56f5035..69b07dbe 100644 --- a/src/mods/vr/D3D11Component.cpp +++ b/src/mods/vr/D3D11Component.cpp @@ -559,7 +559,7 @@ vr::EVRCompositorError D3D11Component::on_frame(VR* vr) { (void*)m_left_eye_tex.Get(), vr::TextureType_DirectX, vr::ColorSpace_Auto, submit_pose }; - auto const left_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[0][0], runtime->m_view_bounds[0][2], + const auto left_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[0][0], runtime->m_view_bounds[0][2], runtime->m_view_bounds[0][1], runtime->m_view_bounds[0][3]}; const auto e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); @@ -711,7 +711,7 @@ vr::EVRCompositorError D3D11Component::on_frame(VR* vr) { (void*)m_left_eye_tex.Get(), vr::TextureType_DirectX, vr::ColorSpace_Auto, submit_pose }; - auto const left_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[0][0], runtime->m_view_bounds[0][2], + const auto left_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[0][0], runtime->m_view_bounds[0][2], runtime->m_view_bounds[0][1], runtime->m_view_bounds[0][3]}; e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); @@ -762,7 +762,7 @@ vr::EVRCompositorError D3D11Component::on_frame(VR* vr) { (void*)m_right_eye_tex.Get(), vr::TextureType_DirectX, vr::ColorSpace_Auto, submit_pose }; - auto const right_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[1][0], runtime->m_view_bounds[1][2], + const auto right_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[1][0], runtime->m_view_bounds[1][2], runtime->m_view_bounds[1][1], runtime->m_view_bounds[1][3]}; e = vr::VRCompositor()->Submit(vr::Eye_Right, &right_eye, &right_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); runtime->frame_synced = false; diff --git a/src/mods/vr/D3D12Component.cpp b/src/mods/vr/D3D12Component.cpp index 4806173f..f2e58f66 100644 --- a/src/mods/vr/D3D12Component.cpp +++ b/src/mods/vr/D3D12Component.cpp @@ -398,7 +398,7 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) { (void*)&left, vr::TextureType_DirectX12, vr::ColorSpace_Auto, submit_pose }; - auto const left_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[0][0], runtime->m_view_bounds[0][2], + const auto left_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[0][0], runtime->m_view_bounds[0][2], runtime->m_view_bounds[0][1], runtime->m_view_bounds[0][3]}; auto e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); @@ -497,7 +497,7 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) { (void*)&left, vr::TextureType_DirectX12, vr::ColorSpace_Auto, submit_pose }; - auto const left_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[0][0], runtime->m_view_bounds[0][2], + const auto left_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[0][0], runtime->m_view_bounds[0][2], runtime->m_view_bounds[0][1], runtime->m_view_bounds[0][3]}; auto e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); @@ -523,7 +523,7 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) { (void*)&right, vr::TextureType_DirectX12, vr::ColorSpace_Auto, submit_pose }; - auto const right_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[1][0], runtime->m_view_bounds[1][2], + const auto right_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[1][0], runtime->m_view_bounds[1][2], runtime->m_view_bounds[1][1], runtime->m_view_bounds[1][3]}; auto e = vr::VRCompositor()->Submit(vr::Eye_Right, &right_eye, &right_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); runtime->frame_synced = false; diff --git a/src/mods/vr/runtimes/OpenVR.cpp b/src/mods/vr/runtimes/OpenVR.cpp index 5a1b66ef..2d91c4aa 100644 --- a/src/mods/vr/runtimes/OpenVR.cpp +++ b/src/mods/vr/runtimes/OpenVR.cpp @@ -214,14 +214,14 @@ VRRuntime::Error OpenVR::update_matrices(float nearz, float farz){ auto& vr = VR::get(); auto get_mat = [&](vr::EVREye eye) { - const auto tan_half_fov = new float[4]; + std::array tan_half_fov{}; - if (vr->get_horiztonal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_SYMMETRIC) { + if (vr->get_horizontal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_SYMMETRIC) { // TODO: don't need to repeat this calculation for each eye? tan_half_fov[0] = std::max(std::max(-this->raw_projections[0][0], this->raw_projections[0][1]), std::max(-this->raw_projections[1][0], this->raw_projections[1][1])); tan_half_fov[1] = -tan_half_fov[0]; - } else if (vr->get_horiztonal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_MIRROR) { + } else if (vr->get_horizontal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_MIRROR) { float max_outer = std::max(-this->raw_projections[0][0], this->raw_projections[1][1]); float max_inner = std::max(this->raw_projections[0][1], -this->raw_projections[1][0]); tan_half_fov[0] = eye == 0 ? max_outer : max_inner; diff --git a/src/mods/vr/runtimes/OpenXR.cpp b/src/mods/vr/runtimes/OpenXR.cpp index 9462a5b1..fbebc988 100644 --- a/src/mods/vr/runtimes/OpenXR.cpp +++ b/src/mods/vr/runtimes/OpenXR.cpp @@ -509,14 +509,14 @@ VRRuntime::Error OpenXR::update_matrices(float nearz, float farz) { // NOTE the sign convention for left-right is opposite to how it is in OpenVR. Up/down is the same auto get_mat = [&](int eye) { - const auto tan_half_fov = new float[4]; + std::array tan_half_fov{}; - if (vr->get_horiztonal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_SYMMETRIC) { + if (vr->get_horizontal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_SYMMETRIC) { // TODO: don't need to repeat this calculation for each eye? tan_half_fov[0] = -std::max(std::max(-this->raw_projections[0][0], this->raw_projections[0][1]), std::max(-this->raw_projections[1][0], this->raw_projections[1][1])); tan_half_fov[1] = -tan_half_fov[0]; - } else if (vr->get_horiztonal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_MIRROR) { + } else if (vr->get_horizontal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_MIRROR) { float max_outer = std::max(-this->raw_projections[0][0], this->raw_projections[1][1]); float max_inner = std::max(this->raw_projections[0][1], -this->raw_projections[1][0]); tan_half_fov[0] = eye == 0 ? -max_outer : -max_inner; From 4a099e2914b249b0f4c25e9fa29a8db868b84947 Mon Sep 17 00:00:00 2001 From: mrbelowski Date: Fri, 16 Feb 2024 12:22:51 +0000 Subject: [PATCH 13/17] more tidy up - cache the results of the eye projection and texture bounds / scaling calculations --- src/mods/VR.cpp | 11 +- src/mods/vr/D3D11Component.cpp | 12 +- src/mods/vr/D3D12Component.cpp | 12 +- src/mods/vr/runtimes/OpenVR.cpp | 84 ++++++------ src/mods/vr/runtimes/OpenXR.cpp | 201 ++++++++++++++--------------- src/mods/vr/runtimes/VRRuntime.hpp | 11 +- 6 files changed, 164 insertions(+), 167 deletions(-) diff --git a/src/mods/VR.cpp b/src/mods/VR.cpp index 181ec3ab..8068fd16 100644 --- a/src/mods/VR.cpp +++ b/src/mods/VR.cpp @@ -2525,9 +2525,14 @@ void VR::on_draw_sidebar_entry(std::string_view name) { m_sceneview_compatibility_mode->draw("SceneView Compatibility Mode"); m_extreme_compat_mode->draw("Extreme Compatibility Mode"); - m_horizontal_projection_override->draw("Horizontal Projection"); - m_vertical_projection_override->draw("Vertical Projection"); - m_grow_rectangle_for_projection_cropping->draw("Scale Render Target"); + // changes to any of these options should trigger a regeneration of the eye projection matrices + const auto horizontal_projection_changed = m_horizontal_projection_override->draw("Horizontal Projection"); + const auto vertical_projection_changed = m_vertical_projection_override->draw("Vertical Projection"); + const auto scale_render = m_grow_rectangle_for_projection_cropping->draw("Scale Render Target"); + const auto scale_render_changed = get_runtime()->is_modifying_eye_texture_scale != scale_render; + get_runtime()->is_modifying_eye_texture_scale = scale_render; + get_runtime()->should_recalculate_eye_projections = horizontal_projection_changed || vertical_projection_changed || scale_render_changed; + ImGui::TreePop(); } diff --git a/src/mods/vr/D3D11Component.cpp b/src/mods/vr/D3D11Component.cpp index 69b07dbe..86d9623a 100644 --- a/src/mods/vr/D3D11Component.cpp +++ b/src/mods/vr/D3D11Component.cpp @@ -559,8 +559,8 @@ vr::EVRCompositorError D3D11Component::on_frame(VR* vr) { (void*)m_left_eye_tex.Get(), vr::TextureType_DirectX, vr::ColorSpace_Auto, submit_pose }; - const auto left_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[0][0], runtime->m_view_bounds[0][2], - runtime->m_view_bounds[0][1], runtime->m_view_bounds[0][3]}; + const auto left_bounds = vr::VRTextureBounds_t{runtime->view_bounds[0][0], runtime->view_bounds[0][2], + runtime->view_bounds[0][1], runtime->view_bounds[0][3]}; const auto e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); if (e != vr::VRCompositorError_None) { @@ -711,8 +711,8 @@ vr::EVRCompositorError D3D11Component::on_frame(VR* vr) { (void*)m_left_eye_tex.Get(), vr::TextureType_DirectX, vr::ColorSpace_Auto, submit_pose }; - const auto left_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[0][0], runtime->m_view_bounds[0][2], - runtime->m_view_bounds[0][1], runtime->m_view_bounds[0][3]}; + const auto left_bounds = vr::VRTextureBounds_t{runtime->view_bounds[0][0], runtime->view_bounds[0][2], + runtime->view_bounds[0][1], runtime->view_bounds[0][3]}; e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); if (e != vr::VRCompositorError_None) { @@ -762,8 +762,8 @@ vr::EVRCompositorError D3D11Component::on_frame(VR* vr) { (void*)m_right_eye_tex.Get(), vr::TextureType_DirectX, vr::ColorSpace_Auto, submit_pose }; - const auto right_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[1][0], runtime->m_view_bounds[1][2], - runtime->m_view_bounds[1][1], runtime->m_view_bounds[1][3]}; + const auto right_bounds = vr::VRTextureBounds_t{runtime->view_bounds[1][0], runtime->view_bounds[1][2], + runtime->view_bounds[1][1], runtime->view_bounds[1][3]}; e = vr::VRCompositor()->Submit(vr::Eye_Right, &right_eye, &right_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); runtime->frame_synced = false; diff --git a/src/mods/vr/D3D12Component.cpp b/src/mods/vr/D3D12Component.cpp index f2e58f66..add08453 100644 --- a/src/mods/vr/D3D12Component.cpp +++ b/src/mods/vr/D3D12Component.cpp @@ -398,8 +398,8 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) { (void*)&left, vr::TextureType_DirectX12, vr::ColorSpace_Auto, submit_pose }; - const auto left_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[0][0], runtime->m_view_bounds[0][2], - runtime->m_view_bounds[0][1], runtime->m_view_bounds[0][3]}; + const auto left_bounds = vr::VRTextureBounds_t{runtime->view_bounds[0][0], runtime->view_bounds[0][2], + runtime->view_bounds[0][1], runtime->view_bounds[0][3]}; auto e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); if (e != vr::VRCompositorError_None) { @@ -497,8 +497,8 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) { (void*)&left, vr::TextureType_DirectX12, vr::ColorSpace_Auto, submit_pose }; - const auto left_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[0][0], runtime->m_view_bounds[0][2], - runtime->m_view_bounds[0][1], runtime->m_view_bounds[0][3]}; + const auto left_bounds = vr::VRTextureBounds_t{runtime->view_bounds[0][0], runtime->view_bounds[0][2], + runtime->view_bounds[0][1], runtime->view_bounds[0][3]}; auto e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); if (e != vr::VRCompositorError_None) { @@ -523,8 +523,8 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) { (void*)&right, vr::TextureType_DirectX12, vr::ColorSpace_Auto, submit_pose }; - const auto right_bounds = vr::VRTextureBounds_t{runtime->m_view_bounds[1][0], runtime->m_view_bounds[1][2], - runtime->m_view_bounds[1][1], runtime->m_view_bounds[1][3]}; + const auto right_bounds = vr::VRTextureBounds_t{runtime->view_bounds[1][0], runtime->view_bounds[1][2], + runtime->view_bounds[1][1], runtime->view_bounds[1][3]}; auto e = vr::VRCompositor()->Submit(vr::Eye_Right, &right_eye, &right_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose); runtime->frame_synced = false; diff --git a/src/mods/vr/runtimes/OpenVR.cpp b/src/mods/vr/runtimes/OpenVR.cpp index 2d91c4aa..bf83eaa8 100644 --- a/src/mods/vr/runtimes/OpenVR.cpp +++ b/src/mods/vr/runtimes/OpenVR.cpp @@ -136,25 +136,11 @@ VRRuntime::Error OpenVR::update_render_target_size() { } uint32_t OpenVR::get_width() const { - auto width = this->w; - // if we've altered the default projection matrix we'll be cropping the image - if the image bounds are non-standard and - // the setting's enabled, scale the recommended width so the cropped width is the same as the recommended width - if (!(m_view_bounds[0][0] == 0 && m_view_bounds[0][1] == 1 && m_view_bounds[1][0] == 0 && m_view_bounds[1][1] == 1) && - VR::get()->should_grow_rectangle_for_projection_cropping()) { - width = width / std::max(m_view_bounds[0][1] - m_view_bounds[0][0], m_view_bounds[1][1] - m_view_bounds[1][0]); - } - return width; + return this->w * eye_width_adjustment; } uint32_t OpenVR::get_height() const { - auto height = this->h; - // if we've altered the default projection matrix we'll be cropping the image - if the image bounds are non-standard and - // the setting's enabled, scale the recommended height so the cropped width is the same as the recommended height - if (!(m_view_bounds[0][2] == 0 && m_view_bounds[0][3] == 1 && m_view_bounds[1][2] == 0 && m_view_bounds[1][3] == 1) && - VR::get()->should_grow_rectangle_for_projection_cropping()) { - height = height / std::max(m_view_bounds[0][3] - m_view_bounds[0][2], m_view_bounds[1][3] - m_view_bounds[1][2]); - } - return height; + return this->h * eye_height_adjustment; } VRRuntime::Error OpenVR::consume_events(std::function callback) { @@ -192,8 +178,9 @@ VRRuntime::Error OpenVR::consume_events(std::function callback) { return VRRuntime::Error::SUCCESS; } -// TODO: this is called 6 times per tick, which seems a bit generous VRRuntime::Error OpenVR::update_matrices(float nearz, float farz){ + + // always update the pose: std::unique_lock __{ this->eyes_mtx }; const auto local_left = this->hmd->GetEyeToHeadTransform(vr::Eye_Left); const auto local_right = this->hmd->GetEyeToHeadTransform(vr::Eye_Right); @@ -201,29 +188,17 @@ VRRuntime::Error OpenVR::update_matrices(float nearz, float farz){ this->eyes[vr::Eye_Left] = glm::rowMajor4(Matrix4x4f{ *(Matrix3x4f*)&local_left } ); this->eyes[vr::Eye_Right] = glm::rowMajor4(Matrix4x4f{ *(Matrix3x4f*)&local_right } ); - //auto pleft = this->hmd->GetProjectionMatrix(vr::Eye_Left, nearz, farz); - //auto pright = this->hmd->GetProjectionMatrix(vr::Eye_Right, nearz, farz); - - //this->projections[vr::Eye_Left] = glm::rowMajor4(Matrix4x4f{ *(Matrix4x4f*)&pleft } ); - //this->projections[vr::Eye_Right] = glm::rowMajor4(Matrix4x4f{ *(Matrix4x4f*)&pright } ); - - this->hmd->GetProjectionRaw(vr::Eye_Left, &this->raw_projections[vr::Eye_Left][0], &this->raw_projections[vr::Eye_Left][1], &this->raw_projections[vr::Eye_Left][2], &this->raw_projections[vr::Eye_Left][3]); - this->hmd->GetProjectionRaw(vr::Eye_Right, &this->raw_projections[vr::Eye_Right][0], &this->raw_projections[vr::Eye_Right][1], &this->raw_projections[vr::Eye_Right][2], &this->raw_projections[vr::Eye_Right][3]); - // SPDLOG_INFO("Original left {}, {}, {}, {}", this->raw_projections[0][0], this->raw_projections[0][1],this->raw_projections[0][2], this->raw_projections[0][3]); - // SPDLOG_INFO("Original right {}, {}, {}, {}", this->raw_projections[1][0], this->raw_projections[1][1],this->raw_projections[1][2], this->raw_projections[1][3]); - - auto& vr = VR::get(); auto get_mat = [&](vr::EVREye eye) { + const auto& vr = VR::get(); std::array tan_half_fov{}; if (vr->get_horizontal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_SYMMETRIC) { - // TODO: don't need to repeat this calculation for each eye? tan_half_fov[0] = std::max(std::max(-this->raw_projections[0][0], this->raw_projections[0][1]), std::max(-this->raw_projections[1][0], this->raw_projections[1][1])); tan_half_fov[1] = -tan_half_fov[0]; } else if (vr->get_horizontal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_MIRROR) { - float max_outer = std::max(-this->raw_projections[0][0], this->raw_projections[1][1]); - float max_inner = std::max(this->raw_projections[0][1], -this->raw_projections[1][0]); + const auto max_outer = std::max(-this->raw_projections[0][0], this->raw_projections[1][1]); + const auto max_inner = std::max(this->raw_projections[0][1], -this->raw_projections[1][0]); tan_half_fov[0] = eye == 0 ? max_outer : max_inner; tan_half_fov[1] = eye == 0 ? -max_inner : -max_outer; } else { @@ -232,32 +207,42 @@ VRRuntime::Error OpenVR::update_matrices(float nearz, float farz){ } if (vr->get_vertical_projection_override() == VR::VERTICAL_PROJECTION_OVERRIDE::VERTICAL_SYMMETRIC) { - // TODO: don't need to repeat this calculation for each eye? tan_half_fov[2] = std::max(std::max(-this->raw_projections[0][2], this->raw_projections[0][3]), std::max(-this->raw_projections[1][2], this->raw_projections[1][3])); tan_half_fov[3] = -tan_half_fov[2]; } else if (vr->get_vertical_projection_override() == VR::VERTICAL_PROJECTION_OVERRIDE::VERTICAL_MATCHED) { - float max_top = std::max(-this->raw_projections[0][2], -this->raw_projections[1][2]); - float max_bottom = std::max(this->raw_projections[0][3], this->raw_projections[1][3]); - tan_half_fov[2] = max_top; - tan_half_fov[3] = -max_bottom; + tan_half_fov[2] = std::max(-this->raw_projections[0][2], -this->raw_projections[1][2]); + tan_half_fov[3] = std::max(this->raw_projections[0][3], this->raw_projections[1][3]); } else { tan_half_fov[2] = -this->raw_projections[eye][2]; tan_half_fov[3] = -this->raw_projections[eye][3]; } - m_view_bounds[eye][0] = 0.5f + 0.5f * this->raw_projections[eye][0] / tan_half_fov[0]; - m_view_bounds[eye][1] = 0.5f - 0.5f * this->raw_projections[eye][1] / tan_half_fov[1]; - m_view_bounds[eye][2] = 0.5f + 0.5f * this->raw_projections[eye][2] / tan_half_fov[2]; - m_view_bounds[eye][3] = 0.5f - 0.5f * this->raw_projections[eye][3] / tan_half_fov[3]; + view_bounds[eye][0] = 0.5f + 0.5f * this->raw_projections[eye][0] / tan_half_fov[0]; + view_bounds[eye][1] = 0.5f - 0.5f * this->raw_projections[eye][1] / tan_half_fov[1]; + view_bounds[eye][2] = 0.5f + 0.5f * this->raw_projections[eye][2] / tan_half_fov[2]; + view_bounds[eye][3] = 0.5f - 0.5f * this->raw_projections[eye][3] / tan_half_fov[3]; + + // if we've derived the right eye, we have up to date view bounds for both so adjust the render target if necessary + if (eye == 1) { + if (vr->should_grow_rectangle_for_projection_cropping()) { + eye_width_adjustment = 1 / std::max(view_bounds[0][1] - view_bounds[0][0], view_bounds[1][1] - view_bounds[1][0]); + eye_height_adjustment = 1 / std::max(view_bounds[0][3] - view_bounds[0][2], view_bounds[1][3] - view_bounds[1][2]); + } else { + eye_width_adjustment = 1; + eye_height_adjustment = 1; + } + SPDLOG_INFO("Eye texture proportion scale: {} by {}", eye_width_adjustment, eye_height_adjustment); + } + const auto left = tan_half_fov[0]; const auto right = tan_half_fov[1]; const auto top = tan_half_fov[2]; const auto bottom = tan_half_fov[3]; // signs : at this point we expect right [1] and bottom [3] to be negative - // SPDLOG_INFO("derived for eye {} {}, {}, {}, {}", eye, left, right, top, bottom); - // SPDLOG_INFO("derived bounds eye {} {}, {}, {}, {}", eye, m_view_bounds[eye][0], m_view_bounds[eye][1], m_view_bounds[eye][2], m_view_bounds[eye][3]); + SPDLOG_INFO("derived FOV for {} eye: {}, {}, {}, {}", eye == 0 ? "left" : "right", left, right, top, bottom); + SPDLOG_INFO("derived texture bounds {} eye: {}, {}, {}, {}", eye == 0 ? "left" : "right", view_bounds[eye][0], view_bounds[eye][1], view_bounds[eye][2], view_bounds[eye][3]); float sum_rl = (left + right); float sum_tb = (top + bottom); float inv_rl = (1.0f / (left - right)); @@ -270,10 +255,15 @@ VRRuntime::Error OpenVR::update_matrices(float nearz, float farz){ 0.0f, 0.0f, nearz, 0.0f }; }; - - this->projections[vr::Eye_Left] = get_mat(vr::Eye_Left); - this->projections[vr::Eye_Right] = get_mat(vr::Eye_Right); - + // if we've not yet derived an eye projection matrix, or we've changed the projection, derive it here + // Hacky way to check for an uninitialised eye matrix - is there something better, is this necessary? + if (this->should_recalculate_eye_projections || this->projections[vr::Eye_Left][2][3] == 0) { + this->hmd->GetProjectionRaw(vr::Eye_Left, &this->raw_projections[vr::Eye_Left][0], &this->raw_projections[vr::Eye_Left][1], &this->raw_projections[vr::Eye_Left][2], &this->raw_projections[vr::Eye_Left][3]); + this->hmd->GetProjectionRaw(vr::Eye_Right, &this->raw_projections[vr::Eye_Right][0], &this->raw_projections[vr::Eye_Right][1], &this->raw_projections[vr::Eye_Right][2], &this->raw_projections[vr::Eye_Right][3]); + this->projections[vr::Eye_Left] = get_mat(vr::Eye_Left); + this->projections[vr::Eye_Right] = get_mat(vr::Eye_Right); + this->should_recalculate_eye_projections = false; + } return VRRuntime::Error::SUCCESS; } diff --git a/src/mods/vr/runtimes/OpenXR.cpp b/src/mods/vr/runtimes/OpenXR.cpp index fbebc988..6b65c492 100644 --- a/src/mods/vr/runtimes/OpenXR.cpp +++ b/src/mods/vr/runtimes/OpenXR.cpp @@ -382,30 +382,14 @@ uint32_t OpenXR::get_width() const { if (this->view_configs.empty()) { return 0; } - auto width = (float)this->view_configs[0].recommendedImageRectWidth* this->resolution_scale->value(); - // if we've altered the default projection matrix we'll be cropping the image - if the image bounds are non-standard and - // the setting's enabled, scale the recommended width so the cropped width is the same as the recommended width - if (!(m_view_bounds[0][0] == 0 && m_view_bounds[0][1] == 1 && m_view_bounds[1][0] == 0 && m_view_bounds[1][1] == 1) && - VR::get()->should_grow_rectangle_for_projection_cropping()) { - // Grow the recommended size to account for the cropping needed when altering the projection matrix - width = width / std::max(m_view_bounds[0][1] - m_view_bounds[0][0], m_view_bounds[1][1] - m_view_bounds[1][0]); - } - return (uint32_t)width; + return (uint32_t)((float)this->view_configs[0].recommendedImageRectWidth * this->resolution_scale->value() * eye_width_adjustment); } uint32_t OpenXR::get_height() const { if (this->view_configs.empty()) { return 0; } - auto height = (float)this->view_configs[0].recommendedImageRectHeight * this->resolution_scale->value(); - // if we've altered the default projection matrix we'll be cropping the image - if the image bounds are non-standard and - // the setting's enabled, scale the recommended height so the cropped width is the same as the recommended height - if (!(m_view_bounds[0][2] == 0 && m_view_bounds[0][3] == 1 && m_view_bounds[1][2] == 0 && m_view_bounds[1][3] == 1) && - VR::get()->should_grow_rectangle_for_projection_cropping()) { - // Grow the recommended size to account for the cropping needed when altering the projection matrix - height = height / std::max(m_view_bounds[0][3] - m_view_bounds[0][2], m_view_bounds[1][3] - m_view_bounds[1][2]); - } - return (uint32_t)height; + return (uint32_t)((float)this->view_configs[0].recommendedImageRectHeight * this->resolution_scale->value() * eye_height_adjustment); } VRRuntime::Error OpenXR::consume_events(std::function callback) { @@ -483,93 +467,102 @@ VRRuntime::Error OpenXR::update_matrices(float nearz, float farz) { return VRRuntime::Error::SUCCESS; } - std::unique_lock __{ this->eyes_mtx }; + // always update the pose: std::unique_lock ___{ this->pose_mtx }; + const auto& left_pose = this->views[0].pose; + const auto& right_pose = this->views[1].pose; + this->eyes[0] = Matrix4x4f{OpenXR::to_glm(left_pose.orientation)}; + this->eyes[0][3] = Vector4f{*(Vector3f*)&left_pose.position, 1.0f}; + this->eyes[1] = Matrix4x4f{OpenXR::to_glm(right_pose.orientation)}; + this->eyes[1][3] = Vector4f{*(Vector3f*)&right_pose.position, 1.0f}; + + auto get_mat = [&](int eye) { + const auto& vr = VR::get(); + std::array tan_half_fov{}; + + if (vr->get_horizontal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_SYMMETRIC) { + tan_half_fov[0] = -std::max(std::max(-this->raw_projections[0][0], this->raw_projections[0][1]), + std::max(-this->raw_projections[1][0], this->raw_projections[1][1])); + tan_half_fov[1] = -tan_half_fov[0]; + } else if (vr->get_horizontal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_MIRROR) { + float max_outer = std::max(-this->raw_projections[0][0], this->raw_projections[1][1]); + float max_inner = std::max(this->raw_projections[0][1], -this->raw_projections[1][0]); + tan_half_fov[0] = eye == 0 ? -max_outer : -max_inner; + tan_half_fov[1] = eye == 0 ? max_inner : max_outer; + } else { + tan_half_fov[0] = this->raw_projections[eye][0]; + tan_half_fov[1] = this->raw_projections[eye][1]; + } - auto& vr = VR::get(); - - // TODO: check signs - this->raw_projections[0][0] = tan(this->views[0].fov.angleLeft); - this->raw_projections[0][1] = tan(this->views[0].fov.angleRight); - this->raw_projections[0][2] = tan(this->views[0].fov.angleUp); - this->raw_projections[0][3] = tan(this->views[0].fov.angleDown); - this->raw_projections[1][0] = tan(this->views[1].fov.angleLeft); - this->raw_projections[1][1] = tan(this->views[1].fov.angleRight); - this->raw_projections[1][2] = tan(this->views[1].fov.angleUp); - this->raw_projections[1][3] = tan(this->views[1].fov.angleDown); - // SPDLOG_INFO("Original left {}, {}, {}, {}", this->raw_projections[0][0], this->raw_projections[0][1],this->raw_projections[0][2], this->raw_projections[0][3]); - // SPDLOG_INFO("Original right {}, {}, {}, {}", this->raw_projections[1][0], this->raw_projections[1][1],this->raw_projections[1][2], this->raw_projections[1][3]); - - for (auto i = 0; i < 2; ++i) { - const auto& pose = this->views[i].pose; - const auto& fov = this->views[i].fov; - - // Update projection matrix - //XrMatrix4x4f_CreateProjection((XrMatrix4x4f*)&this->projections[i], GRAPHICS_D3D, tan(fov.angleLeft), tan(fov.angleRight), tan(fov.angleUp), tan(fov.angleDown), nearz, farz); - - // NOTE the sign convention for left-right is opposite to how it is in OpenVR. Up/down is the same - auto get_mat = [&](int eye) { - std::array tan_half_fov{}; - - if (vr->get_horizontal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_SYMMETRIC) { - // TODO: don't need to repeat this calculation for each eye? - tan_half_fov[0] = -std::max(std::max(-this->raw_projections[0][0], this->raw_projections[0][1]), - std::max(-this->raw_projections[1][0], this->raw_projections[1][1])); - tan_half_fov[1] = -tan_half_fov[0]; - } else if (vr->get_horizontal_projection_override() == VR::HORIZONTAL_PROJECTION_OVERRIDE::HORIZONTAL_MIRROR) { - float max_outer = std::max(-this->raw_projections[0][0], this->raw_projections[1][1]); - float max_inner = std::max(this->raw_projections[0][1], -this->raw_projections[1][0]); - tan_half_fov[0] = eye == 0 ? -max_outer : -max_inner; - tan_half_fov[1] = eye == 0 ? max_inner : max_outer; + if (vr->get_vertical_projection_override() == VR::VERTICAL_PROJECTION_OVERRIDE::VERTICAL_SYMMETRIC) { + tan_half_fov[2] = std::max(std::max(this->raw_projections[0][2], -this->raw_projections[0][3]), + std::max(this->raw_projections[1][2], -this->raw_projections[1][3])); + tan_half_fov[3] = -tan_half_fov[2]; + } else if (vr->get_vertical_projection_override() == VR::VERTICAL_PROJECTION_OVERRIDE::VERTICAL_MATCHED) { + float max_top = std::max(this->raw_projections[0][2], this->raw_projections[1][2]); + float max_bottom = std::max(-this->raw_projections[0][3], -this->raw_projections[1][3]); + tan_half_fov[2] = max_top; + tan_half_fov[3] = -max_bottom; + } else { + tan_half_fov[2] = this->raw_projections[eye][2]; + tan_half_fov[3] = this->raw_projections[eye][3]; + } + view_bounds[eye][0] = 0.5f - 0.5f * this->raw_projections[eye][0] / tan_half_fov[0]; + view_bounds[eye][1] = 0.5f + 0.5f * this->raw_projections[eye][1] / tan_half_fov[1]; + view_bounds[eye][2] = 0.5f - 0.5f * this->raw_projections[eye][2] / tan_half_fov[2]; + view_bounds[eye][3] = 0.5f + 0.5f * this->raw_projections[eye][3] / tan_half_fov[3]; + + // if we've derived the right eye, we have up to date view bounds for both so adjust the render target if necessary + if (eye == 1) { + if (vr->should_grow_rectangle_for_projection_cropping()) { + eye_width_adjustment = 1 / std::max(view_bounds[0][1] - view_bounds[0][0], view_bounds[1][1] - view_bounds[1][0]); + eye_height_adjustment = 1 / std::max(view_bounds[0][3] - view_bounds[0][2], view_bounds[1][3] - view_bounds[1][2]); } else { - tan_half_fov[0] = this->raw_projections[eye][0]; - tan_half_fov[1] = this->raw_projections[eye][1]; + eye_width_adjustment = 1; + eye_height_adjustment = 1; } + SPDLOG_INFO("Eye texture proportion scale: {} by {}", eye_width_adjustment, eye_height_adjustment); + } - if (vr->get_vertical_projection_override() == VR::VERTICAL_PROJECTION_OVERRIDE::VERTICAL_SYMMETRIC) { - // TODO: don't need to repeat this calculation for each eye? - tan_half_fov[2] = std::max(std::max(this->raw_projections[0][2], -this->raw_projections[0][3]), - std::max(this->raw_projections[1][2], -this->raw_projections[1][3])); - tan_half_fov[3] = -tan_half_fov[2]; - } else if (vr->get_vertical_projection_override() == VR::VERTICAL_PROJECTION_OVERRIDE::VERTICAL_MATCHED) { - float max_top = std::max(this->raw_projections[0][2], this->raw_projections[1][2]); - float max_bottom = std::max(-this->raw_projections[0][3], -this->raw_projections[1][3]); - tan_half_fov[2] = max_top; - tan_half_fov[3] = -max_bottom; - } else { - tan_half_fov[2] = this->raw_projections[eye][2]; - tan_half_fov[3] = this->raw_projections[eye][3]; - } - m_view_bounds[eye][0] = 0.5f - 0.5f * this->raw_projections[eye][0] / tan_half_fov[0]; - m_view_bounds[eye][1] = 0.5f + 0.5f * this->raw_projections[eye][1] / tan_half_fov[1]; - m_view_bounds[eye][2] = 0.5f - 0.5f * this->raw_projections[eye][2] / tan_half_fov[2]; - m_view_bounds[eye][3] = 0.5f + 0.5f * this->raw_projections[eye][3] / tan_half_fov[3]; - const auto left = tan_half_fov[0]; - const auto right = tan_half_fov[1]; - const auto top = tan_half_fov[2]; - const auto bottom = tan_half_fov[3]; - - // signs: at this point we expect left[0] and bottom[3] to be negative - // SPDLOG_INFO("derived for eye {} {}, {}, {}, {}", eye, left, right, top, bottom); - // SPDLOG_INFO("derived bounds eye {} {}, {}, {}, {}", eye, m_view_bounds[eye][0], m_view_bounds[eye][1], m_view_bounds[eye][2], m_view_bounds[eye][3]); - float sum_rl = (right + left); - float sum_tb = (top + bottom); - float inv_rl = (1.0f / (right - left)); - float inv_tb = (1.0f / (top - bottom)); - - return Matrix4x4f { - (2.0f * inv_rl), 0.0f, 0.0f, 0.0f, - 0.0f, (2.0f * inv_tb), 0.0f, 0.0f, - (sum_rl * -inv_rl), (sum_tb * -inv_tb), 0.0f, 1.0f, - 0.0f, 0.0f, nearz, 0.0f - }; + const auto left = tan_half_fov[0]; + const auto right = tan_half_fov[1]; + const auto top = tan_half_fov[2]; + const auto bottom = tan_half_fov[3]; + + // signs: at this point we expect left[0] and bottom[3] to be negative + SPDLOG_INFO("derived FOV for {} eye: {}, {}, {}, {}", eye == 0 ? "left" : "right", left, right, top, bottom); + SPDLOG_INFO("derived texture bounds {} eye: {}, {}, {}, {}", eye == 0 ? "left" : "right", view_bounds[eye][0], view_bounds[eye][1], view_bounds[eye][2], view_bounds[eye][3]); + float sum_rl = (right + left); + float sum_tb = (top + bottom); + float inv_rl = (1.0f / (right - left)); + float inv_tb = (1.0f / (top - bottom)); + + return Matrix4x4f { + (2.0f * inv_rl), 0.0f, 0.0f, 0.0f, + 0.0f, (2.0f * inv_tb), 0.0f, 0.0f, + (sum_rl * -inv_rl), (sum_tb * -inv_tb), 0.0f, 1.0f, + 0.0f, 0.0f, nearz, 0.0f }; + }; - this->projections[i] = get_mat(i); - - // Update view matrix - this->eyes[i] = Matrix4x4f{OpenXR::to_glm(pose.orientation)}; - this->eyes[i][3] = Vector4f{*(Vector3f*)&pose.position, 1.0f}; + // if we've not yet derived an eye projection matrix, or we've changed the projection, derive it here + // Hacky way to check for an uninitialised eye matrix - is there something better, is this necessary? + if (this->should_recalculate_eye_projections || this->projections[0][2][3] == 0) { + // deriving the texture bounds when modifying projections requires left and right raw projections so get them all before we start: + std::unique_lock __{this->eyes_mtx}; + const auto& left_fov = this->views[0].fov; + this->raw_projections[0][0] = tan(left_fov.angleLeft); + this->raw_projections[0][1] = tan(left_fov.angleRight); + this->raw_projections[0][2] = tan(left_fov.angleUp); + this->raw_projections[0][3] = tan(left_fov.angleDown); + const auto& right_fov = this->views[1].fov; + this->raw_projections[1][0] = tan(right_fov.angleLeft); + this->raw_projections[1][1] = tan(right_fov.angleRight); + this->raw_projections[1][2] = tan(right_fov.angleUp); + this->raw_projections[1][3] = tan(right_fov.angleDown); + this->projections[0] = get_mat(0); + this->projections[1] = get_mat(1); + this->should_recalculate_eye_projections = false; } return VRRuntime::Error::SUCCESS; @@ -1803,15 +1796,15 @@ XrResult OpenXR::end_frame(const std::vector& qua // if we're working with a double-wide texture, use half the view bounds adjustment (as they apply to a single eye) int texture_area_width = is_afr ? swapchain->width : swapchain->width / 2; if (is_afr || i == 0) { - offset_x = m_view_bounds[i][0] * texture_area_width; - extent_x = m_view_bounds[i][1] * texture_area_width - offset_x; + offset_x = view_bounds[i][0] * texture_area_width; + extent_x = view_bounds[i][1] * texture_area_width - offset_x; } else { // right eye double-wide - offset_x = texture_area_width + m_view_bounds[i][0] * texture_area_width; - extent_x = m_view_bounds[i][1] * texture_area_width - (offset_x - texture_area_width); + offset_x = texture_area_width + view_bounds[i][0] * texture_area_width; + extent_x = view_bounds[i][1] * texture_area_width - (offset_x - texture_area_width); } - offset_y = m_view_bounds[i][2] * swapchain->height; - extent_y = m_view_bounds[i][3] * swapchain->height - offset_y; + offset_y = view_bounds[i][2] * swapchain->height; + extent_y = view_bounds[i][3] * swapchain->height - offset_y; // SPDLOG_INFO("image calc for eye {} {}, {}, {}, {}", i, offset_x, extent_x, offset_y, extent_y); projection_layer_views[i].subImage.imageRect.offset = {offset_x, offset_y}; diff --git a/src/mods/vr/runtimes/VRRuntime.hpp b/src/mods/vr/runtimes/VRRuntime.hpp index a2a2b074..da4cf9c8 100644 --- a/src/mods/vr/runtimes/VRRuntime.hpp +++ b/src/mods/vr/runtimes/VRRuntime.hpp @@ -195,5 +195,14 @@ struct VRRuntime { bool has_render_frame_count{false}; // view bounds proportions - left xmin, xmax, ymin, ymax then right xmin, xmax, ymin, ymax - float m_view_bounds[2][4] = {0, 1, 0, 1, 0, 1, 0, 1}; + // used to crop the rendered eye textures to account for projection adjustments + float view_bounds[2][4] = {0, 1, 0, 1, 0, 1, 0, 1}; + + bool should_recalculate_eye_projections{false}; + bool is_modifying_eye_texture_scale{false}; + + // factor to scale the recommended eye texture size where we're cropping due to projection overrides, but + // want to retain the final eye texture resolution + float eye_width_adjustment{1}; + float eye_height_adjustment{1}; }; \ No newline at end of file From 95961a3557aca2969693a33e2af1730984adcc0b Mon Sep 17 00:00:00 2001 From: mrbelowski Date: Fri, 16 Feb 2024 16:14:25 +0000 Subject: [PATCH 14/17] only get the eye positions once per framework sync --- src/CommitHash.hpp | 6 +++--- src/mods/vr/runtimes/OpenVR.cpp | 11 +++++++++-- src/mods/vr/runtimes/OpenXR.cpp | 11 +++++++++-- src/mods/vr/runtimes/VRRuntime.hpp | 1 + 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/CommitHash.hpp b/src/CommitHash.hpp index 7e00fe92..c3c400fd 100644 --- a/src/CommitHash.hpp +++ b/src/CommitHash.hpp @@ -1,4 +1,4 @@ #pragma once -#define UEVR_COMMIT_HASH "be2dff432001a24c045fadea6699def157c05a17" -#define UEVR_BUILD_DATE "15.02.2024" -#define UEVR_BUILD_TIME "00:00" +#define UEVR_COMMIT_HASH "6a837bc85d408514a0901c2212e466edd2bd99e0" +#define UEVR_BUILD_DATE "16.02.2024" +#define UEVR_BUILD_TIME "14:19" diff --git a/src/mods/vr/runtimes/OpenVR.cpp b/src/mods/vr/runtimes/OpenVR.cpp index bf83eaa8..8baac314 100644 --- a/src/mods/vr/runtimes/OpenVR.cpp +++ b/src/mods/vr/runtimes/OpenVR.cpp @@ -20,8 +20,8 @@ VRRuntime::Error OpenVR::synchronize_frame(std::optional frame_count) this->got_first_valid_poses = true; this->got_first_sync = true; this->frame_synced = true; + this->should_update_eye_matrices = true; } - return (VRRuntime::Error)ret; } @@ -178,7 +178,12 @@ VRRuntime::Error OpenVR::consume_events(std::function callback) { return VRRuntime::Error::SUCCESS; } -VRRuntime::Error OpenVR::update_matrices(float nearz, float farz){ +VRRuntime::Error OpenVR::update_matrices(float nearz, float farz) { + // exit immediately if we've updated the eye matrices since the last frame sync, so we only do this + // operation once per sync + if (!this->should_update_eye_matrices) { + return VRRuntime::Error::SUCCESS; + } // always update the pose: std::unique_lock __{ this->eyes_mtx }; @@ -264,6 +269,8 @@ VRRuntime::Error OpenVR::update_matrices(float nearz, float farz){ this->projections[vr::Eye_Right] = get_mat(vr::Eye_Right); this->should_recalculate_eye_projections = false; } + // don't allow the eye matrices to be derived again until after the next frame sync + this->should_update_eye_matrices = false; return VRRuntime::Error::SUCCESS; } diff --git a/src/mods/vr/runtimes/OpenXR.cpp b/src/mods/vr/runtimes/OpenXR.cpp index 6b65c492..8063a9a0 100644 --- a/src/mods/vr/runtimes/OpenXR.cpp +++ b/src/mods/vr/runtimes/OpenXR.cpp @@ -185,8 +185,8 @@ VRRuntime::Error OpenXR::synchronize_frame(std::optional frame_count) this->got_first_sync = true; this->frame_synced = true; + this->should_update_eye_matrices = true; } - return VRRuntime::Error::SUCCESS; } @@ -463,6 +463,12 @@ VRRuntime::Error OpenXR::consume_events(std::function callback) { } VRRuntime::Error OpenXR::update_matrices(float nearz, float farz) { + // exit immediately if we've updated the eye matrices since the last frame sync, so we only do this + // operation once per sync + if (!this->should_update_eye_matrices) { + return VRRuntime::Error::SUCCESS; + } + if (!this->session_ready || this->views.empty()) { return VRRuntime::Error::SUCCESS; } @@ -564,7 +570,8 @@ VRRuntime::Error OpenXR::update_matrices(float nearz, float farz) { this->projections[1] = get_mat(1); this->should_recalculate_eye_projections = false; } - + // don't allow the eye matrices to be derived again until after the next frame sync + this->should_update_eye_matrices = false; return VRRuntime::Error::SUCCESS; } diff --git a/src/mods/vr/runtimes/VRRuntime.hpp b/src/mods/vr/runtimes/VRRuntime.hpp index da4cf9c8..5aa64a99 100644 --- a/src/mods/vr/runtimes/VRRuntime.hpp +++ b/src/mods/vr/runtimes/VRRuntime.hpp @@ -198,6 +198,7 @@ struct VRRuntime { // used to crop the rendered eye textures to account for projection adjustments float view_bounds[2][4] = {0, 1, 0, 1, 0, 1, 0, 1}; + bool should_update_eye_matrices{true}; bool should_recalculate_eye_projections{false}; bool is_modifying_eye_texture_scale{false}; From bfd2c5aecc516e058a90f301483de8238eb8d24c Mon Sep 17 00:00:00 2001 From: mrbelowski Date: Sat, 17 Feb 2024 10:17:54 +0000 Subject: [PATCH 15/17] ensure changes to near clipping plane trigger eye matrix derivation; added original FOV to log messages when deriving eye matrices --- src/mods/vr/runtimes/OpenVR.cpp | 9 ++++++--- src/mods/vr/runtimes/OpenXR.cpp | 9 ++++++--- src/mods/vr/runtimes/VRRuntime.hpp | 1 + 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/mods/vr/runtimes/OpenVR.cpp b/src/mods/vr/runtimes/OpenVR.cpp index 8baac314..45155e19 100644 --- a/src/mods/vr/runtimes/OpenVR.cpp +++ b/src/mods/vr/runtimes/OpenVR.cpp @@ -246,8 +246,10 @@ VRRuntime::Error OpenVR::update_matrices(float nearz, float farz) { const auto bottom = tan_half_fov[3]; // signs : at this point we expect right [1] and bottom [3] to be negative - SPDLOG_INFO("derived FOV for {} eye: {}, {}, {}, {}", eye == 0 ? "left" : "right", left, right, top, bottom); - SPDLOG_INFO("derived texture bounds {} eye: {}, {}, {}, {}", eye == 0 ? "left" : "right", view_bounds[eye][0], view_bounds[eye][1], view_bounds[eye][2], view_bounds[eye][3]); + SPDLOG_INFO("Original FOV for {} eye: {}, {}, {}, {}", eye == 0 ? "left" : "right", -this->raw_projections[eye][0], -this->raw_projections[eye][1], + -this->raw_projections[eye][2], -this->raw_projections[eye][3]); + SPDLOG_INFO("Derived FOV for {} eye: {}, {}, {}, {}", eye == 0 ? "left" : "right", left, right, top, bottom); + SPDLOG_INFO("Derived texture bounds {} eye: {}, {}, {}, {}", eye == 0 ? "left" : "right", view_bounds[eye][0], view_bounds[eye][1], view_bounds[eye][2], view_bounds[eye][3]); float sum_rl = (left + right); float sum_tb = (top + bottom); float inv_rl = (1.0f / (left - right)); @@ -262,12 +264,13 @@ VRRuntime::Error OpenVR::update_matrices(float nearz, float farz) { }; // if we've not yet derived an eye projection matrix, or we've changed the projection, derive it here // Hacky way to check for an uninitialised eye matrix - is there something better, is this necessary? - if (this->should_recalculate_eye_projections || this->projections[vr::Eye_Left][2][3] == 0) { + if (this->should_recalculate_eye_projections || this->last_eye_matrix_nearz != nearz || this->projections[vr::Eye_Left][2][3] == 0) { this->hmd->GetProjectionRaw(vr::Eye_Left, &this->raw_projections[vr::Eye_Left][0], &this->raw_projections[vr::Eye_Left][1], &this->raw_projections[vr::Eye_Left][2], &this->raw_projections[vr::Eye_Left][3]); this->hmd->GetProjectionRaw(vr::Eye_Right, &this->raw_projections[vr::Eye_Right][0], &this->raw_projections[vr::Eye_Right][1], &this->raw_projections[vr::Eye_Right][2], &this->raw_projections[vr::Eye_Right][3]); this->projections[vr::Eye_Left] = get_mat(vr::Eye_Left); this->projections[vr::Eye_Right] = get_mat(vr::Eye_Right); this->should_recalculate_eye_projections = false; + this->last_eye_matrix_nearz = nearz; } // don't allow the eye matrices to be derived again until after the next frame sync this->should_update_eye_matrices = false; diff --git a/src/mods/vr/runtimes/OpenXR.cpp b/src/mods/vr/runtimes/OpenXR.cpp index 8063a9a0..9b2fda09 100644 --- a/src/mods/vr/runtimes/OpenXR.cpp +++ b/src/mods/vr/runtimes/OpenXR.cpp @@ -536,8 +536,10 @@ VRRuntime::Error OpenXR::update_matrices(float nearz, float farz) { const auto bottom = tan_half_fov[3]; // signs: at this point we expect left[0] and bottom[3] to be negative - SPDLOG_INFO("derived FOV for {} eye: {}, {}, {}, {}", eye == 0 ? "left" : "right", left, right, top, bottom); - SPDLOG_INFO("derived texture bounds {} eye: {}, {}, {}, {}", eye == 0 ? "left" : "right", view_bounds[eye][0], view_bounds[eye][1], view_bounds[eye][2], view_bounds[eye][3]); + SPDLOG_INFO("Original FOV for {} eye: {}, {}, {}, {}", eye == 0 ? "left" : "right", this->raw_projections[eye][0], this->raw_projections[eye][1], + this->raw_projections[eye][2], this->raw_projections[eye][3]); + SPDLOG_INFO("Derived FOV for {} eye: {}, {}, {}, {}", eye == 0 ? "left" : "right", left, right, top, bottom); + SPDLOG_INFO("Derived texture bounds {} eye: {}, {}, {}, {}", eye == 0 ? "left" : "right", view_bounds[eye][0], view_bounds[eye][1], view_bounds[eye][2], view_bounds[eye][3]); float sum_rl = (right + left); float sum_tb = (top + bottom); float inv_rl = (1.0f / (right - left)); @@ -553,7 +555,7 @@ VRRuntime::Error OpenXR::update_matrices(float nearz, float farz) { // if we've not yet derived an eye projection matrix, or we've changed the projection, derive it here // Hacky way to check for an uninitialised eye matrix - is there something better, is this necessary? - if (this->should_recalculate_eye_projections || this->projections[0][2][3] == 0) { + if (this->should_recalculate_eye_projections || this->last_eye_matrix_nearz != nearz || this->projections[0][2][3] == 0) { // deriving the texture bounds when modifying projections requires left and right raw projections so get them all before we start: std::unique_lock __{this->eyes_mtx}; const auto& left_fov = this->views[0].fov; @@ -569,6 +571,7 @@ VRRuntime::Error OpenXR::update_matrices(float nearz, float farz) { this->projections[0] = get_mat(0); this->projections[1] = get_mat(1); this->should_recalculate_eye_projections = false; + this->last_eye_matrix_nearz = nearz; } // don't allow the eye matrices to be derived again until after the next frame sync this->should_update_eye_matrices = false; diff --git a/src/mods/vr/runtimes/VRRuntime.hpp b/src/mods/vr/runtimes/VRRuntime.hpp index 5aa64a99..f773c1e7 100644 --- a/src/mods/vr/runtimes/VRRuntime.hpp +++ b/src/mods/vr/runtimes/VRRuntime.hpp @@ -198,6 +198,7 @@ struct VRRuntime { // used to crop the rendered eye textures to account for projection adjustments float view_bounds[2][4] = {0, 1, 0, 1, 0, 1, 0, 1}; + float last_eye_matrix_nearz = 0.01f; bool should_update_eye_matrices{true}; bool should_recalculate_eye_projections{false}; bool is_modifying_eye_texture_scale{false}; From 540b5265eb0610df704282c38e5e785a4b938439 Mon Sep 17 00:00:00 2001 From: mrbelowski Date: Tue, 20 Feb 2024 16:08:31 +0000 Subject: [PATCH 16/17] fix incorrect vertical matched for openVR --- src/mods/vr/runtimes/OpenVR.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mods/vr/runtimes/OpenVR.cpp b/src/mods/vr/runtimes/OpenVR.cpp index 45155e19..4777562a 100644 --- a/src/mods/vr/runtimes/OpenVR.cpp +++ b/src/mods/vr/runtimes/OpenVR.cpp @@ -218,7 +218,7 @@ VRRuntime::Error OpenVR::update_matrices(float nearz, float farz) { } else if (vr->get_vertical_projection_override() == VR::VERTICAL_PROJECTION_OVERRIDE::VERTICAL_MATCHED) { tan_half_fov[2] = std::max(-this->raw_projections[0][2], -this->raw_projections[1][2]); - tan_half_fov[3] = std::max(this->raw_projections[0][3], this->raw_projections[1][3]); + tan_half_fov[3] = -std::max(this->raw_projections[0][3], this->raw_projections[1][3]); } else { tan_half_fov[2] = -this->raw_projections[eye][2]; tan_half_fov[3] = -this->raw_projections[eye][3]; From 1a320c6cd52ee55843a9164316934f8f77109af8 Mon Sep 17 00:00:00 2001 From: praydog Date: Wed, 20 Mar 2024 13:06:40 -0700 Subject: [PATCH 17/17] Remove unused CommitHash.hpp --- src/CommitHash.hpp | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/CommitHash.hpp diff --git a/src/CommitHash.hpp b/src/CommitHash.hpp deleted file mode 100644 index 8b137891..00000000 --- a/src/CommitHash.hpp +++ /dev/null @@ -1 +0,0 @@ -