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 AR hit test support #1926

Merged
merged 16 commits into from
Mar 22, 2020
2 changes: 2 additions & 0 deletions build/dependencies.txt
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@
../src/xr/xr-manager.js
../src/xr/xr-input.js
../src/xr/xr-input-source.js
../src/xr/xr-hit-test.js
../src/xr/xr-hit-test-source.js
../src/net/http.js
../src/script/script.js
../src/script/script-type.js
Expand Down
2 changes: 2 additions & 0 deletions build/externs.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ var WebAssembly = {};

// WebXR
var XRWebGLLayer = {};
var XRRay = {};
var DOMPoint = {};
7 changes: 7 additions & 0 deletions src/callbacks.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,10 @@
* @description Callback used by {@link pc.XrManager#endXr} and {@link pc.XrManager#startXr}.
* @param {Error|null} err - The Error object or null if operation was successfull.
*/

/**
* @callback pc.callbacks.XrHitTestStart
* @description Callback used by {@link pc.XrHitTest#start} and {@link pc.XrHitTest#startForInputSource}.
* @param {Error|null} err - The Error object if failed to create hit test source or null.
* @param {pc.XrHitTestSource|null} hitTestSource - object that provides access to hit results against real world geometry.
*/
117 changes: 117 additions & 0 deletions src/xr/xr-hit-test-source.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
Object.assign(pc, function () {
var poolVec3 = [];
var poolQuat = [];


/**
* @class
* @name pc.XrHitTestSource
* @augments pc.EventHandler
* @classdesc Represents XR hit test source, which provides access to hit results of real world geometry from AR session.
* @description Represents XR hit test source, which provides access to hit results of real world geometry from AR session.
* @param {pc.XrManager} manager - WebXR Manager.
* @param {object} xrHitTestSource - XRHitTestSource object that is created by WebXR API.
* @param {boolean} transient - True if XRHitTestSource created for input source profile.
* @example
* hitTestSource.on('result', function (position, rotation) {
* target.setPosition(position);
* });
*/
var XrHitTestSource = function (manager, xrHitTestSource, transient) {
pc.EventHandler.call(this);

this.manager = manager;
this._xrHitTestSource = xrHitTestSource;
this._transient = transient;
};
XrHitTestSource.prototype = Object.create(pc.EventHandler.prototype);
XrHitTestSource.prototype.constructor = XrHitTestSource;

/**
* @event
* @name pc.XrHitTestSource#remove
* @description Fired when {pc.XrHitTestSource} is removed.
* @example
* hitTestSource.once('remove', function () {
* // hit test source has been removed
* });
*/

/**
* @event
* @name pc.XrHitTestSource#result
* @description Fired when hit test source receives new results. It provides transform information that tries to match real world picked geometry.
* @param {pc.Vec3} position - Position of hit test
* @param {pc.Quat} rotation - Rotation of hit test
* @param {pc.XrInputSource|null} inputSource - If is transient hit test source, then it will provide related input source
* @example
* hitTestSource.on('result', function (position, rotation, inputSource) {
* target.setPosition(position);
* target.setRotation(rotation);
* });
*/

/**
* @function
* @name pc.XrHitTestSource#remove
* @description Stop and remove hit test source.
*/
XrHitTestSource.prototype.remove = function () {
if (! this._xrHitTestSource)
return;

var hitTestSources = this.manager.hitTest.hitTestSources;
var ind = hitTestSources.indexOf(this);
if (ind !== -1) hitTestSources.splice(ind, 1);

this.onStop();
};

XrHitTestSource.prototype.onStop = function () {
this._xrHitTestSource.cancel();
this._xrHitTestSource = null;

this.fire('remove');
this.manager.hitTest.fire('remove', this);
};

XrHitTestSource.prototype.update = function (frame) {
if (this._transient) {
var transientResults = frame.getHitTestResultsForTransientInput(this._xrHitTestSource);
for (var i = 0; i < transientResults.length; i++) {
var transientResult = transientResults[i];
var inputSource;

if (transientResult.inputSource)
inputSource = this.manager.input._getByInputSource(transientResult.inputSource);

this.updateHitResults(transientResult.results, inputSource);
}
} else {
this.updateHitResults(frame.getHitTestResults(this._xrHitTestSource));
}
};

XrHitTestSource.prototype.updateHitResults = function (results, inputSource) {
for (var i = 0; i < results.length; i++) {
var pose = results[i].getPose(this.manager._referenceSpace);

var position = poolVec3.pop();
if (! position) position = new pc.Vec3();
position.copy(pose.transform.position);

var rotation = poolQuat.pop();
if (! rotation) rotation = new pc.Quat();
rotation.copy(pose.transform.orientation);

this.fire('result', position, rotation, inputSource);
this.manager.hitTest.fire('result', this, position, rotation, inputSource);

poolVec3.push(position);
poolQuat.push(rotation);
}
};


return { XrHitTestSource: XrHitTestSource };
}());
Loading