diff --git a/prismarine-viewer/viewer/lib/viewer.ts b/prismarine-viewer/viewer/lib/viewer.ts index 3ff8e6ca..fcb64627 100644 --- a/prismarine-viewer/viewer/lib/viewer.ts +++ b/prismarine-viewer/viewer/lib/viewer.ts @@ -20,6 +20,7 @@ export class Viewer { playerHeight: number isSneaking: boolean version: string + cameraObjectOverride?: THREE.Object3D // for xr constructor (public renderer: THREE.WebGLRenderer, numWorkers?: number) { this.scene = new THREE.Scene() @@ -81,12 +82,13 @@ export class Viewer { } setFirstPersonCamera (pos: Vec3 | null, yaw: number, pitch: number, roll = 0) { + const cam = this.cameraObjectOverride || this.camera if (pos) { let y = pos.y + this.playerHeight if (this.isSneaking) y -= 0.3 - new tweenJs.Tween(this.camera.position).to({ x: pos.x, y, z: pos.z }, 50).start() + new tweenJs.Tween(cam.position).to({ x: pos.x, y, z: pos.z }, 50).start() } - this.camera.rotation.set(pitch, yaw, roll, 'ZYX') + cam.rotation.set(pitch, yaw, roll, 'ZYX') } // todo type diff --git a/src/index.ts b/src/index.ts index a22800d3..a59fbc10 100644 --- a/src/index.ts +++ b/src/index.ts @@ -129,7 +129,7 @@ let previousWindowHeight = window.innerHeight const renderFrame = (time: DOMHighResTimeStamp) => { if (window.stopLoop) return window.requestAnimationFrame(renderFrame) - if (window.stopRender) return + if (window.stopRender || renderer.xr.isPresenting) return if (renderInterval) { delta += time - lastTime lastTime = time @@ -540,7 +540,7 @@ async function connect (connectOptions: { window.debugMenu = debugMenu - void initVR(bot, renderer, viewer) + void initVR() postRenderFrameFn = () => { viewer.setFirstPersonCamera(null, bot.entity.yaw, bot.entity.pitch) diff --git a/src/styles.css b/src/styles.css index a4034529..d19a6ada 100644 --- a/src/styles.css +++ b/src/styles.css @@ -64,6 +64,12 @@ body { text-shadow: 1px 1px #222; } +#VRButton { + background: rgba(0, 0, 0, 0.3) !important; + opacity: 0.7 !important; + position: fixed !important; +} + .dirt-bg { position: absolute; top: 0; diff --git a/src/vr.js b/src/vr.js index 72d23cb1..7e11cb71 100644 --- a/src/vr.js +++ b/src/vr.js @@ -1,13 +1,11 @@ -/* global THREE */ - const { VRButton } = require('three/examples/jsm/webxr/VRButton.js') const { GLTFLoader } = require('three/examples/jsm/loaders/GLTFLoader.js') const { XRControllerModelFactory } = require('three/examples/jsm/webxr/XRControllerModelFactory.js') -const TWEEN = require('@tweenjs/tween.js') -async function initVR (bot, renderer, viewer) { +async function initVR () { + const { renderer } = viewer if (!('xr' in navigator)) return - const isSupported = await navigator.xr.isSessionSupported('immersive-vr') + const isSupported = await navigator.xr.isSessionSupported('immersive-vr') && !!XRSession.prototype.updateRenderState // e.g. android webview doesn't support updateRenderState if (!isSupported) return // VR @@ -34,14 +32,10 @@ async function initVR (bot, renderer, viewer) { }) controller2.add(hand2) - viewer.setFirstPersonCamera = function (pos, yaw, pitch) { - if (pos) new TWEEN.Tween(user.position).to({ x: pos.x, y: pos.y, z: pos.z }, 50).start() - user.rotation.set(pitch, yaw, 0, 'ZYX') - } - let rotSnapReset = true let yawOffset = 0 renderer.setAnimationLoop(() => { + if (!renderer.xr.isPresenting) return if (hand1.xrInputSource && hand2.xrInputSource) { hand1.xAxis = hand1.xrInputSource.gamepad.axes[2] hand1.yAxis = hand1.xrInputSource.gamepad.axes[3] @@ -76,9 +70,14 @@ async function initVR (bot, renderer, viewer) { bot.setControlState('right', hand2.xAxis < -0.5) bot.setControlState('left', hand2.xAxis > 0.5) - TWEEN.update() viewer.update() - renderer.render(viewer.scene, viewer.camera) + viewer.render() + }) + renderer.xr.addEventListener('sessionstart', () => { + viewer.cameraObjectOverride = user + }) + renderer.xr.addEventListener('sessionend', () => { + viewer.cameraObjectOverride = undefined }) }