forked from EXT/VR180-Web-Player
Compare commits
11 Commits
fix/quest-
...
v1.0.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d52a722ce7 | ||
|
|
40e3711925 | ||
|
|
c41ad12b32 | ||
|
|
dbe6e5b1d9 | ||
|
|
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
|
||||
@@ -4,10 +4,9 @@ A web-based video player for 180 degree, 3D video.
|
||||
Got an immersive video you want people to see with the Apple Vision Pro or Meta Quest headsets? Now you can put it on your website just like any other video! People will see the immersive 3D video if they have a capable headset or they'll get a 2D version on other devices.
|
||||
|
||||
## How to use it
|
||||
1. Drop the `vr180player` directory in the root level of your website.
|
||||
2. Link to the player CSS file `<link rel="stylesheet" href="vr180player/vr180-player.css">`.
|
||||
3. Add the player script `<script type="module" src="vr180player/vr180-player.js"></script>` before the closing body tag.
|
||||
4. And use this HTML snippet to embed your video:
|
||||
1. Link to the player CSS file `<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Verdi/VR180-Web-Player@v1.0.1/vr180player/vr180-player.css">`.
|
||||
2. Add the player script `<script type="module" src="https://cdn.jsdelivr.net/gh/Verdi/VR180-Web-Player@v1.0.1/vr180player/vr180-player.js"></script>` before the closing body tag.
|
||||
3. And use this HTML snippet to embed your video:
|
||||
```
|
||||
<div id="vr-container">
|
||||
<video id="vr180" poster="poster.jpg" title="Demo Video" crossOrigin="anonymous" playsinline>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<title>VR180 Web Player</title>
|
||||
<link rel="stylesheet" href="vr180player/vr180-player.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Verdi/VR180-Web-Player@v1.0.1/vr180player/vr180-player.css">
|
||||
<style>
|
||||
body {
|
||||
font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
@@ -28,6 +28,6 @@
|
||||
<!-- UI elements will be dynamically inserted here by JavaScript -->
|
||||
</div>
|
||||
</main>
|
||||
<script type="module" src="vr180player/vr180-player.js"></script>
|
||||
<script type="module" src="https://cdn.jsdelivr.net/gh/Verdi/VR180-Web-Player@v1.0.1/vr180player/vr180-player.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as THREE from 'https://unpkg.com/three/build/three.module.js';
|
||||
const _playerBase = new URL('.', import.meta.url).href;
|
||||
|
||||
let scene, camera, renderer, video, videoTexture, sphereMaterial;
|
||||
let vr180Mesh;
|
||||
@@ -111,7 +112,7 @@ function createPlayButton() {
|
||||
playButton.setAttribute('aria-label', 'Play video');
|
||||
|
||||
const playImg = document.createElement('img');
|
||||
playImg.src = 'vr180player/images/play.png';
|
||||
playImg.src = _playerBase + 'images/play.png';
|
||||
playImg.alt = 'Play';
|
||||
|
||||
playButton.appendChild(playImg);
|
||||
@@ -428,19 +429,41 @@ function init() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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];
|
||||
const xrCamera = renderer.xr.getCamera();
|
||||
let isLeftEye = true; // Default to left eye
|
||||
|
||||
if (eyeOffsetX < 0) {
|
||||
// Left eye - show left half of SBS video
|
||||
material.map.offset.x = 0;
|
||||
if (xrCamera && xrCamera.cameras && xrCamera.cameras.length >= 2) {
|
||||
// Method 1: Direct camera reference comparison
|
||||
if (activeCamera === xrCamera.cameras[0]) {
|
||||
isLeftEye = true;
|
||||
} else if (activeCamera === xrCamera.cameras[1]) {
|
||||
isLeftEye = false;
|
||||
} else {
|
||||
// Right eye - show right half of SBS video
|
||||
material.map.offset.x = 0.5;
|
||||
// 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 {
|
||||
// Fallback when xrCamera.cameras is not available
|
||||
const projMatrixEl8 = activeCamera.projectionMatrix.elements[8];
|
||||
isLeftEye = projMatrixEl8 <= 0;
|
||||
}
|
||||
|
||||
material.map.offset.x = isLeftEye ? 0 : 0.5;
|
||||
material.map.repeat.x = 0.5;
|
||||
};
|
||||
|
||||
@@ -1726,12 +1749,10 @@ function renderXR(timestamp, frame) {
|
||||
}
|
||||
}
|
||||
try {
|
||||
// Ensure video texture is synchronized with render loop
|
||||
// This prevents glitches from texture update timing issues on Quest browsers
|
||||
// Sync video texture before render to ensure frame consistency
|
||||
if (videoTexture && video && !video.paused && !video.ended) {
|
||||
videoTexture.needsUpdate = true;
|
||||
}
|
||||
|
||||
handleControllerInteractions();
|
||||
renderer.render(scene, camera);
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user