123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- import { WebXRFeature, WebXRFeaturesManager } from '../webXRFeaturesManager';
- import { WebXRSessionManager } from '../webXRSessionManager';
- import { Observable, Observer } from '../../../Misc/observable';
- import { Vector3, Matrix } from '../../../Maths/math.vector';
- import { TransformNode } from '../../../Meshes/transformNode';
- import { Nullable } from '../../../types';
- const Name = "xr-hit-test";
- //register the plugin
- WebXRFeaturesManager.AddWebXRFeature(Name, (xrSessionManager, options) => {
- return () => new WebXRHitTest(xrSessionManager, options);
- });
- export interface WebXRHitTestOptions {
- testOnPointerDownOnly?: boolean;
- worldParentNode?: TransformNode;
- }
- export interface WebXRHitResult {
- xrHitResult: XRHitResult;
- transformationMatrix: Matrix;
- }
- export type WebXRHitResults = WebXRHitResult[];
- export class WebXRHitTest implements WebXRFeature {
- public static readonly Name = Name;
- public static XRHitTestWithSelectEvent(event: XRInputSourceEvent, referenceSpace: XRReferenceSpace): Promise<XRHitResult[]> {
- let targetRayPose = event.frame.getPose(event.inputSource.targetRaySpace, referenceSpace);
- if (!targetRayPose) {
- return Promise.resolve([]);
- }
- let targetRay = new XRRay(targetRayPose.transform);
- return this.XRHitTestWithRay(event.frame.session, targetRay, referenceSpace);
- }
- public static XRHitTestWithRay(xrSession: XRSession, xrRay: XRRay, referenceSpace: XRReferenceSpace, filter?: (result: XRHitResult) => boolean): Promise<XRHitResult[]> {
- return xrSession.requestHitTest(xrRay, referenceSpace).then((results) => {
- const filterFunction = filter || ((result) => !!result.hitMatrix);
- return results.filter(filterFunction);
- });
- }
- public onHitTestResultObservable: Observable<WebXRHitResults> = new Observable();
- constructor(private xrSessionManager: WebXRSessionManager, public readonly options: WebXRHitTestOptions = {}) {
- }
- private _onSelectEnabled = false;
- private _xrFrameObserver: Nullable<Observer<XRFrame>>;
- private _attached: boolean = false;
- public lastNativeXRHitResults: XRHitResult[] = [];
- attach(): boolean {
- if (this.options.testOnPointerDownOnly) {
- this.xrSessionManager.session.addEventListener('select', this.onSelect, false);
- } else {
- // we are in XR space!
- const origin = new Vector3(0, 0, 0);
- // in XR space z-forward is negative
- const direction = new Vector3(0, 0, -1);
- const mat = new Matrix();
- this._xrFrameObserver = this.xrSessionManager.onXRFrameObservable.add((frame) => {
- // make sure we do nothing if (async) not attached
- if (!this._attached) {
- return;
- }
- let pose = frame.getViewerPose(this.xrSessionManager.referenceSpace);
- if (!pose) {
- return;
- }
- Matrix.FromArrayToRef(pose.transform.matrix, 0, mat);
- Vector3.TransformCoordinatesFromFloatsToRef(0, 0, 0, mat, origin);
- Vector3.TransformCoordinatesFromFloatsToRef(0, 0, -1, mat, direction);
- direction.subtractInPlace(origin);
- direction.normalize();
- let ray = new XRRay((<DOMPointReadOnly>{ x: origin.x, y: origin.y, z: origin.z, w: 0 }),
- (<DOMPointReadOnly>{ x: direction.x, y: direction.y, z: direction.z, w: 0 }));
- WebXRHitTest.XRHitTestWithRay(this.xrSessionManager.session, ray, this.xrSessionManager.referenceSpace).then(this.onHitTestResults);
- });
- }
- this._attached = true;
- return true;
- }
- detach(): boolean {
- // disable select
- this._onSelectEnabled = false;
- this.xrSessionManager.session.removeEventListener('select', this.onSelect);
- if (this._xrFrameObserver) {
- this.xrSessionManager.onXRFrameObservable.remove(this._xrFrameObserver);
- this._xrFrameObserver = null;
- }
- this._attached = false;
- return true;
- }
- private onHitTestResults = (xrResults: XRHitResult[]) => {
- const mats = xrResults.map((result) => {
- let mat = Matrix.FromArray(result.hitMatrix);
- if (!this.xrSessionManager.scene.useRightHandedSystem) {
- mat.toggleModelMatrixHandInPlace();
- }
- // if (this.options.coordinatesSpace === Space.WORLD) {
- if (this.options.worldParentNode) {
- mat.multiplyToRef(this.options.worldParentNode.getWorldMatrix(), mat);
- }
- return {
- xrHitResult: result,
- transformationMatrix: mat
- };
- });
- this.lastNativeXRHitResults = xrResults;
- this.onHitTestResultObservable.notifyObservers(mats);
- }
- // can be done using pointerdown event, and xrSessionManager.currentFrame
- private onSelect = (event: XRInputSourceEvent) => {
- if (!this._onSelectEnabled) {
- return;
- }
- WebXRHitTest.XRHitTestWithSelectEvent(event, this.xrSessionManager.referenceSpace);
- }
- dispose(): void {
- this.detach();
- this.onHitTestResultObservable.clear();
- }
- }
|