UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

172 lines (155 loc) 5.7 kB
import {Camera, WebGLRenderer} from 'three'; import {PolyScene} from '../../../engine/scene/PolyScene'; import {CameraAttribute} from '../CoreCamera'; import { WebXRControllerMountFunction, WebXRControllerUnmountFunction, WEBXR_REFERENCE_SPACE_TYPES, } from '../../webXR/Common'; import {WebXRVRFeature, WEBXR_VR_FEATURES} from '../../webXR/webXRVR/CommonVR'; import {BaseCoreWebXRController} from '../../webXR/_BaseCoreWebXRController'; import {WebXRARFeature, WEBXR_AR_FEATURES} from '../../webXR/webXRAR/CommonAR'; import {coreObjectClassFactory} from '../../geometry/CoreObjectFactory'; interface WebXRControllerOptions { camera: Camera; scene: PolyScene; renderer: WebGLRenderer; canvas: HTMLCanvasElement; } export interface CoreCameraWebXRControllerConfig { mountFunction: WebXRControllerMountFunction; unmountFunction: WebXRControllerUnmountFunction; } function getFeatures<F extends WebXRARFeature | WebXRVRFeature>( camera: Camera, attribName: string, existingFeatures: F[] ): F[] { const features: F[] = []; const featuresStr = coreObjectClassFactory(camera).attribValue(camera, attribName) as string | null; const featuresStrings = featuresStr?.split(' '); if (featuresStrings) { for (const featuresString of featuresStrings) { if (existingFeatures.includes(featuresString as F)) { features.push(featuresString as F); } } } return features; } interface FeatureAttribNames { optional: CameraAttribute; required: CameraAttribute; } function _getRequiredAndOptionalFeatures<E extends WebXRARFeature | WebXRVRFeature>( camera: Camera, existingFeatures: E[], attribNames: FeatureAttribNames ) { // features const optionalFeatures = getFeatures<E>(camera, attribNames.optional, existingFeatures); const requiredFeatures = getFeatures<E>(camera, attribNames.required, existingFeatures); return {requiredFeatures, optionalFeatures}; } interface SpaceTypeAttribNames { type: CameraAttribute; override: CameraAttribute; } function _getReferenceSpaceType(camera: Camera, options: SpaceTypeAttribNames) { // referenceSpaceType const coreObjectClass = coreObjectClassFactory(camera); let overrideReferenceSpaceType = coreObjectClass.attribValue(camera, options.override) as boolean | null; let referenceSpaceType: string | null | undefined = coreObjectClass.attribValue(camera, options.type) as | string | null; if (!(referenceSpaceType && WEBXR_REFERENCE_SPACE_TYPES.includes(referenceSpaceType as XRReferenceSpaceType))) { overrideReferenceSpaceType = false; referenceSpaceType = undefined; } return {overrideReferenceSpaceType, referenceSpaceType}; } export class CoreCameraWebXRController { static process(options: WebXRControllerOptions): CoreCameraWebXRControllerConfig { const {camera, scene, renderer, canvas} = options; const controllers: BaseCoreWebXRController[] = []; const subMountFunctions: WebXRControllerMountFunction[] = []; const subUnmountFunctions: WebXRControllerUnmountFunction[] = []; const mountFunction: WebXRControllerMountFunction = () => { for (const subFunc of subMountFunctions) { subFunc(); } }; const unmountFunction: WebXRControllerUnmountFunction = () => { for (const subFunc of subUnmountFunctions) { subFunc(); } }; const coreObjectClass = coreObjectClassFactory(camera); // // AR // const isWebAR = coreObjectClass.attribValue(camera, CameraAttribute.WEBXR_AR) as boolean | null; if (isWebAR == true) { const createFunction = scene.webXR.ARControllerCreateFunction(); if (createFunction) { const {overrideReferenceSpaceType, referenceSpaceType} = _getReferenceSpaceType(camera, { type: CameraAttribute.WEBXR_AR_OVERRIDE_REFERENCE_SPACE_TYPE, override: CameraAttribute.WEBXR_AR_REFERENCE_SPACE_TYPE, }); const {requiredFeatures, optionalFeatures} = _getRequiredAndOptionalFeatures<WebXRARFeature>( camera, WEBXR_AR_FEATURES, { optional: CameraAttribute.WEBXR_AR_FEATURES_OPTIONAL, required: CameraAttribute.WEBXR_AR_FEATURES_REQUIRED, } ); // createFunction const controller = createFunction(renderer, camera, canvas, { overrideReferenceSpaceType: overrideReferenceSpaceType || false, referenceSpaceType: referenceSpaceType as XRReferenceSpaceType | undefined, requiredFeatures, optionalFeatures, }); controllers.push(controller); } } // // VR // const isWebVR = coreObjectClass.attribValue(camera, CameraAttribute.WEBXR_VR) as boolean | null; if (isWebVR == true) { const createFunction = scene.webXR.VRControllerCreateFunction(); if (createFunction) { const {overrideReferenceSpaceType, referenceSpaceType} = _getReferenceSpaceType(camera, { type: CameraAttribute.WEBXR_VR_OVERRIDE_REFERENCE_SPACE_TYPE, override: CameraAttribute.WEBXR_VR_REFERENCE_SPACE_TYPE, }); const {requiredFeatures, optionalFeatures} = _getRequiredAndOptionalFeatures<WebXRVRFeature>( camera, WEBXR_VR_FEATURES, { optional: CameraAttribute.WEBXR_VR_FEATURES_OPTIONAL, required: CameraAttribute.WEBXR_VR_FEATURES_REQUIRED, } ); // createFunction const controller = createFunction(renderer, camera, canvas, { overrideReferenceSpaceType: overrideReferenceSpaceType || false, referenceSpaceType: referenceSpaceType as XRReferenceSpaceType | undefined, requiredFeatures, optionalFeatures, }); controllers.push(controller); } } // // // for (const controller of controllers) { subMountFunctions.push(() => controller.mount()); subUnmountFunctions.push(() => controller.unmount()); } return {mountFunction, unmountFunction}; } }