forked from EXT/VR180-Web-Player
Fix stereo rendering glitches on Meta Quest browsers
Replace camera reference comparison with view matrix eye detection for more reliable left/right eye identification. Recent Quest Browser updates (Chromium 138/140, Horizon OS v83) changed WebXR multiview behavior, causing the previous xrCamera.cameras[0]/[1] comparison to fail intermittently on the left eye. The new approach uses activeCamera.matrixWorldInverse.elements[12] (the X translation in the view matrix) which reliably indicates: - Negative value = left eye - Positive value = right eye This method is consistent across both Quest Browser and Safari/VisionOS. Also adds explicit video texture synchronization in the render loop to prevent timing-related glitches. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -411,7 +411,7 @@ function init() {
|
||||
vr180Mesh.onBeforeRender = function (renderer, scene, activeCamera, geometry, material, group) {
|
||||
if (!material.map) return;
|
||||
const isPresentingXR = renderer.xr.isPresenting;
|
||||
|
||||
|
||||
// Handle 2D mode - show only left eye view
|
||||
if (is2DMode && !isPresentingXR) {
|
||||
material.map.offset.x = 0;
|
||||
@@ -420,7 +420,7 @@ function init() {
|
||||
material.map.repeat.y = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Default to full texture for non-VR, non-2D mode
|
||||
material.map.offset.x = 0; material.map.repeat.x = 1;
|
||||
material.map.offset.y = 0; material.map.repeat.y = 1;
|
||||
@@ -428,25 +428,20 @@ function init() {
|
||||
return;
|
||||
}
|
||||
|
||||
const xrCamera = renderer.xr.getCamera();
|
||||
// Use view matrix eye offset for reliable stereo detection
|
||||
// This works consistently across Quest Browser updates and Safari/VisionOS
|
||||
// Left eye has negative X offset, right eye has positive X offset
|
||||
const viewMatrix = activeCamera.matrixWorldInverse;
|
||||
const eyeOffsetX = viewMatrix.elements[12];
|
||||
|
||||
if (xrCamera && xrCamera.cameras && xrCamera.cameras.length >= 2) {
|
||||
if (activeCamera === xrCamera.cameras[0]) {
|
||||
material.map.offset.x = 0;
|
||||
} else if (activeCamera === xrCamera.cameras[1]) {
|
||||
material.map.offset.x = 0.5;
|
||||
} else {
|
||||
material.map.offset.x = 0;
|
||||
}
|
||||
material.map.repeat.x = 0.5;
|
||||
if (eyeOffsetX < 0) {
|
||||
// Left eye - show left half of SBS video
|
||||
material.map.offset.x = 0;
|
||||
} else {
|
||||
const projMatrixEl8 = activeCamera.projectionMatrix.elements[8];
|
||||
if (projMatrixEl8 < -0.0001) {
|
||||
material.map.offset.x = 0; material.map.repeat.x = 0.5;
|
||||
} else if (projMatrixEl8 > 0.0001) {
|
||||
material.map.offset.x = 0.5; material.map.repeat.x = 0.5;
|
||||
}
|
||||
// Right eye - show right half of SBS video
|
||||
material.map.offset.x = 0.5;
|
||||
}
|
||||
material.map.repeat.x = 0.5;
|
||||
};
|
||||
|
||||
// Initialize 2D camera
|
||||
@@ -1731,6 +1726,12 @@ function renderXR(timestamp, frame) {
|
||||
}
|
||||
}
|
||||
try {
|
||||
// Ensure video texture is synchronized with render loop
|
||||
// This prevents glitches from texture update timing issues on Quest browsers
|
||||
if (videoTexture && video && !video.paused && !video.ended) {
|
||||
videoTexture.needsUpdate = true;
|
||||
}
|
||||
|
||||
handleControllerInteractions();
|
||||
renderer.render(scene, camera);
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user