UNPKG

@polygonjs/polygonjs

Version:

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

121 lines (110 loc) 3.84 kB
import { WebGLRenderer, BufferGeometry, Float32BufferAttribute, AdditiveBlending, LineBasicMaterial, Line, RingGeometry, MeshBasicMaterial, Mesh, Object3D, Camera, } from 'three'; import {PolyScene} from '../../../engine/scene/PolyScene'; import {CoreVRButton} from '../buttons/CoreVRButton'; import {CoreWebXRVRControllerOptions} from './CommonVR'; import {CoreWebXRControllerContainer} from '../CoreWebXRControllerContainer'; import {BaseCoreWebXRController, OnWebXRSessionStartedCallback} from '../_BaseCoreWebXRController'; import {BaseXRSessionEventName} from '../Common'; // from three // examples/webxr_vr_ballshooter.html function buildController(data: XRInputSource) { let geometry, material; switch (data.targetRayMode) { case 'tracked-pointer': geometry = new BufferGeometry(); geometry.setAttribute('position', new Float32BufferAttribute([0, 0, 0, 0, 0, -1], 3)); geometry.setAttribute('color', new Float32BufferAttribute([0.5, 0.5, 0.5, 0, 0, 0], 3)); material = new LineBasicMaterial({vertexColors: true, blending: AdditiveBlending}); return new Line(geometry, material); case 'gaze': geometry = new RingGeometry(0.02, 0.04, 32).translate(0, 0, -1); material = new MeshBasicMaterial({opacity: 0.5, transparent: true}); return new Mesh(geometry, material); } } export class CoreWebXRVRController extends BaseCoreWebXRController { private _baseReferenceSpace: XRReferenceSpace | null = null; constructor( scene: PolyScene, renderer: WebGLRenderer, camera: Camera, canvas: HTMLCanvasElement, protected override options: CoreWebXRVRControllerOptions ) { super(scene, renderer, camera, canvas, options); } override mount() { super.mount(); // this.scene.webXR.setVRController(this); const xr = this.renderer.xr; xr.addEventListener('sessionstart', () => (this._baseReferenceSpace = xr.getReferenceSpace())); } override async requestSession(sessionInit: XRSessionInit, onSessionStarted: OnWebXRSessionStartedCallback) { super.requestSession(sessionInit, onSessionStarted); return navigator.xr?.requestSession('immersive-vr', sessionInit).then(onSessionStarted); } protected override _onSessionStart() { // set active before super._onSessionStart // so that actor nodes can listen to the active xr manager this.scene.webXR.setActiveVRController(this); super._onSessionStart(); } protected override _onSessionEnd() { this.scene.webXR.setActiveVRController(null); super._onSessionEnd(); } baseReferenceSpace() { return this._baseReferenceSpace; } setReferenceSpace(referenceSpace: XRReferenceSpace) { this.renderer.xr.setReferenceSpace(referenceSpace); } protected override _addControllerEvents( controllerContainer: CoreWebXRControllerContainer, controllerIndex: number ): void { let controllerChild: Object3D | undefined; // add/remove crosshair to controller controllerContainer.controller.addEventListener(BaseXRSessionEventName.CONNECTED, function (event) { const data: XRInputSource = event.data; const _controllerChild = buildController(data); if (_controllerChild) { controllerChild = _controllerChild; controllerChild.name = `VR-eye-target-${controllerIndex}`; controllerContainer.controller.add(controllerChild); } }); controllerContainer.controller.addEventListener(BaseXRSessionEventName.DISCONNECTED, function () { if (controllerChild) { controllerContainer.controller.remove(controllerChild); } }); } createButton() { return CoreVRButton.createButton( { renderer: this.renderer, controller: this, }, { optionalFeatures: this.options.optionalFeatures, requiredFeatures: this.options.requiredFeatures, } ); } attachButton(parentElement: HTMLElement, buttonElement: HTMLElement) { parentElement.append(buttonElement); } }