forked from EXT/VR180-Web-Player
Compare commits
7 Commits
fix/quest-
...
v1.0.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
626b7f451b | ||
|
|
a56e36eaf6 | ||
|
|
bebcb3d355 | ||
|
|
f4fb9cf6bb | ||
|
|
38200c82f2 | ||
|
|
715e762fc9 | ||
|
|
065e8310e3 |
4
.gitattributes
vendored
Normal file
4
.gitattributes
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
index.html export-ignore
|
||||||
|
README.md export-ignore
|
||||||
|
sbs-video.mp4 export-ignore
|
||||||
|
poster.jpg export-ignore
|
||||||
@@ -411,7 +411,7 @@ function init() {
|
|||||||
vr180Mesh.onBeforeRender = function (renderer, scene, activeCamera, geometry, material, group) {
|
vr180Mesh.onBeforeRender = function (renderer, scene, activeCamera, geometry, material, group) {
|
||||||
if (!material.map) return;
|
if (!material.map) return;
|
||||||
const isPresentingXR = renderer.xr.isPresenting;
|
const isPresentingXR = renderer.xr.isPresenting;
|
||||||
|
|
||||||
// Handle 2D mode - show only left eye view
|
// Handle 2D mode - show only left eye view
|
||||||
if (is2DMode && !isPresentingXR) {
|
if (is2DMode && !isPresentingXR) {
|
||||||
material.map.offset.x = 0;
|
material.map.offset.x = 0;
|
||||||
@@ -420,7 +420,7 @@ function init() {
|
|||||||
material.map.repeat.y = 1;
|
material.map.repeat.y = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default to full texture for non-VR, non-2D mode
|
// Default to full texture for non-VR, non-2D mode
|
||||||
material.map.offset.x = 0; material.map.repeat.x = 1;
|
material.map.offset.x = 0; material.map.repeat.x = 1;
|
||||||
material.map.offset.y = 0; material.map.repeat.y = 1;
|
material.map.offset.y = 0; material.map.repeat.y = 1;
|
||||||
@@ -428,19 +428,41 @@ function init() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use view matrix eye offset for reliable stereo detection
|
const xrCamera = renderer.xr.getCamera();
|
||||||
// This works consistently across Quest Browser updates and Safari/VisionOS
|
let isLeftEye = true; // Default to left eye
|
||||||
// Left eye has negative X offset, right eye has positive X offset
|
|
||||||
const viewMatrix = activeCamera.matrixWorldInverse;
|
|
||||||
const eyeOffsetX = viewMatrix.elements[12];
|
|
||||||
|
|
||||||
if (eyeOffsetX < 0) {
|
if (xrCamera && xrCamera.cameras && xrCamera.cameras.length >= 2) {
|
||||||
// Left eye - show left half of SBS video
|
// Method 1: Direct camera reference comparison
|
||||||
material.map.offset.x = 0;
|
if (activeCamera === xrCamera.cameras[0]) {
|
||||||
|
isLeftEye = true;
|
||||||
|
} else if (activeCamera === xrCamera.cameras[1]) {
|
||||||
|
isLeftEye = false;
|
||||||
|
} else {
|
||||||
|
// Method 2: View matrix position (matrixWorldInverse.elements[12] is the X translation)
|
||||||
|
const viewMatrixX = activeCamera.matrixWorldInverse.elements[12];
|
||||||
|
const leftCamX = xrCamera.cameras[0].matrixWorldInverse.elements[12];
|
||||||
|
const rightCamX = xrCamera.cameras[1].matrixWorldInverse.elements[12];
|
||||||
|
|
||||||
|
const diffToLeft = Math.abs(viewMatrixX - leftCamX);
|
||||||
|
const diffToRight = Math.abs(viewMatrixX - rightCamX);
|
||||||
|
|
||||||
|
if (diffToLeft < 0.001 || diffToLeft < diffToRight) {
|
||||||
|
isLeftEye = true;
|
||||||
|
} else if (diffToRight < 0.001) {
|
||||||
|
isLeftEye = false;
|
||||||
|
} else {
|
||||||
|
// Method 3: Projection matrix asymmetry (elements[8] indicates eye offset)
|
||||||
|
const projMatrixEl8 = activeCamera.projectionMatrix.elements[8];
|
||||||
|
isLeftEye = projMatrixEl8 <= 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Right eye - show right half of SBS video
|
// Fallback when xrCamera.cameras is not available
|
||||||
material.map.offset.x = 0.5;
|
const projMatrixEl8 = activeCamera.projectionMatrix.elements[8];
|
||||||
|
isLeftEye = projMatrixEl8 <= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
material.map.offset.x = isLeftEye ? 0 : 0.5;
|
||||||
material.map.repeat.x = 0.5;
|
material.map.repeat.x = 0.5;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1726,12 +1748,10 @@ function renderXR(timestamp, frame) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// Ensure video texture is synchronized with render loop
|
// Sync video texture before render to ensure frame consistency
|
||||||
// This prevents glitches from texture update timing issues on Quest browsers
|
|
||||||
if (videoTexture && video && !video.paused && !video.ended) {
|
if (videoTexture && video && !video.paused && !video.ended) {
|
||||||
videoTexture.needsUpdate = true;
|
videoTexture.needsUpdate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleControllerInteractions();
|
handleControllerInteractions();
|
||||||
renderer.render(scene, camera);
|
renderer.render(scene, camera);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user