@threlte/xr
Version:
Tools to more easily create VR and AR experiences with Threlte
70 lines (69 loc) • 3.05 kB
JavaScript
import { XRControllerModelFactory } from 'three/examples/jsm/webxr/XRControllerModelFactory.js';
import { useThrelte } from '@threlte/core';
import { onMount } from 'svelte';
import { useHandTrackingState } from './useHandTrackingState';
import { gaze, left, right } from '../hooks/useController';
import { controllerEvents } from './stores';
export const setupControllers = () => {
const factory = new XRControllerModelFactory();
const stores = { left, right, none: gaze };
const { xr } = useThrelte().renderer;
const hasHands = useHandTrackingState();
const controllers = [xr.getController(0), xr.getController(1)];
const indexMap = new Map();
controllers.forEach((targetRay, index) => {
indexMap.set(targetRay, {
targetRay,
grip: xr.getControllerGrip(index),
model: factory.createControllerModel(targetRay)
});
});
onMount(() => {
const dispatch = (event) => {
if (hasHands())
return;
const { data } = event;
controllerEvents[data.handedness]?.current?.[`on${event.type}`]?.(event);
};
function handleConnected(event) {
const { model, targetRay, grip } = indexMap.get(this);
const { data: inputSource } = event;
stores[event.data.handedness].set({
inputSource,
targetRay,
grip,
model
});
dispatch(event);
}
const handleDisconnected = (event) => {
dispatch(event);
stores[event.data.handedness].set(undefined);
};
for (const targetRay of controllers) {
targetRay.addEventListener('connected', handleConnected);
targetRay.addEventListener('disconnected', handleDisconnected);
targetRay.addEventListener('select', dispatch);
targetRay.addEventListener('selectstart', dispatch);
targetRay.addEventListener('selectend', dispatch);
targetRay.addEventListener('squeeze', dispatch);
targetRay.addEventListener('squeezestart', dispatch);
targetRay.addEventListener('squeezeend', dispatch);
}
return () => {
for (const targetRay of controllers) {
targetRay.removeEventListener('connected', handleConnected);
targetRay.removeEventListener('disconnected', handleDisconnected);
targetRay.removeEventListener('select', dispatch);
targetRay.removeEventListener('selectstart', dispatch);
targetRay.removeEventListener('selectend', dispatch);
targetRay.removeEventListener('squeeze', dispatch);
targetRay.removeEventListener('squeezestart', dispatch);
targetRay.removeEventListener('squeezeend', dispatch);
}
stores.left.set(undefined);
stores.right.set(undefined);
stores.none.set(undefined);
};
});
};