summit/frontend/node_modules/three-stdlib/webxr/XRControllerModelFactory.cj...

1 line
12 KiB
Plaintext
Raw Normal View History

2025-12-08 16:31:30 +00:00
{"version":3,"file":"XRControllerModelFactory.cjs","sources":["../../src/webxr/XRControllerModelFactory.ts"],"sourcesContent":["import { Mesh, Object3D, SphereGeometry, MeshBasicMaterial } from 'three'\nimport type { Texture, Group } from 'three'\nimport { GLTFLoader } from '../loaders/GLTFLoader'\nimport { fetchProfile, MotionController, MotionControllerConstants } from '../libs/MotionControllers'\n\nconst DEFAULT_PROFILES_PATH = 'https://cdn.jsdelivr.net/npm/@webxr-input-profiles/assets@1.0/dist/profiles'\nconst DEFAULT_PROFILE = 'generic-trigger'\n\nconst applyEnvironmentMap = (envMap: Texture, obj: Object3D): void => {\n obj.traverse((child) => {\n if (child instanceof Mesh && 'envMap' in child.material) {\n child.material.envMap = envMap\n child.material.needsUpdate = true\n }\n })\n}\n\nclass XRControllerModel extends Object3D {\n envMap: Texture | null\n motionController: MotionController | null\n constructor() {\n super()\n\n this.motionController = null\n this.envMap = null\n }\n\n setEnvironmentMap(envMap: Texture): XRControllerModel {\n if (this.envMap == envMap) {\n return this\n }\n\n this.envMap = envMap\n applyEnvironmentMap(this.envMap, this)\n\n return this\n }\n\n /**\n * Polls data from the XRInputSource and updates the model's components to match\n * the real world data\n */\n updateMatrixWorld(force: boolean): void {\n super.updateMatrixWorld(force)\n\n if (!this.motionController) return\n\n // Cause the MotionController to poll the Gamepad for data\n this.motionController.updateFromGamepad()\n\n // Update the 3D model to reflect the button, thumbstick, and touchpad state\n Object.values(this.motionController.components).forEach((component) => {\n // Update node data based on the visual responses' current states\n Object.values(component.visualResponses).forEach((visualResponse) => {\n const { valueNode, minNode, maxNode, value, valueNodeProperty } = visualResponse\n\n // Skip if the visual response node is not found. No error is needed,\n // because it will have been reported at load time.\n if (!valueNode) return\n\n // Calculate the new properties based on the weight supplied\n if (\n valueNodeProperty === MotionControllerConstants.VisualResponseProperty.VISIBILITY &&\n typeof value === 'boolean'\n ) {\n valueNode.visible = value\n } else if (\n valueNodeProperty === MotionControllerConstants.VisualResponseProperty.TRANSFORM &&\n minNode &&\n maxNode &&\n typeof value === 'number'\n ) {\n valueNode.quaternion.slerpQuaternions(minNode.quaternion, maxNode.quaternion, value)\n\n valueNode.position.lerpVectors(minNode.position, maxNode.position, value)\n }\n })\n })\n }\n}\n\n/**\n * Walks the model's tree to find the nodes needed to animate the components and\n * saves them to the motionContoller components for use in the frame loop. When\n * touchpads are found, attaches a touch dot to them.\n */\nfunction findNodes(motionController: MotionController, scene: Object3D): void {\n // Loop through the components and find the nodes needed for each components' visual responses\n Object.values(motionController.components).forEach((component) => {\n const { type, touchPointNodeName, visualResponses } = component\n\n if (type === MotionControllerConstants.ComponentType.TOUCHPAD && touchPointNodeName) {\n component.touchPointNode = scene.getObjectByName(touchPointNodeName)\n if (component.touchPointNode) {\n // Attach a touch dot to the touchpad.\n const sphereGeometry = new SphereGeometry(0.001)\n const material = new MeshBasicMaterial({ color: 0x0000ff })\n const sphere = new Mesh(sphereGeometry, material)\n component.touchPointNode.add(sphere)\n } else {\n console.warn(`Could not find touch dot, ${component.touchPointNodeName}, in touchpad component ${component.id}`)\n }\n }\n\n // Loop