Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[XR] Fix teleportation backwards movement #8855

Merged
merged 3 commits into from Sep 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion dist/preview release/what's new.md
Expand Up @@ -181,7 +181,7 @@
- Fixed an issue with stencil not enabled per default ([#8720](https://github.com/BabylonJS/Babylon.js/issues/8720)) ([RaananW](https://github.com/RaananW))
- Expose the overlay to which the XR Enter/Exit buttons are added to ([#8754](https://github.com/BabylonJS/Babylon.js/issues/8754)) ([RaananW](https://github.com/RaananW))
- WebXR hand-tracking module is available, able to track hand-joints on selected devices including physics interactions ([RaananW](https://github.com/RaananW))

- Fixed an issue with backwards movement in XR ([#8854](https://github.com/BabylonJS/Babylon.js/issues/8854)) ([RaananW](https://github.com/RaananW))
### Collisions

- Added an option to optimize collision detection performance ([jsdream](https://github.com/jsdream)) - [PR](https://github.com/BabylonJS/Babylon.js/pull/7810)
Expand Down
46 changes: 40 additions & 6 deletions src/XR/features/WebXRControllerTeleportation.ts
Expand Up @@ -109,6 +109,11 @@ export interface IWebXRTeleportationOptions {
* Babylon XR Input class for controller
*/
xrInput: WebXRInput;

/**
* Meshes that the teleportation ray cannot go through
*/
pickBlockerMeshes?: AbstractMesh[];
}

/**
Expand Down Expand Up @@ -141,6 +146,7 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
private _teleportationRingMaterial?: StandardMaterial;
private _tmpRay = new Ray(new Vector3(), new Vector3());
private _tmpVector = new Vector3();
private _tmpQuaternion = new Quaternion();

/**
* The module's name
Expand Down Expand Up @@ -357,8 +363,15 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
if (index === -1) {
return false;
}
// check for mesh-blockers
if (this._options.pickBlockerMeshes && this._options.pickBlockerMeshes.indexOf(o) !== -1) {
return true;
}
return this._floorMeshes[index].absolutePosition.y < this._options.xrInput.xrCamera.position.y;
});
if (pick && pick.pickedMesh && this._options.pickBlockerMeshes && this._options.pickBlockerMeshes.indexOf(pick.pickedMesh) !== -1) {
return;
}
if (pick && pick.pickedPoint) {
hitPossible = true;
this._setTargetMeshPosition(pick.pickedPoint);
Expand All @@ -378,8 +391,15 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
this._tmpRay.direction.normalize();

let pick = scene.pickWithRay(this._tmpRay, (o) => {
// check for mesh-blockers
if (this._options.pickBlockerMeshes && this._options.pickBlockerMeshes.indexOf(o) !== -1) {
return true;
}
return this._floorMeshes.indexOf(o) !== -1;
});
if (pick && pick.pickedMesh && this._options.pickBlockerMeshes && this._options.pickBlockerMeshes.indexOf(pick.pickedMesh) !== -1) {
return;
}
if (pick && pick.pickedPoint) {
hitPossible = true;
this._setTargetMeshPosition(pick.pickedPoint);
Expand Down Expand Up @@ -461,23 +481,37 @@ export class WebXRMotionControllerTeleportation extends WebXRAbstractFeature {
}
if (axesData.y > 0.7 && !controllerData.teleportationState.forward && this.backwardsMovementEnabled && !this.snapPointsOnly) {
// teleport backwards

// General gist: Go Back N units, cast a ray towards the floor. If collided, move.
if (!controllerData.teleportationState.backwards) {
controllerData.teleportationState.backwards = true;
// teleport backwards ONCE
this._tmpVector.set(0, 0, this.backwardsTeleportationDistance * (this._xrSessionManager.scene.useRightHandedSystem ? -1.0 : 1.0));
this._tmpVector.rotateByQuaternionToRef(this._options.xrInput.xrCamera.rotationQuaternion!, this._tmpVector);
this._tmpQuaternion.copyFrom(this._options.xrInput.xrCamera.rotationQuaternion!);
this._tmpQuaternion.toEulerAnglesToRef(this._tmpVector);
// get only the y rotation
this._tmpVector.x = 0;
this._tmpVector.z = 0;
// get the quaternion
Quaternion.FromEulerVectorToRef(this._tmpVector, this._tmpQuaternion);
this._tmpVector.set(0, 0, this.backwardsTeleportationDistance * (this._xrSessionManager.scene.useRightHandedSystem ? 1.0 : -1.0));
this._tmpVector.rotateByQuaternionToRef(this._tmpQuaternion, this._tmpVector);
this._tmpVector.addInPlace(this._options.xrInput.xrCamera.position);
this._options.xrInput.xrCamera.position.subtractToRef(this._tmpVector, this._tmpVector);
this._tmpRay.origin.copyFrom(this._tmpVector);
this._tmpRay.direction.set(0, this._xrSessionManager.scene.useRightHandedSystem ? 1 : -1, 0);
// This will prevent the user from "falling" to a lower platform!
// TODO - should this be a flag? 'allow falling to lower platforms'?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the flag approach but I do not have enough background to be a good judge :-) I let you chose

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more "dev freedom" that an actual needed feature :-)
I will put it on future features to implement.

this._tmpRay.length = this._options.xrInput.xrCamera.realWorldHeight + 0.1;
// Right handed system had here "1" instead of -1. This is unneeded.
this._tmpRay.direction.set(0, -1, 0);
let pick = this._xrSessionManager.scene.pickWithRay(this._tmpRay, (o) => {
return this._floorMeshes.indexOf(o) !== -1;
});

// pick must exist, but stay safe
if (pick && pick.pickedPoint) {
// Teleport the users feet to where they targeted
this._options.xrInput.xrCamera.position.addInPlace(pick.pickedPoint);
// Teleport the users feet to where they targeted. Ignore the Y axis.
// If the "falling to lower platforms" feature is implemented the Y axis should be set here as well
this._options.xrInput.xrCamera.position.x = pick.pickedPoint.x;
this._options.xrInput.xrCamera.position.z = pick.pickedPoint.z;
}
}
}
Expand Down