From 33f75e36c80f3bdc39c377712c31d29e46537ea1 Mon Sep 17 00:00:00 2001 From: adambenovic Date: Sat, 6 Jun 2026 19:44:46 +0200 Subject: [PATCH] Fix doubled stereo image on UE 5.5/5.6 (zero-based eye index misclassified as full pass) UE <= 5.4 called CalculateStereoViewOffset with view index -1 or 2 early, flipping the index_was_ever_two/negative flags so index 0 was treated as a real eye. UE 5.5/5.6 only ever sends indices 0/1, leaving view 0 permanently classified as a mono "full pass" - which skipped per-eye mod callbacks and HMD state updates for one eye only. Measured result on a UE 5.6.1 game (Satisfactory 1.2 experimental): eye separation of ~33.6 cm (incl. 15.7 cm vertical) instead of IPD, producing a heavily doubled image for near-field content. Fix: on UE5 (already detected via LWC double-precision math) index 0 in a stereo pass is always a real eye - a genuine mono pass arrives as INDEX_NONE (-1), which is already filtered above. Likely also addresses praydog/UEVR#329 (UE 5.5.3 games not entering VR correctly) and contributes to praydog/UEVR#368 (UE 5.6 support). Co-Authored-By: Claude Opus 4.8 --- src/mods/vr/FFakeStereoRenderingHook.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/mods/vr/FFakeStereoRenderingHook.cpp b/src/mods/vr/FFakeStereoRenderingHook.cpp index 12588b9b1..8bc22bf93 100644 --- a/src/mods/vr/FFakeStereoRenderingHook.cpp +++ b/src/mods/vr/FFakeStereoRenderingHook.cpp @@ -4652,7 +4652,12 @@ __forceinline void FFakeStereoRenderingHook::calculate_stereo_view_offset( index_starts_from_one = false; } - const auto is_full_pass = view_index == 0 && !index_was_ever_two && !index_was_ever_negative; + // On UE5 (detected via double-precision LWC math) eye indices are always 0/1 and a genuine + // mono/full pass arrives as INDEX_NONE (-1), which is already ignored above. UE <= 5.4 + // happened to send -1 (or 2) early enough to flip the flags below, but UE 5.5/5.6 only ever + // sends 0/1 - leaving view 0 permanently misclassified as a "full pass", which skips per-eye + // transforms/callbacks for one eye only and produces a heavily doubled image. + const auto is_full_pass = view_index == 0 && !index_was_ever_two && !index_was_ever_negative && !g_hook->m_has_double_precision; auto true_index = index_starts_from_one ? ((view_index + 1) % 2) : (view_index % 2); const auto has_double_precision = g_hook->m_has_double_precision;