@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
121 lines (110 loc) • 3.84 kB
text/typescript
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);
}
}