From f8980836dc8e35df244cf4bb0baae6abff769f82 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 22 Jun 2024 20:15:12 +0300 Subject: [PATCH] fix: fix basic vr support & test dom overlay sentry-ref: 5517390383, 5517390775 --- package.json | 3 ++- patches/three@0.154.0.patch | 16 ++++++++++++++++ pnpm-lock.yaml | 15 +++++++++------ src/styles.css | 3 +++ src/{vr.js => vr.ts} | 38 ++++++++++++++++++------------------- 5 files changed, 49 insertions(+), 26 deletions(-) create mode 100644 patches/three@0.154.0.patch rename src/{vr.js => vr.ts} (81%) diff --git a/package.json b/package.json index 56e3cfdd..c0342260 100644 --- a/package.json +++ b/package.json @@ -168,7 +168,8 @@ "ignoreDependencies": [] }, "patchedDependencies": { - "minecraft-protocol@1.47.0": "patches/minecraft-protocol@1.47.0.patch" + "minecraft-protocol@1.47.0": "patches/minecraft-protocol@1.47.0.patch", + "three@0.154.0": "patches/three@0.154.0.patch" } }, "packageManager": "pnpm@9.0.4" diff --git a/patches/three@0.154.0.patch b/patches/three@0.154.0.patch new file mode 100644 index 00000000..e612415c --- /dev/null +++ b/patches/three@0.154.0.patch @@ -0,0 +1,16 @@ +diff --git a/examples/jsm/webxr/VRButton.js b/examples/jsm/webxr/VRButton.js +index 6856a21b17aa45d7922bbf776fd2d7e63c7a9b4e..0925b706f7629bd52f0bb5af469536af8f5fce2c 100644 +--- a/examples/jsm/webxr/VRButton.js ++++ b/examples/jsm/webxr/VRButton.js +@@ -62,7 +62,10 @@ class VRButton { + // ('local' is always available for immersive sessions and doesn't need to + // be requested separately.) + +- const sessionInit = { optionalFeatures: [ 'local-floor', 'bounded-floor', 'hand-tracking', 'layers' ] }; ++ const sessionInit = { ++ optionalFeatures: ['local-floor', 'bounded-floor', 'layers'], ++ domOverlay: { root: document.body }, ++ }; + navigator.xr.requestSession( 'immersive-vr', sessionInit ).then( onSessionStarted ); + + } else { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4edd6e2b..1f2b4809 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ patchedDependencies: minecraft-protocol@1.47.0: hash: 2uxevyasyasdavsxuehfavgkjq path: patches/minecraft-protocol@1.47.0.patch + three@0.154.0: + hash: sj7ocb4p23jym6bkfgueanti2e + path: patches/three@0.154.0.patch importers: @@ -341,7 +344,7 @@ importers: version: 3.0.0 three: specifier: 0.154.0 - version: 0.154.0 + version: 0.154.0(patch_hash=sj7ocb4p23jym6bkfgueanti2e) timers-browserify: specifier: ^2.0.12 version: 2.0.12 @@ -410,7 +413,7 @@ importers: version: 4.7.2 three-stdlib: specifier: ^2.26.11 - version: 2.28.5(three@0.154.0) + version: 2.28.5(three@0.154.0(patch_hash=sj7ocb4p23jym6bkfgueanti2e)) three.meshline: specifier: ^1.3.0 version: 1.4.0 @@ -17565,7 +17568,7 @@ snapshots: dependencies: '@types/three': 0.156.0 skinview-utils: 0.7.1 - three: 0.154.0 + three: 0.154.0(patch_hash=sj7ocb4p23jym6bkfgueanti2e) slash@3.0.0: {} @@ -18018,7 +18021,7 @@ snapshots: dependencies: any-promise: 1.3.0 - three-stdlib@2.28.5(three@0.154.0): + three-stdlib@2.28.5(three@0.154.0(patch_hash=sj7ocb4p23jym6bkfgueanti2e)): dependencies: '@types/draco3d': 1.4.7 '@types/offscreencanvas': 2019.7.2 @@ -18026,11 +18029,11 @@ snapshots: draco3d: 1.5.6 fflate: 0.6.10 potpack: 1.0.2 - three: 0.154.0 + three: 0.154.0(patch_hash=sj7ocb4p23jym6bkfgueanti2e) three.meshline@1.4.0: {} - three@0.154.0: {} + three@0.154.0(patch_hash=sj7ocb4p23jym6bkfgueanti2e): {} throttle-debounce@3.0.1: {} diff --git a/src/styles.css b/src/styles.css index 139996e9..9aea87a1 100644 --- a/src/styles.css +++ b/src/styles.css @@ -163,6 +163,9 @@ body { animation-timing-function: ease-in-out; animation-fill-mode: forwards; } +#viewer-canvas::xr-overlay { + display: none; +} .full-svg svg { width: 100%; diff --git a/src/vr.js b/src/vr.ts similarity index 81% rename from src/vr.js rename to src/vr.ts index 92f020f2..af1e885a 100644 --- a/src/vr.js +++ b/src/vr.ts @@ -1,13 +1,13 @@ -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 { buttonMap: standardButtonsMap } = require('contro-max/build/gamepad') -const { activeModalStack, hideModal } = require('./globalState') +import { VRButton } from 'three/examples/jsm/webxr/VRButton.js' +import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js' +import { XRControllerModelFactory } from 'three/examples/jsm/webxr/XRControllerModelFactory.js' +import { buttonMap as standardButtonsMap } from 'contro-max/build/gamepad' +import { activeModalStack, hideModal } from './globalState' -async function initVR() { +export async function initVR () { const { renderer } = viewer if (!('xr' in navigator)) return - const isSupported = await navigator.xr.isSessionSupported('immersive-vr') && !!XRSession.prototype.updateRenderState // e.g. android webview doesn't support updateRenderState + const isSupported = await navigator.xr?.isSessionSupported('immersive-vr') && !!XRSession.prototype.updateRenderState // e.g. android webview doesn't support updateRenderState if (!isSupported) return // VR @@ -25,22 +25,23 @@ async function initVR() { // todo the logic written here can be hard to understand as it was designed to work in gamepad api emulation mode, will be refactored once there is a contro-max rewrite is done const virtualGamepadIndex = 4 let connectedVirtualGamepad + //@ts-expect-error const manageXrInputSource = ({ gamepad, handedness = defaultHandedness }, defaultHandedness, removeAction = false) => { if (handedness === 'right') { - const event = new Event(removeAction ? 'gamepaddisconnected' : 'gamepadconnected') // todo need to expose and use external gamepads api in contro-max instead + const event: any = new Event(removeAction ? 'gamepaddisconnected' : 'gamepadconnected') // todo need to expose and use external gamepads api in contro-max instead event.gamepad = removeAction ? connectedVirtualGamepad : { ...gamepad, mapping: 'standard', index: virtualGamepadIndex } connectedVirtualGamepad = event.gamepad window.dispatchEvent(event) } } - let hand1 = controllerModelFactory.createControllerModel(controller1) + let hand1: any = controllerModelFactory.createControllerModel(controller1) controller1.addEventListener('connected', (event) => { hand1.xrInputSource = event.data manageXrInputSource(event.data, 'left') user.add(controller1) }) controller1.add(hand1) - let hand2 = controllerModelFactory.createControllerModel(controller2) + let hand2: any = controllerModelFactory.createControllerModel(controller2) controller2.addEventListener('connected', (event) => { hand2.xrInputSource = event.data manageXrInputSource(event.data, 'right') @@ -50,15 +51,17 @@ async function initVR() { controller1.addEventListener('disconnected', () => { // don't handle removal of gamepads for now as is don't affect contro-max - hand1.xrInputSource = undefined manageXrInputSource(hand1.xrInputSource, 'left', true) + hand1.xrInputSource = undefined }) controller2.addEventListener('disconnected', () => { - hand2.xrInputSource = undefined manageXrInputSource(hand1.xrInputSource, 'right', true) + hand2.xrInputSource = undefined }) const originalGetGamepads = navigator.getGamepads.bind(navigator) + // is it okay to patch this? + //@ts-expect-error navigator.getGamepads = () => { const originalGamepads = originalGetGamepads() if (!hand1.xrInputSource || !hand2.xrInputSource) return originalGamepads @@ -105,15 +108,14 @@ async function initVR() { viewer.setFirstPersonCamera(null, bot.entity.yaw, bot.entity.pitch) // todo restore this logic (need to preserve ability to move camera) - // const xrCamera = renderer.xr.getCamera(viewer.camera) - // const d = xrCamera.getWorldDirection() // todo target + // const xrCamera = renderer.xr.getCamera() + // const d = xrCamera.getWorldDirection(new THREE.Vector3()) // bot.entity.yaw = Math.atan2(-d.x, -d.z) // bot.entity.pitch = Math.asin(d.y) // todo ? // bot.physics.stepHeight = 1 - viewer.update() viewer.render() }) renderer.xr.addEventListener('sessionstart', () => { @@ -128,8 +130,6 @@ async function initVR() { }) } -module.exports.initVR = initVR - const xrStandardRightButtonsMap = [ [0 /* trigger */, 'Right Trigger'], [1 /* squeeze */, 'Right Bumper'], @@ -146,9 +146,9 @@ const xrStandardLeftButtonsMap = [ [4 /* A */, 'X'], [5 /* B */, 'Y'], ] -const remapButtons = (rightButtons, leftButtons) => { +const remapButtons = (rightButtons: any[], leftButtons: any[]) => { // return remapped buttons - const remapped = [] + const remapped = [] as string[] const remapWithMap = (buttons, map) => { for (const [index, standardName] of map) { const standardMappingIndex = standardButtonsMap.findIndex((aliases) => aliases.find(alias => standardName === alias))