https://github.com/EpicGames/UnrealEngine/pull/14830
OpenXR: Fix SPS mono culling frustum incorrectly culling edge objects with toe-out views
The eSSE_MONOSCOPIC branch in GetStereoProjectionMatrix() built the unified
culling frustum by directly min/max-ing each eye’s XrFovf angles. Those angles
are expressed in eye-local space, so on HMDs with toe-out (left/right eyes
rotated outward) the merged frustum was narrower than the actual combined
visible area. Objects near the view edge that were visible to at least one eye
were incorrectly culled before reaching the rasterizer.
Root cause
----------
XrFovf.angleLeft/Right/Up/Down are offsets relative to each eye’s own forward
axis. When the two eye orientations differ (toe-out), simply taking min/max of
the raw angles ignores the per-eye rotation and produces a frustum that does
not enclose all visible directions in head/reference space.
Fix
---
Instead of merging raw angles, project each eye’s four frustum-corner rays
(tan-angle direction vectors, one per FOV boundary) into head/reference space
using the eye’s pose.orientation, then compute the encompassing FOV from those
rotated directions:
1. Construct four corner direction vectors in eye-local XR space:
(tan(angleLeft/Right), tan(angleUp/Down), -1)
2. Convert orientation via ToFQuat() and rotate each corner with
FQuat::RotateVector() (reuses the existing OpenXRCore.h isometry).
3. Map the rotated UE-space vector back to XR space.
4. Back-project onto the Z=-1 plane to recover head-space tan-angles.
5. min/max across all corners and both eyes to get the final FOV.
When eyes are parallel (identity orientation) the new path is mathematically
identical to the old min/max and produces bit-identical results.
Verified on PICO device with OpenXR:
- Eye orientations showed non-zero y component (confirmed toe-out present).
- Raw per-eye FOV: Left=-47.50 Right=47.50 Up=43.00 Down=-43.00 (degrees).
- Merged head-space FOV after fix: Left=-54.62 Right=54.62 Up=41.98 Down=-49.98.
- Edge-object culling artefacts no longer reproducible.
[Attachment Removed]