Skip to content

Commit 9074c01

Browse files
mrbelowskipraydog
andauthored
OpenVR and OpenXR symmetric and other projection matrix options (#196)
* naive symmetric projection for OpenVR * WIP OpenXR symmetric projection * first cut of OpenXR symmetric projection matrices - desparately needs tidying up but appears to work correctly * tweak a calculation the looked upside down (but is hard to tell with Index's almost vertically symmetric projection) * WIP * more WIP - reworked bounds and FOV calculations to reduce mess; still need to verify OpenXR signs * wip * wip * corrected various calculations; added mirrored projections * add option to grow the render target to accommodate projection cropping with no image quality loss (at the expense of performance) * revert commit hash change * fix memory leak; first part of changes following PR comments * more tidy up - cache the results of the eye projection and texture bounds / scaling calculations * only get the eye positions once per framework sync * ensure changes to near clipping plane trigger eye matrix derivation; added original FOV to log messages when deriving eye matrices * fix incorrect vertical matched for openVR * Remove unused CommitHash.hpp --------- Co-authored-by: praydog <praydog@praydog.com>
1 parent 8b2fc9f commit 9074c01

9 files changed

Lines changed: 298 additions & 102 deletions

File tree

src/mods/VR.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2533,6 +2533,15 @@ void VR::on_draw_sidebar_entry(std::string_view name) {
25332533
m_compatibility_skip_pip->draw("Skip PostInitProperties");
25342534
m_sceneview_compatibility_mode->draw("SceneView Compatibility Mode");
25352535
m_extreme_compat_mode->draw("Extreme Compatibility Mode");
2536+
2537+
// changes to any of these options should trigger a regeneration of the eye projection matrices
2538+
const auto horizontal_projection_changed = m_horizontal_projection_override->draw("Horizontal Projection");
2539+
const auto vertical_projection_changed = m_vertical_projection_override->draw("Vertical Projection");
2540+
const auto scale_render = m_grow_rectangle_for_projection_cropping->draw("Scale Render Target");
2541+
const auto scale_render_changed = get_runtime()->is_modifying_eye_texture_scale != scale_render;
2542+
get_runtime()->is_modifying_eye_texture_scale = scale_render;
2543+
get_runtime()->should_recalculate_eye_projections = horizontal_projection_changed || vertical_projection_changed || scale_render_changed;
2544+
25362545
ImGui::TreePop();
25372546
}
25382547

src/mods/VR.hpp

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@ class VR : public Mod {
5454
GESTURE_HEAD_RIGHT,
5555
};
5656

57+
enum HORIZONTAL_PROJECTION_OVERRIDE : int32_t {
58+
HORIZONTAL_DEFAULT,
59+
HORIZONTAL_SYMMETRIC,
60+
HORIZONTAL_MIRROR
61+
};
62+
63+
enum VERTICAL_PROJECTION_OVERRIDE : int32_t {
64+
VERTICAL_DEFAULT,
65+
VERTICAL_SYMMETRIC,
66+
VERTICAL_MATCHED
67+
};
68+
5769
static const inline std::string s_action_pose = "/actions/default/in/Pose";
5870
static const inline std::string s_action_grip_pose = "/actions/default/in/GripPose";
5971
static const inline std::string s_action_trigger = "/actions/default/in/Trigger";
@@ -102,6 +114,11 @@ class VR : public Mod {
102114
};
103115
}
104116

117+
// texture bounds to tell OpenVR which parts of the submitted texture to render (default - use the whole texture).
118+
// Will be modified to accommodate forced symmetrical eye projection
119+
vr::VRTextureBounds_t m_right_bounds{0.0f, 0.0f, 1.0f, 1.0f};
120+
vr::VRTextureBounds_t m_left_bounds{0.0f, 0.0f, 1.0f, 1.0f};
121+
105122
void on_config_load(const utility::Config& cfg, bool set_defaults) override;
106123
void on_config_save(utility::Config& cfg) override;
107124

@@ -577,6 +594,18 @@ class VR : public Mod {
577594
return m_extreme_compat_mode->value();
578595
}
579596

597+
auto get_horizontal_projection_override() const {
598+
return m_horizontal_projection_override->value();
599+
}
600+
601+
auto get_vertical_projection_override() const {
602+
return m_vertical_projection_override->value();
603+
}
604+
605+
bool should_grow_rectangle_for_projection_cropping() const {
606+
return m_grow_rectangle_for_projection_cropping->value();
607+
}
608+
580609
vrmod::D3D11Component& d3d11() {
581610
return m_d3d11;
582611
}
@@ -671,9 +700,6 @@ class VR : public Mod {
671700
std::vector<int32_t> m_controllers{};
672701
std::unordered_set<int32_t> m_controllers_set{};
673702

674-
vr::VRTextureBounds_t m_right_bounds{ 0.0f, 0.0f, 1.0f, 1.0f };
675-
vr::VRTextureBounds_t m_left_bounds{ 0.0f, 0.0f, 1.0f, 1.0f };
676-
677703
glm::vec3 m_overlay_rotation{-1.550f, 0.0f, -1.330f};
678704
glm::vec4 m_overlay_position{0.0f, 0.06f, -0.07f, 1.0f};
679705

@@ -797,6 +823,18 @@ class VR : public Mod {
797823
"Gesture (Head) + Right Joystick",
798824
};
799825

826+
static const inline std::vector<std::string> s_horizontal_projection_override_names{
827+
"Raw / default",
828+
"Symmetrical",
829+
"Mirrored",
830+
};
831+
832+
static const inline std::vector<std::string> s_vertical_projection_override_names{
833+
"Raw / default",
834+
"Symmetrical",
835+
"Matched",
836+
};
837+
800838
const ModCombo::Ptr m_rendering_method{ ModCombo::create(generate_name("RenderingMethod"), s_rendering_method_names) };
801839
const ModCombo::Ptr m_synced_afr_method{ ModCombo::create(generate_name("SyncedSequentialMethod"), s_synced_afr_method_names, 1) };
802840
const ModToggle::Ptr m_extreme_compat_mode{ ModToggle::create(generate_name("ExtremeCompatibilityMode"), false, true) };
@@ -814,6 +852,9 @@ class VR : public Mod {
814852
const ModToggle::Ptr m_2d_screen_mode{ ModToggle::create(generate_name("2DScreenMode"), false) };
815853
const ModToggle::Ptr m_roomscale_movement{ ModToggle::create(generate_name("RoomscaleMovement"), false) };
816854
const ModToggle::Ptr m_swap_controllers{ ModToggle::create(generate_name("SwapControllerInputs"), false) };
855+
const ModCombo::Ptr m_horizontal_projection_override{ModCombo::create(generate_name("HorizontalProjectionOverride"), s_horizontal_projection_override_names)};
856+
const ModCombo::Ptr m_vertical_projection_override{ModCombo::create(generate_name("VerticalProjectionOverride"), s_vertical_projection_override_names)};
857+
const ModToggle::Ptr m_grow_rectangle_for_projection_cropping{ModToggle::create(generate_name("GrowRectangleForProjectionCropping"), false)};
817858

818859
// Snap turn settings and globals
819860
void gamepad_snapturn(XINPUT_STATE& state);
@@ -952,6 +993,9 @@ class VR : public Mod {
952993
*m_2d_screen_mode,
953994
*m_roomscale_movement,
954995
*m_swap_controllers,
996+
*m_horizontal_projection_override,
997+
*m_vertical_projection_override,
998+
*m_grow_rectangle_for_projection_cropping,
955999
*m_snapturn,
9561000
*m_snapturn_joystick_deadzone,
9571001
*m_snapturn_angle,
@@ -1134,4 +1178,4 @@ class VR : public Mod {
11341178
friend class vrmod::D3D12Component;
11351179
friend class vrmod::OverlayComponent;
11361180
friend class FFakeStereoRenderingHook;
1137-
};
1181+
};

src/mods/vr/D3D11Component.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -559,8 +559,9 @@ vr::EVRCompositorError D3D11Component::on_frame(VR* vr) {
559559
(void*)m_left_eye_tex.Get(), vr::TextureType_DirectX, vr::ColorSpace_Auto,
560560
submit_pose
561561
};
562-
563-
const auto e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &vr->m_left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose);
562+
const auto left_bounds = vr::VRTextureBounds_t{runtime->view_bounds[0][0], runtime->view_bounds[0][2],
563+
runtime->view_bounds[0][1], runtime->view_bounds[0][3]};
564+
const auto e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose);
564565

565566
if (e != vr::VRCompositorError_None) {
566567
spdlog::error("[VR] VRCompositor failed to submit left eye: {}", (int)e);
@@ -710,8 +711,9 @@ vr::EVRCompositorError D3D11Component::on_frame(VR* vr) {
710711
(void*)m_left_eye_tex.Get(), vr::TextureType_DirectX, vr::ColorSpace_Auto,
711712
submit_pose
712713
};
713-
714-
e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &vr->m_left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose);
714+
const auto left_bounds = vr::VRTextureBounds_t{runtime->view_bounds[0][0], runtime->view_bounds[0][2],
715+
runtime->view_bounds[0][1], runtime->view_bounds[0][3]};
716+
e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose);
715717

716718
if (e != vr::VRCompositorError_None) {
717719
spdlog::error("[VR] VRCompositor failed to submit left eye: {}", (int)e);
@@ -760,8 +762,9 @@ vr::EVRCompositorError D3D11Component::on_frame(VR* vr) {
760762
(void*)m_right_eye_tex.Get(), vr::TextureType_DirectX, vr::ColorSpace_Auto,
761763
submit_pose
762764
};
763-
764-
e = vr::VRCompositor()->Submit(vr::Eye_Right, &right_eye, &vr->m_right_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose);
765+
const auto right_bounds = vr::VRTextureBounds_t{runtime->view_bounds[1][0], runtime->view_bounds[1][2],
766+
runtime->view_bounds[1][1], runtime->view_bounds[1][3]};
767+
e = vr::VRCompositor()->Submit(vr::Eye_Right, &right_eye, &right_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose);
765768
runtime->frame_synced = false;
766769

767770
bool submitted = true;

src/mods/vr/D3D12Component.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -398,8 +398,9 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) {
398398
(void*)&left, vr::TextureType_DirectX12, vr::ColorSpace_Auto,
399399
submit_pose
400400
};
401-
402-
auto e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &vr->m_left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose);
401+
const auto left_bounds = vr::VRTextureBounds_t{runtime->view_bounds[0][0], runtime->view_bounds[0][2],
402+
runtime->view_bounds[0][1], runtime->view_bounds[0][3]};
403+
auto e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose);
403404

404405
if (e != vr::VRCompositorError_None) {
405406
spdlog::error("[VR] VRCompositor failed to submit left eye: {}", (int)e);
@@ -496,8 +497,9 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) {
496497
(void*)&left, vr::TextureType_DirectX12, vr::ColorSpace_Auto,
497498
submit_pose
498499
};
499-
500-
auto e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &vr->m_left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose);
500+
const auto left_bounds = vr::VRTextureBounds_t{runtime->view_bounds[0][0], runtime->view_bounds[0][2],
501+
runtime->view_bounds[0][1], runtime->view_bounds[0][3]};
502+
auto e = vr::VRCompositor()->Submit(vr::Eye_Left, &left_eye, &left_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose);
501503

502504
if (e != vr::VRCompositorError_None) {
503505
spdlog::error("[VR] VRCompositor failed to submit left eye: {}", (int)e);
@@ -521,8 +523,9 @@ vr::EVRCompositorError D3D12Component::on_frame(VR* vr) {
521523
(void*)&right, vr::TextureType_DirectX12, vr::ColorSpace_Auto,
522524
submit_pose
523525
};
524-
525-
auto e = vr::VRCompositor()->Submit(vr::Eye_Right, &right_eye, &vr->m_right_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose);
526+
const auto right_bounds = vr::VRTextureBounds_t{runtime->view_bounds[1][0], runtime->view_bounds[1][2],
527+
runtime->view_bounds[1][1], runtime->view_bounds[1][3]};
528+
auto e = vr::VRCompositor()->Submit(vr::Eye_Right, &right_eye, &right_bounds, vr::EVRSubmitFlags::Submit_TextureWithPose);
526529
runtime->frame_synced = false;
527530

528531
if (e != vr::VRCompositorError_None) {

src/mods/vr/OverlayComponent.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,8 @@ void OverlayComponent::update_slate_openvr() {
327327

328328
const auto is_d3d11 = g_framework->get_renderer_type() == Framework::RendererType::D3D11;
329329

330+
// TODO: do the sizing / scaling calculations below need to take into account non-standard VRTextureBounds_t
331+
// when we force a symmetrical eye projection matrix?
330332
vr::VRTextureBounds_t bounds{};
331333
bounds.uMin = 0.0f;
332334
bounds.uMax = 1.0f;
@@ -424,6 +426,8 @@ bool OverlayComponent::update_wrist_overlay_openvr() {
424426
// so it doesn't become too intrusive during gameplay
425427
const auto scale = m_closed_ui ? 0.25f : 1.0f;
426428

429+
// TODO: do the sizing / scaling calculations below need to take into account non-standard VRTextureBounds_t
430+
// when we force a symmetrical eye projection matrix?
427431
vr::VRTextureBounds_t bounds{};
428432
bounds.uMin = last_window_pos.x / render_target_width ;
429433
bounds.uMax = (last_window_pos.x + last_window_size.x) / render_target_width;
@@ -667,6 +671,8 @@ void OverlayComponent::update_overlay_openvr() {
667671
vr::VROverlay()->ShowOverlay(m_overlay_handle);
668672

669673
// Show the entire texture
674+
// TODO: do the sizing / scaling calculations below need to take into account non-standard VRTextureBounds_t
675+
// when we force a symmetrical eye projection matrix?
670676
vr::VRTextureBounds_t bounds{};
671677
bounds.uMin = 0.0f;
672678
bounds.uMax = 1.0f;

0 commit comments

Comments
 (0)