playcanvas
Version:
PlayCanvas WebGL game engine
215 lines (212 loc) • 7.48 kB
JavaScript
import { EventHandler } from '../../core/event-handler.js';
import { Mat4 } from '../../core/math/mat4.js';
import { Quat } from '../../core/math/quat.js';
import { Vec3 } from '../../core/math/vec3.js';
import { Ray } from '../../core/shape/ray.js';
import { XrHand } from './xr-hand.js';
import { now } from '../../core/time.js';
var vec3A = new Vec3();
var quat = new Quat();
var ids = 0;
class XrInputSource extends EventHandler {
get id() {
return this._id;
}
get inputSource() {
return this._xrInputSource;
}
get targetRayMode() {
return this._xrInputSource.targetRayMode;
}
get handedness() {
return this._xrInputSource.handedness;
}
get profiles() {
return this._xrInputSource.profiles;
}
get grip() {
return this._grip;
}
get hand() {
return this._hand;
}
get gamepad() {
return this._xrInputSource.gamepad || null;
}
get selecting() {
return this._selecting;
}
get squeezing() {
return this._squeezing;
}
set elementInput(value) {
if (this._elementInput === value) {
return;
}
this._elementInput = value;
if (!this._elementInput) {
this._elementEntity = null;
}
}
get elementInput() {
return this._elementInput;
}
get elementEntity() {
return this._elementEntity;
}
get hitTestSources() {
return this._hitTestSources;
}
update(frame) {
if (this._hand) {
this._hand.update(frame);
} else {
var gripSpace = this._xrInputSource.gripSpace;
if (gripSpace) {
var 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();
}
var timestamp = now();
var 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;
}
}
var targetRayPose = frame.getPose(this._xrInputSource.targetRaySpace, this._manager._referenceSpace);
if (targetRayPose) {
this._dirtyRay = true;
this._rayLocal.origin.copy(targetRayPose.transform.position);
this._rayLocal.direction.set(0, 0, -1);
quat.copy(targetRayPose.transform.orientation);
quat.transformVector(this._rayLocal.direction, this._rayLocal.direction);
}
}
}
_updateTransforms() {
if (this._dirtyLocal) {
this._dirtyLocal = false;
this._localTransform.setTRS(this._localPosition, this._localRotation, Vec3.ONE);
}
var parent = this._manager.camera.parent;
if (parent) {
this._worldTransform.mul2(parent.getWorldTransform(), this._localTransform);
} else {
this._worldTransform.copy(this._localTransform);
}
}
_updateRayTransforms() {
var dirty = this._dirtyRay;
this._dirtyRay = false;
var parent = this._manager.camera.parent;
if (parent) {
var parentTransform = this._manager.camera.parent.getWorldTransform();
parentTransform.getTranslation(this._position);
this._rotation.setFromMat4(parentTransform);
this._rotation.transformVector(this._rayLocal.origin, this._ray.origin);
this._ray.origin.add(this._position);
this._rotation.transformVector(this._rayLocal.direction, this._ray.direction);
} else if (dirty) {
this._ray.origin.copy(this._rayLocal.origin);
this._ray.direction.copy(this._rayLocal.direction);
}
}
getPosition() {
if (!this._position) return null;
this._updateTransforms();
this._worldTransform.getTranslation(this._position);
return this._position;
}
getLocalPosition() {
return this._localPosition;
}
getRotation() {
if (!this._rotation) return null;
this._updateTransforms();
this._rotation.setFromMat4(this._worldTransform);
return this._rotation;
}
getLocalRotation() {
return this._localRotation;
}
getLinearVelocity() {
if (!this._velocitiesAvailable) {
return null;
}
return this._linearVelocity;
}
getOrigin() {
this._updateRayTransforms();
return this._ray.origin;
}
getDirection() {
this._updateRayTransforms();
return this._ray.direction;
}
hitTestStart(options) {
if (options === undefined) options = {};
options.inputSource = this;
options.profile = this._xrInputSource.profiles[0];
var callback = options.callback;
options.callback = (err, hitTestSource)=>{
if (hitTestSource) this.onHitTestSourceAdd(hitTestSource);
if (callback) callback(err, hitTestSource);
};
this._manager.hitTest.start(options);
}
onHitTestSourceAdd(hitTestSource) {
this._hitTestSources.push(hitTestSource);
this.fire('hittest:add', hitTestSource);
hitTestSource.on('result', (position, rotation, inputSource, hitTestResult)=>{
if (inputSource !== this) return;
this.fire('hittest:result', hitTestSource, position, rotation, hitTestResult);
});
hitTestSource.once('remove', ()=>{
this.onHitTestSourceRemove(hitTestSource);
this.fire('hittest:remove', hitTestSource);
});
}
onHitTestSourceRemove(hitTestSource) {
var ind = this._hitTestSources.indexOf(hitTestSource);
if (ind !== -1) this._hitTestSources.splice(ind, 1);
}
constructor(manager, xrInputSource){
super(), this._ray = new Ray(), this._rayLocal = new Ray(), this._grip = false, this._hand = null, this._velocitiesAvailable = false, this._velocitiesTimestamp = now(), this._localTransform = null, this._worldTransform = null, this._position = new Vec3(), this._rotation = new Quat(), this._localPosition = null, this._localPositionLast = null, this._localRotation = null, this._linearVelocity = null, this._dirtyLocal = true, this._dirtyRay = false, this._selecting = false, this._squeezing = false, this._elementInput = true, this._elementEntity = null, this._hitTestSources = [];
this._id = ++ids;
this._manager = manager;
this._xrInputSource = xrInputSource;
if (xrInputSource.hand) {
this._hand = new XrHand(this);
}
}
}
XrInputSource.EVENT_REMOVE = 'remove';
XrInputSource.EVENT_SELECT = 'select';
XrInputSource.EVENT_SELECTSTART = 'selectstart';
XrInputSource.EVENT_SELECTEND = 'selectend';
XrInputSource.EVENT_SQUEEZE = 'squeeze';
XrInputSource.EVENT_SQUEEZESTART = 'squeezestart';
XrInputSource.EVENT_SQUEEZEEND = 'squeezeend';
XrInputSource.EVENT_HITTESTADD = 'hittest:add';
XrInputSource.EVENT_HITTESTREMOVE = 'hittest:remove';
XrInputSource.EVENT_HITTESTRESULT = 'hittest:result';
export { XrInputSource };