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

WebXR Input Source: linear velocity #3060

Merged
merged 12 commits into from
Dec 8, 2023
73 changes: 67 additions & 6 deletions src/framework/xr/xr-input-source.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import { Ray } from '../../core/shape/ray.js';

import { XrHand } from './xr-hand.js';

import { now } from '../../core/time.js';

const vec3A = new Vec3();
const quat = new Quat();
let ids = 0;

Expand Down Expand Up @@ -56,11 +59,23 @@ class XrInputSource extends EventHandler {
_grip = false;

/**
* @type {XrHand}
* @type {XrHand|null}
* @private
*/
_hand = null;

/**
* @type {boolean}
* @private
*/
_velocitiesAvailable = false;

/**
* @type {number}
* @private
*/
_velocitiesTimestamp = now();

/**
* @type {Mat4|null}
* @private
Expand All @@ -86,17 +101,29 @@ class XrInputSource extends EventHandler {
_rotation = new Quat();

/**
* @type {Mat4|null}
* @type {Vec3|null}
* @private
*/
_localPosition = null;

/**
* @type {Mat4|null}
* @type {Vec3|null}
* @private
*/
_localPositionLast = null;

/**
* @type {Quat|null}
* @private
*/
_localRotation = null;

/**
* @type {Vec3|null}
* @private
*/
_linearVelocity = null;

/**
* @type {boolean}
* @private
Expand Down Expand Up @@ -431,21 +458,42 @@ class XrInputSource extends EventHandler {
this._hand.update(frame);
} else {
// grip
if (this._xrInputSource.gripSpace) {
const gripPose = frame.getPose(this._xrInputSource.gripSpace, this._manager._referenceSpace);
const gripSpace = this._xrInputSource.gripSpace;
if (gripSpace) {
const gripPose = frame.getPose(gripSpace, this._manager._referenceSpace);
if (gripPose) {
if (!this._grip) {
this._grip = true;

this._localTransform = new Mat4();
this._worldTransform = new Mat4();

this._localPositionLast = new Vec3();
this._localPosition = new Vec3();
this._localRotation = new Quat();

this._linearVelocity = new Vec3();
}

const timestamp = now();
const dt = (timestamp - this._velocitiesTimestamp) / 1000;
this._velocitiesTimestamp = timestamp;

this._dirtyLocal = true;

this._localPositionLast.copy(this._localPosition);
this._localPosition.copy(gripPose.transform.position);
this._localRotation.copy(gripPose.transform.orientation);

this._velocitiesAvailable = true;
if (this._manager.input.velocitiesSupported && gripPose.linearVelocity) {
this._linearVelocity.copy(gripPose.linearVelocity);
} else if (dt > 0) {
vec3A.sub2(this._localPosition, this._localPositionLast).divScalar(dt);
this._linearVelocity.lerp(this._linearVelocity, vec3A, 0.15);
}
} else {
this._velocitiesAvailable = false;
}
}

Expand Down Expand Up @@ -541,12 +589,25 @@ class XrInputSource extends EventHandler {
* Get the local space rotation of input source if it is handheld ({@link XrInputSource#grip}
* is true). Local space is relative to parent of the XR camera. Otherwise it will return null.
*
* @returns {Vec3|null} The world space rotation of handheld input source.
* @returns {Quat|null} The world space rotation of handheld input source.
*/
getLocalRotation() {
return this._localRotation;
}

/**
* Get the linear velocity (units per second) of the input source if it is handheld
* ({@link XrInputSource#grip} is true). Otherwise it will return null.
*
* @returns {Vec3|null} The world space linear velocity of the handheld input source.
*/
getLinearVelocity() {
if (!this._velocitiesAvailable)
return null;

return this._linearVelocity;
}

/**
* Get the world space origin of input source ray.
*
Expand Down
9 changes: 8 additions & 1 deletion src/framework/xr/xr-input.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { EventHandler } from '../../core/event-handler.js';

import { platform } from '../../core/platform.js';
import { XrInputSource } from './xr-input-source.js';

/**
Expand Down Expand Up @@ -27,6 +27,12 @@ class XrInput extends EventHandler {
*/
_onInputSourcesChangeEvt;

/**
* @type {boolean}
* @ignore
*/
velocitiesSupported = false;

/**
* Create a new XrInput instance.
*
Expand All @@ -37,6 +43,7 @@ class XrInput extends EventHandler {
super();

this.manager = manager;
this.velocitiesSupported = !!(platform.browser && window.XRPose?.prototype?.hasOwnProperty('linearVelocity'));

this._onInputSourcesChangeEvt = (evt) => {
this._onInputSourcesChange(evt);
Expand Down