UNPKG

@pmndrs/xr

Version:
83 lines (82 loc) 3.08 kB
import { Matrix4, Quaternion, Vector3 } from 'three'; import { getSpaceFromAncestors } from './internals.js'; import { toDOMPointInit } from './utils.js'; const matrixHelper = new Matrix4(); const vectorHelper = new Vector3(); const scaleHelper = new Vector3(); const quaternionHelper = new Quaternion(); export async function createXRHitTestSource(store, session, relativeTo, trackableType = ['point', 'plane', 'mesh']) { if (typeof relativeTo === 'string') { relativeTo = await session.requestReferenceSpace(relativeTo); } const entityTypes = Array.isArray(trackableType) ? trackableType : [trackableType]; //necassary data for request and compute hit test results let options; let baseSpace; let object; const state = store.getState(); if (relativeTo instanceof XRSpace) { //configure for request and compute hit test results options = { space: relativeTo, entityTypes }; object = state.origin; } else { //compute space const space = getSpaceFromAncestors(relativeTo, state.origin, state.originReferenceSpace, matrixHelper); if (space == null) { return undefined; } //compute offset ray matrixHelper.decompose(vectorHelper, quaternionHelper, scaleHelper); const point = toDOMPointInit(vectorHelper); vectorHelper.set(0, 0, -1).applyQuaternion(quaternionHelper); const offsetRay = new XRRay(point, toDOMPointInit(vectorHelper, 0)); //configure for request and compute hit test results object = relativeTo; options = { space, offsetRay, entityTypes }; baseSpace = space; } const source = await session?.requestHitTestSource?.(options); if (source == null) { return undefined; } return { source, getWorldMatrix: computeWorldMatrixFromXRHitTestResult.bind(null, store, baseSpace, object), }; } export async function requestXRHitTest(store, relativeTo, trackableType) { const session = store.getState().session; if (session == null) { return; } const sourceData = await createXRHitTestSource(store, session, relativeTo, trackableType); if (sourceData == null) { return undefined; } const { source, getWorldMatrix } = sourceData; const frame = await store.requestFrame(); const results = frame.getHitTestResults?.(source) ?? []; source.cancel(); if (results == null) { return undefined; } return { results, getWorldMatrix }; } function computeWorldMatrixFromXRHitTestResult(store, baseSpace, object, target, result) { baseSpace ??= store.getState().originReferenceSpace; if (baseSpace == null) { return false; } const pose = result.getPose(baseSpace); if (pose == null) { return false; } //target = ObjectMatrixWorld? * HitTestMatrix target.fromArray(pose.transform.matrix); if (object != null) { object.updateWorldMatrix(true, false); target.premultiply(object.matrixWorld); } return true; }