[FIX] Fix WebXR stereo frustum culling#8393
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes a critical bug in WebXR stereo rendering where objects visible in the right eye were being incorrectly culled because only the left eye's frustum was used for culling decisions.
Changes:
- Added
Frustum.add()method to combine multiple frustums by keeping the most permissive plane for each boundary - Modified renderer to compute a combined frustum encompassing all XR views instead of using only one view's frustum
- Removed the per-view frustum update that was overwriting the frustum in the view loop
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/core/shape/frustum.js | Added add() method to merge frustums by selecting the outermost plane for each of the 6 boundaries |
| src/scene/renderer/renderer.js | Updated XR frustum culling to combine all view frustums, imported Frustum class, added tempFrustum variable, and removed incorrect per-view frustum update |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| * @param {Frustum} other - The other frustum to add. | ||
| * @returns {Frustum} Self for chaining. | ||
| */ | ||
| add(other) { |
There was a problem hiding this comment.
Such a simple solution, I did not think about.
Maksims
left a comment
There was a problem hiding this comment.
No more phantom disappearing objects in my right eye!
|
Tested on Quest 3 - works flawlessly. Way to test:
And test from this PR (https://engine-nihpvle3p-playcanvas.vercel.app/#/xr/xr-hands) works well - early culling is gone. |
* [FIX] Fix WebXR stereo frustum culling * Improve docs
Summary
Frustum.add()method to combine frustums by keeping the outermost plane for each boundaryDetails
The previous implementation used only the first view's (left eye) frustum for culling, causing objects visible in the right eye but outside the left eye's view to be incorrectly culled.
The fix computes a combined frustum that encompasses all XR views by selecting the plane with the largest distance for each of the 6 frustum boundaries (left, right, top, bottom, near, far).
Why this works for WebXR
This approach assumes frustums have parallel orientation (same plane normals). This is valid for WebXR stereo rendering because modern VR/AR headsets use parallel projection - both eyes look in the same direction with only a horizontal IPD offset, not toe-in convergence. With parallel views, frustum plane normals are identical and only distances differ, making plane merging by distance comparison correct.
Public API Addition
Fixes #5787
Closes #7411
Checklist