fix: fix basic vr support & test dom overlay

sentry-ref: 5517390383, 5517390775
This commit is contained in:
Vitaly Turovsky 2024-06-22 20:15:12 +03:00
commit f8980836dc
5 changed files with 49 additions and 26 deletions

View file

@ -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"

View file

@ -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 {

15
pnpm-lock.yaml generated
View file

@ -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: {}

View file

@ -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%;

View file

@ -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))