|
@@ -36,8 +36,9 @@ export interface IWebXRTeleportationOptions {
|
|
|
* A list of meshes to use as floor meshes.
|
|
|
* Meshes can be added and removed after initializing the feature using the
|
|
|
* addFloorMesh and removeFloorMesh functions
|
|
|
+ * If empty, rotation will still work
|
|
|
*/
|
|
|
- floorMeshes: AbstractMesh[];
|
|
|
+ floorMeshes?: AbstractMesh[];
|
|
|
/**
|
|
|
* Provide your own teleportation mesh instead of babylon's wonderful doughnut.
|
|
|
* If you want to support rotation, make sure your mesh has a direction indicator.
|
|
@@ -128,7 +129,7 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature imp
|
|
|
* @param mesh the mesh to use as floor mesh
|
|
|
*/
|
|
|
public addFloorMesh(mesh: AbstractMesh) {
|
|
|
- this._options.floorMeshes.push(mesh);
|
|
|
+ this._floorMeshes.push(mesh);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -136,9 +137,9 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature imp
|
|
|
* @param mesh the mesh to remove
|
|
|
*/
|
|
|
public removeFloorMesh(mesh: AbstractMesh) {
|
|
|
- const index = this._options.floorMeshes.indexOf(mesh);
|
|
|
+ const index = this._floorMeshes.indexOf(mesh);
|
|
|
if (index !== -1) {
|
|
|
- this._options.floorMeshes.splice(index, 1);
|
|
|
+ this._floorMeshes.splice(index, 1);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -156,6 +157,8 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature imp
|
|
|
private _tmpRay = new Ray(new Vector3(), new Vector3());
|
|
|
private _tmpVector = new Vector3();
|
|
|
|
|
|
+ private _floorMeshes: AbstractMesh[];
|
|
|
+
|
|
|
private _controllers: {
|
|
|
[controllerUniqueId: string]: {
|
|
|
xrController: WebXRController;
|
|
@@ -184,6 +187,8 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature imp
|
|
|
this.createDefaultTargetMesh();
|
|
|
}
|
|
|
|
|
|
+ this._floorMeshes = this._options.floorMeshes || [];
|
|
|
+
|
|
|
this.setTargetMeshVisibility(false);
|
|
|
}
|
|
|
|
|
@@ -231,63 +236,63 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature imp
|
|
|
|
|
|
protected _onXRFrame(_xrFrame: XRFrame) {
|
|
|
const frame = this._xrSessionManager.currentFrame;
|
|
|
- const scene = this._xrSessionManager.scene;
|
|
|
- if (!this.attach || !frame) { return; }
|
|
|
+ const scene = this._xrSessionManager.scene;
|
|
|
+ if (!this.attach || !frame) { return; }
|
|
|
|
|
|
- // render target if needed
|
|
|
- const targetMesh = this._options.teleportationTargetMesh;
|
|
|
- if (this._currentTeleportationControllerId) {
|
|
|
- if (!targetMesh) {
|
|
|
- return;
|
|
|
- }
|
|
|
- targetMesh.rotationQuaternion = targetMesh.rotationQuaternion || new Quaternion();
|
|
|
- const controllerData = this._controllers[this._currentTeleportationControllerId];
|
|
|
- if (controllerData.teleportationState.forward) {
|
|
|
- // set the rotation
|
|
|
- Quaternion.RotationYawPitchRollToRef(controllerData.teleportationState.currentRotation + controllerData.teleportationState.baseRotation, 0, 0, targetMesh.rotationQuaternion);
|
|
|
- // set the ray and position
|
|
|
-
|
|
|
- let hitPossible = false;
|
|
|
- // first check if direct ray possible
|
|
|
- controllerData.xrController.getWorldPointerRayToRef(this._tmpRay);
|
|
|
- let pick = scene.pickWithRay(this._tmpRay, (o) => {
|
|
|
- return this._options.floorMeshes.indexOf(o) !== -1;
|
|
|
- });
|
|
|
- if (pick && pick.pickedPoint) {
|
|
|
- hitPossible = true;
|
|
|
- this.setTargetMeshPosition(pick.pickedPoint);
|
|
|
- this.setTargetMeshVisibility(true);
|
|
|
- this.showParabolicPath(pick);
|
|
|
- } else {
|
|
|
- if (this.parabolicRayEnabled) {
|
|
|
- // check parabolic ray
|
|
|
- const radius = this.parabolicCheckRadius;
|
|
|
- this._tmpRay.origin.addToRef(this._tmpRay.direction.scale(radius * 2), this._tmpVector);
|
|
|
- this._tmpVector.y = this._tmpRay.origin.y;
|
|
|
- this._tmpRay.origin.addInPlace(this._tmpRay.direction.scale(radius));
|
|
|
- this._tmpVector.subtractToRef(this._tmpRay.origin, this._tmpRay.direction);
|
|
|
- this._tmpRay.direction.normalize();
|
|
|
-
|
|
|
- let pick = scene.pickWithRay(this._tmpRay, (o) => {
|
|
|
- return this._options.floorMeshes.indexOf(o) !== -1;
|
|
|
- });
|
|
|
- if (pick && pick.pickedPoint) {
|
|
|
- hitPossible = true;
|
|
|
- this.setTargetMeshPosition(pick.pickedPoint);
|
|
|
- this.setTargetMeshVisibility(true);
|
|
|
- this.showParabolicPath(pick);
|
|
|
- }
|
|
|
+ // render target if needed
|
|
|
+ const targetMesh = this._options.teleportationTargetMesh;
|
|
|
+ if (this._currentTeleportationControllerId) {
|
|
|
+ if (!targetMesh) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ targetMesh.rotationQuaternion = targetMesh.rotationQuaternion || new Quaternion();
|
|
|
+ const controllerData = this._controllers[this._currentTeleportationControllerId];
|
|
|
+ if (controllerData.teleportationState.forward) {
|
|
|
+ // set the rotation
|
|
|
+ Quaternion.RotationYawPitchRollToRef(controllerData.teleportationState.currentRotation + controllerData.teleportationState.baseRotation, 0, 0, targetMesh.rotationQuaternion);
|
|
|
+ // set the ray and position
|
|
|
+
|
|
|
+ let hitPossible = false;
|
|
|
+ // first check if direct ray possible
|
|
|
+ controllerData.xrController.getWorldPointerRayToRef(this._tmpRay);
|
|
|
+ let pick = scene.pickWithRay(this._tmpRay, (o) => {
|
|
|
+ return this._floorMeshes.indexOf(o) !== -1;
|
|
|
+ });
|
|
|
+ if (pick && pick.pickedPoint) {
|
|
|
+ hitPossible = true;
|
|
|
+ this.setTargetMeshPosition(pick.pickedPoint);
|
|
|
+ this.setTargetMeshVisibility(true);
|
|
|
+ this.showParabolicPath(pick);
|
|
|
+ } else {
|
|
|
+ if (this.parabolicRayEnabled) {
|
|
|
+ // check parabolic ray
|
|
|
+ const radius = this.parabolicCheckRadius;
|
|
|
+ this._tmpRay.origin.addToRef(this._tmpRay.direction.scale(radius * 2), this._tmpVector);
|
|
|
+ this._tmpVector.y = this._tmpRay.origin.y;
|
|
|
+ this._tmpRay.origin.addInPlace(this._tmpRay.direction.scale(radius));
|
|
|
+ this._tmpVector.subtractToRef(this._tmpRay.origin, this._tmpRay.direction);
|
|
|
+ this._tmpRay.direction.normalize();
|
|
|
+
|
|
|
+ let pick = scene.pickWithRay(this._tmpRay, (o) => {
|
|
|
+ return this._floorMeshes.indexOf(o) !== -1;
|
|
|
+ });
|
|
|
+ if (pick && pick.pickedPoint) {
|
|
|
+ hitPossible = true;
|
|
|
+ this.setTargetMeshPosition(pick.pickedPoint);
|
|
|
+ this.setTargetMeshVisibility(true);
|
|
|
+ this.showParabolicPath(pick);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- // if needed, set visible:
|
|
|
- this.setTargetMeshVisibility(hitPossible);
|
|
|
- } else {
|
|
|
- this.setTargetMeshVisibility(false);
|
|
|
}
|
|
|
+
|
|
|
+ // if needed, set visible:
|
|
|
+ this.setTargetMeshVisibility(hitPossible);
|
|
|
} else {
|
|
|
this.setTargetMeshVisibility(false);
|
|
|
}
|
|
|
+ } else {
|
|
|
+ this.setTargetMeshVisibility(false);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private _currentTeleportationControllerId: string;
|
|
@@ -373,7 +378,7 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature imp
|
|
|
this._tmpRay.origin.copyFrom(this._tmpVector);
|
|
|
this._tmpRay.direction.set(0, -1, 0);
|
|
|
let pick = this._xrSessionManager.scene.pickWithRay(this._tmpRay, (o) => {
|
|
|
- return this._options.floorMeshes.indexOf(o) !== -1;
|
|
|
+ return this._floorMeshes.indexOf(o) !== -1;
|
|
|
});
|
|
|
|
|
|
// pick must exist, but stay safe
|