@react-three/xr
Version:
VR/AR for react-three-fiber
83 lines (82 loc) • 3.42 kB
JavaScript
import { jsx as _jsx } from "react/jsx-runtime";
import { createXRHitTestSource, requestXRHitTest } from '@pmndrs/xr';
import { useFrame } from '@react-three/fiber';
import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';
import { useStore } from 'zustand';
import { useXRStore } from './xr.js';
export { createXRHitTestSource, requestXRHitTest } from '@pmndrs/xr';
/**
* Hook for creating a hit test source originating from the provided object or xrspace
*/
export function useXRHitTestSource(relativeTo, trackableType) {
const [source, setState] = useState();
// eslint-disable-next-line react-hooks/rules-of-hooks
useCreateXRHitTestSource(relativeTo, trackableType, setState);
return source;
}
/**
* Hook for setting up a continous hit test originating from the provided object or xrspace
*/
export function useXRHitTest(fn, relativeTo, trackableType) {
const sourceRef = useRef(undefined);
useCreateXRHitTestSource(relativeTo, trackableType, useCallback((source) => (sourceRef.current = source), []));
useFrame((_s, _d, frame) => {
if (fn == null || frame == null || sourceRef.current == null) {
return;
}
fn(frame.getHitTestResults(sourceRef.current.source), sourceRef.current.getWorldMatrix);
});
}
function useCreateXRHitTestSource(relativeTo, trackableType, onLoad) {
const store = useXRStore();
const session = useStore(store, (s) => s.session);
useEffect(() => {
if (session == null) {
return;
}
let storedResult;
let cancelled = false;
const relativeToResolved = relativeTo instanceof XRSpace || typeof relativeTo === 'string' ? relativeTo : relativeTo?.current;
if (relativeToResolved == null) {
return;
}
createXRHitTestSource(store, session, relativeToResolved, trackableType).then((result) => {
if (cancelled) {
return;
}
storedResult = result;
onLoad(result);
});
return () => {
onLoad(undefined);
cancelled = true;
storedResult?.source.cancel();
};
}, [session, store, relativeTo, trackableType, onLoad]);
}
/**
* Hook that returns a function to request a single hit test
*/
export function useXRRequestHitTest() {
const store = useXRStore();
return useCallback((relativeTo, trackableType) => {
const relativeToResolved = relativeTo instanceof XRSpace || typeof relativeTo === 'string' ? relativeTo : relativeTo.current;
if (relativeToResolved == null) {
return;
}
return requestXRHitTest(store, relativeToResolved, trackableType);
}, [store]);
}
/**
* Component for getting hit tests originating based on its position in the scene graph
*
* @param props
* #### `space` - [XRSpaceType](https://developer.mozilla.org/en-US/docs/Web/API/XRSpace) | [XRReferenceSpaceType](https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpace#reference_space_types)
* @function
*/
export const XRHitTest = forwardRef(({ trackableType, onResults, space, ...rest }, ref) => {
const internalRef = useRef(null);
useImperativeHandle(ref, () => internalRef.current);
useXRHitTest(onResults, space ?? internalRef, trackableType);
return _jsx("group", { ...rest, ref: internalRef });
});