import {Vector3} from "three";
import {Vector} from "../../core/geometry/Vector.js";
import {LEFT, RIGHT} from "../../constants.js";
import {bind} from "../../utils.js";
/**
* @class
*
* @classdesc
* Makes sure that an given solid in the geometry follows a VR controller (living in the tangent space).
* The position of the underlying shape should be given by an isometry of the geometry
*/
export class IsotropicChaseVRControls {
/**
* Constructor
* @param {Group} controller - the group representing the controller
* @param {VRCamera} camera - the camera (giving the position of the observer)
* @param {Solid} solid - the solid following the controller.
* The position of the underlying shape should be given by an isometry.
*/
constructor(controller, camera, solid) {
this.controller = controller;
this.camera = camera;
this.solid = solid;
this._isSelecting = false;
this._isSqueezing = false;
const _onSelectStart = bind(this, this.onSelectStart);
const _onSelectEnd = bind(this, this.onSelectEnd);
const _onSqueezeStart = bind(this, this.onSqueezeStart);
const _onSqueezeEnd = bind(this, this.onSqueezeEnd);
this.controller.addEventListener('selectstart', _onSelectStart);
this.controller.addEventListener('selectend', _onSelectEnd);
this.controller.addEventListener('squeezestart', _onSqueezeStart);
this.controller.addEventListener('squeezeend', _onSqueezeEnd);
}
/**
* Event handler when the user starts selecting
*/
onSelectStart() {
this._isSelecting = true;
}
/**
* Event handler when the user stops selecting
*/
onSelectEnd() {
this._isSelecting = false;
}
/**
* Event handler when the user starts squeezing
*/
onSqueezeStart() {
this._isSqueezing = true;
}
/**
* Event handler when the user stops squeezing
*/
onSqueezeEnd() {
this._isSqueezing = false;
}
/**
* @param {WebXRManager} webXRManager - the WebXRManager used by Three.js
*/
chase(webXRManager) {
this.solid.isRendered = this._isSelecting;
const controllerPosition = new Vector().setFromMatrixPosition(this.controller.matrixWorld);
let cameraPosition = new Vector();
if (this.camera.isStereoOn) {
// If XR is enable, we get the position of the left and right camera.
// Note that when XR is on, then main Three.js Camera is shifted to coincide with the right eye.
// So its position is NOT the midpoint between the eyes of the observer.
// Thus we take here the midpoint between the two VR cameras.
// Those can only be accessed using the WebXRManager.
const camerasVR = webXRManager.getCamera(this.camera.threeCamera).cameras;
const newThreePositionL = new Vector3().setFromMatrixPosition(camerasVR[LEFT].matrixWorld);
const newThreePositionR = new Vector3().setFromMatrixPosition(camerasVR[RIGHT].matrixWorld);
cameraPosition.lerpVectors(newThreePositionL, newThreePositionR, 0.5);
} else {
cameraPosition.setFromMatrixPosition(this.camera.matrix);
}
const relativeControllerPosition = controllerPosition.clone().sub(cameraPosition);
const relativeControllerMatrixWorld = this.controller.matrixWorld.clone().setPosition(relativeControllerPosition);
const position = this.camera.position.clone().fakeDiffExpMap(relativeControllerMatrixWorld);
this.solid.isom.copy(position.globalBoost);
this.solid.isom.matrix.multiply(position.facing);
this.solid.updateData();
}
}