Skip to content

Commit

Permalink
OpenVR and OpenXR symmetric and other projection matrix options (#196)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
mrbelowski and praydog committed Mar 20, 2024
1 parent 8b2fc9f commit 9074c01
Show file tree
Hide file tree
Showing 9 changed files with 298 additions and 102 deletions.
9 changes: 9 additions & 0 deletions src/mods/VR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2533,6 +2533,15 @@ 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");

// 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();
}

Expand Down
52 changes: 48 additions & 4 deletions src/mods/VR.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,18 @@ class VR : public Mod {
GESTURE_HEAD_RIGHT,
};

enum HORIZONTAL_PROJECTION_OVERRIDE : int32_t {
HORIZONTAL_DEFAULT,
HORIZONTAL_SYMMETRIC,
HORIZONTAL_MIRROR
};

enum VERTICAL_PROJECTION_OVERRIDE : int32_t {
VERTICAL_DEFAULT,
VERTICAL_SYMMETRIC,
VERTICAL_MATCHED
};

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";
Expand Down Expand Up @@ -102,6 +114,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;

Expand Down Expand Up @@ -577,6 +594,18 @@ class VR : public Mod {
return m_extreme_compat_mode->value();
}

auto get_horizontal_projection_override() const {
return m_horizontal_projection_override->value();
}

auto get_vertical_projection_override() const {
return m_vertical_projection_override->value();
}

bool should_grow_rectangle_for_projection_cropping() const {
return m_grow_rectangle_for_projection_cropping->value();
}

vrmod::D3D11Component& d3d11() {
return m_d3d11;
}
Expand Down Expand Up @@ -671,9 +700,6 @@ class VR : public Mod {
std::vector<int32_t> m_controllers{};
std::unordered_set<int32_t> 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};

Expand Down Expand Up @@ -797,6 +823,18 @@ class VR : public Mod {
"Gesture (Head) + Right Joystick",
};

static const inline std::vector<std::string> s_horizontal_projection_override_names{
"Raw / default",
"Symmetrical",
"Mirrored",
};

static const inline std::vector<std::string> s_vertical_projection_override_names{
"Raw / default",
"Symmetrical",
"Matched",
};

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) };
Expand All @@ -814,6 +852,9 @@ 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 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);
Expand Down Expand Up @@ -952,6 +993,9 @@ class VR : public Mod {
*m_2d_screen_mode,
*m_roomscale_movement,
*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,
Expand Down Expand Up @@ -1134,4 +1178,4 @@ class VR : public Mod {
friend class vrmod::D3D12Component;
friend class vrmod::OverlayComponent;
friend class FFakeStereoRenderingHook;
};
};
15 changes: 9 additions & 6 deletions src/mods/vr/D3D11Component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
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) {
spdlog::error("[VR] VRCompositor failed to submit left eye: {}", (int)e);
Expand Down Expand Up @@ -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);
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) {
spdlog::error("[VR] VRCompositor failed to submit left eye: {}", (int)e);
Expand Down Expand Up @@ -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);
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;

bool submitted = true;
Expand Down
15 changes: 9 additions & 6 deletions src/mods/vr/D3D12Component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
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) {
spdlog::error("[VR] VRCompositor failed to submit left eye: {}", (int)e);
Expand Down Expand Up @@ -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);
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) {
spdlog::error("[VR] VRCompositor failed to submit left eye: {}", (int)e);
Expand All @@ -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);
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;

if (e != vr::VRCompositorError_None) {
Expand Down
6 changes: 6 additions & 0 deletions src/mods/vr/OverlayComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 9074c01

Please sign in to comment.