import * as THREE from 'https://unpkg.com/three/build/three.module.js'; import { getSeekProgressFromIntersection, type VrControlPanel } from './vr-control-panel.js'; type VrControllerSelectionOptions = { exitVr: () => void; forward: () => void; hidePanel: () => void; isPanelVisible: () => boolean; raycaster: any; rewind: () => void; seek: (progress: number) => void; showPanel: () => void; toggleMute: () => void; togglePlayPause: () => void; uiElements: any[]; vrPanel: VrControlPanel | undefined; }; const tempMatrix = new THREE.Matrix4(); export function createVrController(scene: any, renderer: any, onSelectStart: (event: any) => void): { controller: any; raycaster: any; } { const controller = renderer.xr.getController(0); controller.addEventListener('selectstart', onSelectStart); const lineMaterial = new THREE.LineBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.5 }); const lineGeometry = new THREE.BufferGeometry().setFromPoints([ new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 0, -5) ]); controller.add(new THREE.Line(lineGeometry, lineMaterial)); scene.add(controller); const raycaster = new THREE.Raycaster(); raycaster.near = 0.1; raycaster.far = 5; return { controller, raycaster }; } export function handleVrControllerSelect(event: any, options: VrControllerSelectionOptions): void { const controller = event.target; if (!options.raycaster) return; controller.updateMatrixWorld(); tempMatrix.identity().extractRotation(controller.matrixWorld); options.raycaster.ray.origin.setFromMatrixPosition(controller.matrixWorld); options.raycaster.ray.direction.set(0, 0, -1).applyMatrix4(tempMatrix); const directIntersects = options.raycaster.intersectObjects(options.uiElements, true); if (directIntersects.length === 0) { togglePanel(options); return; } const firstIntersected = directIntersects[0].object; const intersectionPoint = directIntersects[0].point; if (firstIntersected.name === 'vrPlayPauseButton') { options.togglePlayPause(); options.showPanel(); return; } if (firstIntersected.name === 'vrRewindButton') { options.rewind(); options.showPanel(); return; } if (firstIntersected.name === 'vrForwardButton') { options.forward(); options.showPanel(); return; } if (firstIntersected.name === 'vrExitButton') { options.exitVr(); options.showPanel(); return; } if (firstIntersected.name === 'vrVolumeButton') { options.toggleMute(); options.showPanel(); return; } if (firstIntersected.name === 'seekBarHitArea') { options.showPanel(); options.seek(getSeekProgressFromIntersection(options.vrPanel, intersectionPoint)); return; } togglePanel(options); } function togglePanel(options: VrControllerSelectionOptions): void { if (options.isPanelVisible()) { options.hidePanel(); } else { options.showPanel(); } }