@threlte/xr
Version:
Tools to more easily create VR and AR experiences with Threlte
64 lines (63 loc) • 2.56 kB
JavaScript
import { XRHandModelFactory } from 'three/examples/jsm/webxr/XRHandModelFactory.js';
import { useThrelte } from '@threlte/core';
import { onMount } from 'svelte';
import { left, right } from '../hooks/useHand';
import { useHandTrackingState } from './useHandTrackingState';
import { handEvents } from './stores';
export const setupHands = () => {
const factory = new XRHandModelFactory();
const stores = { left, right };
const { xr } = useThrelte().renderer;
const hasHands = useHandTrackingState();
const handSpaces = [xr.getHand(0), xr.getHand(1)];
const map = new Map();
handSpaces.forEach((handSpace, index) => {
map.set(handSpace, {
hand: handSpace,
targetRay: xr.getController(index),
model: factory.createHandModel(handSpace, 'mesh')
});
});
onMount(() => {
const dispatch = (event) => {
if (!hasHands())
return;
const handEvent = event;
const handedness = 'handedness' in handEvent ? handEvent.handedness : handEvent.data.handedness;
handEvents[handedness]?.current?.[`on${event.type}`]?.(event);
};
function handleConnected(event) {
const hand = this;
const { model, targetRay } = map.get(this);
const { data } = event;
const { handedness, hand: inputSource } = data;
stores[handedness].set({
hand,
model,
inputSource,
targetRay
});
dispatch(event);
}
const handleDisconnected = (event) => {
dispatch(event);
stores[event.data.handedness].set(undefined);
};
for (const handSpace of handSpaces) {
handSpace.addEventListener('connected', handleConnected);
handSpace.addEventListener('disconnected', handleDisconnected);
handSpace.addEventListener('pinchstart', dispatch);
handSpace.addEventListener('pinchend', dispatch);
}
return () => {
for (const handSpace of handSpaces) {
handSpace.removeEventListener('connected', handleConnected);
handSpace.removeEventListener('disconnected', handleDisconnected);
handSpace.removeEventListener('pinchstart', dispatch);
handSpace.removeEventListener('pinchend', dispatch);
}
stores.left.set(undefined);
stores.right.set(undefined);
};
});
};