mirror of
https://github.com/google-ar/three.ar.js.git
synced 2026-01-25 14:06:43 +00:00
1608 lines
55 KiB
JavaScript
1608 lines
55 KiB
JavaScript
/**
|
|
* @license
|
|
* three.ar.js
|
|
* Copyright (c) 2017 Google
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/**
|
|
* @license
|
|
* gl-preserve-state
|
|
* Copyright (c) 2016, Brandon Jones.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
|
|
import { Color, DoubleSide, EventDispatcher, Face3, Geometry, Math as Math$1, Matrix4, Mesh, MeshBasicMaterial, Object3D, PerspectiveCamera, Quaternion, RawShaderMaterial, RingGeometry, Vector3 } from 'three';
|
|
|
|
var global$1 = typeof global !== "undefined" ? global :
|
|
typeof self !== "undefined" ? self :
|
|
typeof window !== "undefined" ? window : {};
|
|
|
|
var noop = function noop() {};
|
|
var opacityRemap = function opacityRemap(mat) {
|
|
if (mat.opacity === 0) {
|
|
mat.opacity = 1;
|
|
}
|
|
};
|
|
var loadObj = function loadObj(objPath, materialCreator, OBJLoader) {
|
|
return new Promise(function (resolve, reject) {
|
|
var loader = new OBJLoader();
|
|
if (materialCreator) {
|
|
Object.keys(materialCreator.materials).forEach(function (k) {
|
|
return opacityRemap(materialCreator.materials[k]);
|
|
});
|
|
loader.setMaterials(materialCreator);
|
|
}
|
|
loader.load(objPath, resolve, noop, reject);
|
|
});
|
|
};
|
|
var loadMtl = function loadMtl(mtlPath, MTLLoader) {
|
|
return new Promise(function (resolve, reject) {
|
|
var loader = new MTLLoader();
|
|
loader.setTexturePath(mtlPath.substr(0, mtlPath.lastIndexOf('/') + 1));
|
|
loader.setMaterialOptions({ ignoreZeroRGBs: true });
|
|
loader.load(mtlPath, resolve, noop, reject);
|
|
});
|
|
};
|
|
|
|
var colors = ['#F44336', '#E91E63', '#9C27B0', '#673AB7', '#3F51B5', '#2196F3', '#03A9F4', '#00BCD4', '#009688', '#4CAF50', '#8BC34A', '#CDDC39', '#FFEB3B', '#FFC107', '#FF9800'].map(function (hex) {
|
|
return new Color(hex);
|
|
});
|
|
var LEARN_MORE_LINK = 'https://developers.google.com/ar/develop/web/getting-started';
|
|
var UNSUPPORTED_MESSAGE = 'This augmented reality experience requires\n WebARonARCore or WebARonARKit, experimental browsers from Google\n for Android and iOS. Learn more at the <a href="' + LEARN_MORE_LINK + '">Google Developers site</a>.';
|
|
var ARUtils = Object.create(null);
|
|
ARUtils.isTango = function (display) {
|
|
return display && display.displayName.toLowerCase().includes('tango');
|
|
};
|
|
var isTango = ARUtils.isTango;
|
|
ARUtils.isARKit = function (display) {
|
|
return display && display.displayName.toLowerCase().includes('arkit');
|
|
};
|
|
var isARKit = ARUtils.isARKit;
|
|
ARUtils.isARDisplay = function (display) {
|
|
return isARKit(display) || isTango(display);
|
|
};
|
|
var isARDisplay = ARUtils.isARDisplay;
|
|
ARUtils.getARDisplay = function () {
|
|
return new Promise(function (resolve, reject) {
|
|
if (!navigator.getVRDisplays) {
|
|
resolve(null);
|
|
return;
|
|
}
|
|
navigator.getVRDisplays().then(function (displays) {
|
|
if (!displays && displays.length === 0) {
|
|
resolve(null);
|
|
return;
|
|
}
|
|
var _iteratorNormalCompletion = true;
|
|
var _didIteratorError = false;
|
|
var _iteratorError = undefined;
|
|
try {
|
|
for (var _iterator = displays[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
var display = _step.value;
|
|
if (isARDisplay(display)) {
|
|
resolve(display);
|
|
return;
|
|
}
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError = true;
|
|
_iteratorError = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion && _iterator.return) {
|
|
_iterator.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError) {
|
|
throw _iteratorError;
|
|
}
|
|
}
|
|
}
|
|
resolve(null);
|
|
});
|
|
});
|
|
};
|
|
|
|
ARUtils.loadModel = function () {
|
|
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
return new Promise(function (resolve, reject) {
|
|
var mtlPath = config.mtlPath,
|
|
objPath = config.objPath;
|
|
var OBJLoader = config.OBJLoader || (global$1.THREE ? global$1.THREE.OBJLoader : null);
|
|
var MTLLoader = config.MTLLoader || (global$1.THREE ? global$1.THREE.MTLLoader : null);
|
|
if (!config.objPath) {
|
|
reject(new Error('`objPath` must be specified.'));
|
|
return;
|
|
}
|
|
if (!OBJLoader) {
|
|
reject(new Error('Missing OBJLoader as third argument, or window.THREE.OBJLoader existence'));
|
|
return;
|
|
}
|
|
if (config.mtlPath && !MTLLoader) {
|
|
reject(new Error('Missing MTLLoader as fourth argument, or window.THREE.MTLLoader existence'));
|
|
return;
|
|
}
|
|
var p = Promise.resolve();
|
|
if (mtlPath) {
|
|
p = loadMtl(mtlPath, MTLLoader);
|
|
}
|
|
p.then(function (materialCreator) {
|
|
if (materialCreator) {
|
|
materialCreator.preload();
|
|
}
|
|
return loadObj(objPath, materialCreator, OBJLoader);
|
|
}).then(resolve, reject);
|
|
});
|
|
};
|
|
|
|
var model = new Matrix4();
|
|
var tempPos = new Vector3();
|
|
var tempQuat = new Quaternion();
|
|
var tempScale = new Vector3();
|
|
ARUtils.placeObjectAtHit = function (object, hit) {
|
|
var easing = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
|
|
var applyOrientation = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
if (!hit || !hit.modelMatrix) {
|
|
throw new Error('placeObjectAtHit requires a VRHit object');
|
|
}
|
|
model.fromArray(hit.modelMatrix);
|
|
model.decompose(tempPos, tempQuat, tempScale);
|
|
if (easing === 1) {
|
|
object.position.copy(tempPos);
|
|
if (applyOrientation) {
|
|
object.quaternion.copy(tempQuat);
|
|
}
|
|
} else {
|
|
object.position.lerp(tempPos, easing);
|
|
if (applyOrientation) {
|
|
object.quaternion.slerp(tempQuat, easing);
|
|
}
|
|
}
|
|
};
|
|
var placeObjectAtHit = ARUtils.placeObjectAtHit;
|
|
ARUtils.getRandomPaletteColor = function () {
|
|
return colors[Math.floor(Math.random() * colors.length)];
|
|
};
|
|
var getRandomPaletteColor = ARUtils.getRandomPaletteColor;
|
|
ARUtils.displayUnsupportedMessage = function (customMessage) {
|
|
var element = document.createElement('div');
|
|
element.id = 'webgl-error-message';
|
|
element.style.fontFamily = 'monospace';
|
|
element.style.fontSize = '13px';
|
|
element.style.fontWeight = 'normal';
|
|
element.style.textAlign = 'center';
|
|
element.style.background = '#fff';
|
|
element.style.border = '1px solid black';
|
|
element.style.color = '#000';
|
|
element.style.padding = '1.5em';
|
|
element.style.width = '400px';
|
|
element.style.margin = '5em auto 0';
|
|
element.innerHTML = typeof customMessage === 'string' ? customMessage : UNSUPPORTED_MESSAGE;
|
|
document.body.appendChild(element);
|
|
};
|
|
|
|
var vertexShader = "precision mediump float;precision mediump int;uniform mat4 modelViewMatrix;uniform mat4 modelMatrix;uniform mat4 projectionMatrix;attribute vec3 position;varying vec3 vPosition;void main(){vPosition=(modelMatrix*vec4(position,1.0)).xyz;gl_Position=projectionMatrix*modelViewMatrix*vec4(position,1.0);}";
|
|
|
|
var fragmentShader = "precision highp float;varying vec3 vPosition;\n#define countX 7.0\n#define countY 4.0\n#define gridAlpha 0.75\nuniform float dotRadius;uniform vec3 dotColor;uniform vec3 lineColor;uniform vec3 backgroundColor;uniform float alpha;float Circle(in vec2 p,float r){return length(p)-r;}float Line(in vec2 p,in vec2 a,in vec2 b){vec2 pa=p-a;vec2 ba=b-a;float t=clamp(dot(pa,ba)/dot(ba,ba),0.0,1.0);vec2 pt=a+t*ba;return length(pt-p);}float Union(float a,float b){return min(a,b);}void main(){vec2 count=vec2(countX,countY);vec2 size=vec2(1.0)/count;vec2 halfSize=size*0.5;vec2 uv=mod(vPosition.xz*1.5,size)-halfSize;float dots=Circle(uv-vec2(halfSize.x,0.0),dotRadius);dots=Union(dots,Circle(uv+vec2(halfSize.x,0.0),dotRadius));dots=Union(dots,Circle(uv+vec2(0.0,halfSize.y),dotRadius));dots=Union(dots,Circle(uv-vec2(0.0,halfSize.y),dotRadius));float lines=Line(uv,vec2(0.0,halfSize.y),-vec2(halfSize.x,0.0));lines=Union(lines,Line(uv,vec2(0.0,-halfSize.y),-vec2(halfSize.x,0.0)));lines=Union(lines,Line(uv,vec2(0.0,-halfSize.y),vec2(halfSize.x,0.0)));lines=Union(lines,Line(uv,vec2(0.0,halfSize.y),vec2(halfSize.x,0.0)));lines=Union(lines,Line(uv,vec2(-halfSize.x,halfSize.y),vec2(halfSize.x,halfSize.y)));lines=Union(lines,Line(uv,vec2(-halfSize.x,-halfSize.y),vec2(halfSize.x,-halfSize.y)));lines=Union(lines,Line(uv,vec2(-halfSize.x,0.0),vec2(halfSize.x,0.0)));lines=clamp(smoothstep(0.0,0.0035,lines),0.0,1.0);dots=clamp(smoothstep(0.0,0.001,dots),0.0,1.0);float result=Union(dots,lines);gl_FragColor=vec4(mix(backgroundColor+mix(dotColor,lineColor,dots),backgroundColor,result),mix(gridAlpha,alpha,result));}";
|
|
|
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
|
|
return typeof obj;
|
|
} : function (obj) {
|
|
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var asyncGenerator = function () {
|
|
function AwaitValue(value) {
|
|
this.value = value;
|
|
}
|
|
|
|
function AsyncGenerator(gen) {
|
|
var front, back;
|
|
|
|
function send(key, arg) {
|
|
return new Promise(function (resolve, reject) {
|
|
var request = {
|
|
key: key,
|
|
arg: arg,
|
|
resolve: resolve,
|
|
reject: reject,
|
|
next: null
|
|
};
|
|
|
|
if (back) {
|
|
back = back.next = request;
|
|
} else {
|
|
front = back = request;
|
|
resume(key, arg);
|
|
}
|
|
});
|
|
}
|
|
|
|
function resume(key, arg) {
|
|
try {
|
|
var result = gen[key](arg);
|
|
var value = result.value;
|
|
|
|
if (value instanceof AwaitValue) {
|
|
Promise.resolve(value.value).then(function (arg) {
|
|
resume("next", arg);
|
|
}, function (arg) {
|
|
resume("throw", arg);
|
|
});
|
|
} else {
|
|
settle(result.done ? "return" : "normal", result.value);
|
|
}
|
|
} catch (err) {
|
|
settle("throw", err);
|
|
}
|
|
}
|
|
|
|
function settle(type, value) {
|
|
switch (type) {
|
|
case "return":
|
|
front.resolve({
|
|
value: value,
|
|
done: true
|
|
});
|
|
break;
|
|
|
|
case "throw":
|
|
front.reject(value);
|
|
break;
|
|
|
|
default:
|
|
front.resolve({
|
|
value: value,
|
|
done: false
|
|
});
|
|
break;
|
|
}
|
|
|
|
front = front.next;
|
|
|
|
if (front) {
|
|
resume(front.key, front.arg);
|
|
} else {
|
|
back = null;
|
|
}
|
|
}
|
|
|
|
this._invoke = send;
|
|
|
|
if (typeof gen.return !== "function") {
|
|
this.return = undefined;
|
|
}
|
|
}
|
|
|
|
if (typeof Symbol === "function" && Symbol.asyncIterator) {
|
|
AsyncGenerator.prototype[Symbol.asyncIterator] = function () {
|
|
return this;
|
|
};
|
|
}
|
|
|
|
AsyncGenerator.prototype.next = function (arg) {
|
|
return this._invoke("next", arg);
|
|
};
|
|
|
|
AsyncGenerator.prototype.throw = function (arg) {
|
|
return this._invoke("throw", arg);
|
|
};
|
|
|
|
AsyncGenerator.prototype.return = function (arg) {
|
|
return this._invoke("return", arg);
|
|
};
|
|
|
|
return {
|
|
wrap: function (fn) {
|
|
return function () {
|
|
return new AsyncGenerator(fn.apply(this, arguments));
|
|
};
|
|
},
|
|
await: function (value) {
|
|
return new AwaitValue(value);
|
|
}
|
|
};
|
|
}();
|
|
|
|
|
|
|
|
|
|
|
|
var classCallCheck = function (instance, Constructor) {
|
|
if (!(instance instanceof Constructor)) {
|
|
throw new TypeError("Cannot call a class as a function");
|
|
}
|
|
};
|
|
|
|
var createClass = function () {
|
|
function defineProperties(target, props) {
|
|
for (var i = 0; i < props.length; i++) {
|
|
var descriptor = props[i];
|
|
descriptor.enumerable = descriptor.enumerable || false;
|
|
descriptor.configurable = true;
|
|
if ("value" in descriptor) descriptor.writable = true;
|
|
Object.defineProperty(target, descriptor.key, descriptor);
|
|
}
|
|
}
|
|
|
|
return function (Constructor, protoProps, staticProps) {
|
|
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
|
if (staticProps) defineProperties(Constructor, staticProps);
|
|
return Constructor;
|
|
};
|
|
}();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var get = function get(object, property, receiver) {
|
|
if (object === null) object = Function.prototype;
|
|
var desc = Object.getOwnPropertyDescriptor(object, property);
|
|
|
|
if (desc === undefined) {
|
|
var parent = Object.getPrototypeOf(object);
|
|
|
|
if (parent === null) {
|
|
return undefined;
|
|
} else {
|
|
return get(parent, property, receiver);
|
|
}
|
|
} else if ("value" in desc) {
|
|
return desc.value;
|
|
} else {
|
|
var getter = desc.get;
|
|
|
|
if (getter === undefined) {
|
|
return undefined;
|
|
}
|
|
|
|
return getter.call(receiver);
|
|
}
|
|
};
|
|
|
|
var inherits = function (subClass, superClass) {
|
|
if (typeof superClass !== "function" && superClass !== null) {
|
|
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
|
|
}
|
|
|
|
subClass.prototype = Object.create(superClass && superClass.prototype, {
|
|
constructor: {
|
|
value: subClass,
|
|
enumerable: false,
|
|
writable: true,
|
|
configurable: true
|
|
}
|
|
});
|
|
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var possibleConstructorReturn = function (self, call) {
|
|
if (!self) {
|
|
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
|
}
|
|
|
|
return call && (typeof call === "object" || typeof call === "function") ? call : self;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var slicedToArray = function () {
|
|
function sliceIterator(arr, i) {
|
|
var _arr = [];
|
|
var _n = true;
|
|
var _d = false;
|
|
var _e = undefined;
|
|
|
|
try {
|
|
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
|
|
_arr.push(_s.value);
|
|
|
|
if (i && _arr.length === i) break;
|
|
}
|
|
} catch (err) {
|
|
_d = true;
|
|
_e = err;
|
|
} finally {
|
|
try {
|
|
if (!_n && _i["return"]) _i["return"]();
|
|
} finally {
|
|
if (_d) throw _e;
|
|
}
|
|
}
|
|
|
|
return _arr;
|
|
}
|
|
|
|
return function (arr, i) {
|
|
if (Array.isArray(arr)) {
|
|
return arr;
|
|
} else if (Symbol.iterator in Object(arr)) {
|
|
return sliceIterator(arr, i);
|
|
} else {
|
|
throw new TypeError("Invalid attempt to destructure non-iterable instance");
|
|
}
|
|
};
|
|
}();
|
|
|
|
var DEFAULT_MATERIAL = new RawShaderMaterial({
|
|
side: DoubleSide,
|
|
transparent: true,
|
|
uniforms: {
|
|
dotColor: {
|
|
value: new Color(0xffffff)
|
|
},
|
|
lineColor: {
|
|
value: new Color(0x707070)
|
|
},
|
|
backgroundColor: {
|
|
value: new Color(0x404040)
|
|
},
|
|
dotRadius: {
|
|
value: 0.006666666667
|
|
},
|
|
alpha: {
|
|
value: 0.4
|
|
}
|
|
},
|
|
vertexShader: vertexShader,
|
|
fragmentShader: fragmentShader
|
|
});
|
|
var ARPlanes = function (_Object3D) {
|
|
inherits(ARPlanes, _Object3D);
|
|
function ARPlanes(vrDisplay) {
|
|
classCallCheck(this, ARPlanes);
|
|
var _this = possibleConstructorReturn(this, (ARPlanes.__proto__ || Object.getPrototypeOf(ARPlanes)).call(this));
|
|
_this.addPlane_ = function (plane) {
|
|
var planeObj = _this.createPlane(plane);
|
|
if (planeObj) {
|
|
_this.add(planeObj);
|
|
_this.planes.set(plane.identifier, planeObj);
|
|
}
|
|
};
|
|
_this.removePlane_ = function (identifier) {
|
|
var existing = _this.planes.get(identifier);
|
|
if (existing) {
|
|
_this.remove(existing);
|
|
}
|
|
_this.planes.delete(identifier);
|
|
};
|
|
_this.onPlaneAdded_ = function (event) {
|
|
event.planes.forEach(function (plane) {
|
|
return _this.addPlane_(plane);
|
|
});
|
|
};
|
|
_this.onPlaneUpdated_ = function (event) {
|
|
var _iteratorNormalCompletion = true;
|
|
var _didIteratorError = false;
|
|
var _iteratorError = undefined;
|
|
try {
|
|
for (var _iterator = event.planes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
var plane = _step.value;
|
|
_this.removePlane_(plane.identifier);
|
|
_this.addPlane_(plane);
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError = true;
|
|
_iteratorError = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion && _iterator.return) {
|
|
_iterator.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError) {
|
|
throw _iteratorError;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
_this.onPlaneRemoved_ = function (event) {
|
|
var _iteratorNormalCompletion2 = true;
|
|
var _didIteratorError2 = false;
|
|
var _iteratorError2 = undefined;
|
|
try {
|
|
for (var _iterator2 = event.planes[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
|
|
var plane = _step2.value;
|
|
_this.removePlane_(plane.identifier);
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError2 = true;
|
|
_iteratorError2 = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion2 && _iterator2.return) {
|
|
_iterator2.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError2) {
|
|
throw _iteratorError2;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
_this.vrDisplay = vrDisplay;
|
|
_this.planes = new Map();
|
|
_this.materials = new Map();
|
|
return _this;
|
|
}
|
|
createClass(ARPlanes, [{
|
|
key: 'enable',
|
|
value: function enable() {
|
|
this.vrDisplay.getPlanes().forEach(this.addPlane_);
|
|
this.vrDisplay.addEventListener('planesadded', this.onPlaneAdded_);
|
|
this.vrDisplay.addEventListener('planesupdated', this.onPlaneUpdated_);
|
|
this.vrDisplay.addEventListener('planesremoved', this.onPlaneRemoved_);
|
|
}
|
|
}, {
|
|
key: 'disable',
|
|
value: function disable() {
|
|
this.vrDisplay.removeEventListener('planesadded', this.onPlaneAdded_);
|
|
this.vrDisplay.removeEventListener('planesupdated', this.onPlaneUpdated_);
|
|
this.vrDisplay.removeEventListener('planesremoved', this.onPlaneRemoved_);
|
|
var _iteratorNormalCompletion3 = true;
|
|
var _didIteratorError3 = false;
|
|
var _iteratorError3 = undefined;
|
|
try {
|
|
for (var _iterator3 = this.planes.keys()[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
|
|
var identifier = _step3.value;
|
|
this.removePlane_(identifier);
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError3 = true;
|
|
_iteratorError3 = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion3 && _iterator3.return) {
|
|
_iterator3.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError3) {
|
|
throw _iteratorError3;
|
|
}
|
|
}
|
|
}
|
|
this.materials.clear();
|
|
}
|
|
}, {
|
|
key: 'createPlane',
|
|
value: function createPlane(plane) {
|
|
if (plane.vertices.length == 0) {
|
|
return null;
|
|
}
|
|
var geo = new Geometry();
|
|
for (var pt = 0; pt < plane.vertices.length / 3; pt++) {
|
|
geo.vertices.push(new Vector3(plane.vertices[pt * 3], plane.vertices[pt * 3 + 1], plane.vertices[pt * 3 + 2]));
|
|
}
|
|
for (var face = 0; face < geo.vertices.length - 2; face++) {
|
|
geo.faces.push(new Face3(0, face + 1, face + 2));
|
|
}
|
|
var material = void 0;
|
|
if (this.materials.has(plane.identifier)) {
|
|
material = this.materials.get(plane.identifier);
|
|
} else {
|
|
var color = getRandomPaletteColor();
|
|
material = DEFAULT_MATERIAL.clone();
|
|
material.uniforms.backgroundColor.value = color;
|
|
this.materials.set(plane.identifier, material);
|
|
}
|
|
var planeObj = new Mesh(geo, material);
|
|
var mm = plane.modelMatrix;
|
|
planeObj.matrixAutoUpdate = false;
|
|
planeObj.matrix.set(mm[0], mm[4], mm[8], mm[12], mm[1], mm[5], mm[9], mm[13], mm[2], mm[6], mm[10], mm[14], mm[3], mm[7], mm[11], mm[15]);
|
|
this.add(planeObj);
|
|
return planeObj;
|
|
}
|
|
}, {
|
|
key: 'size',
|
|
value: function size() {
|
|
return this.planes.size;
|
|
}
|
|
}]);
|
|
return ARPlanes;
|
|
}(Object3D);
|
|
|
|
var DEFAULTS = {
|
|
open: true,
|
|
showLastHit: true,
|
|
showPoseStatus: true,
|
|
showPlanes: false
|
|
};
|
|
var SUCCESS_COLOR = '#00ff00';
|
|
var FAILURE_COLOR = '#ff0077';
|
|
var PLANES_POLLING_TIMER = 500;
|
|
var THROTTLE_SPEED = 500;
|
|
var cachedVRDisplayMethods = new Map();
|
|
function throttle(fn, timer, scope) {
|
|
var lastFired = void 0;
|
|
var timeout = void 0;
|
|
return function () {
|
|
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
|
args[_key] = arguments[_key];
|
|
}
|
|
var current = +new Date();
|
|
var until = void 0;
|
|
if (lastFired) {
|
|
until = lastFired + timer - current;
|
|
}
|
|
if (until == undefined || until < 0) {
|
|
lastFired = current;
|
|
fn.apply(scope, args);
|
|
} else if (until >= 0) {
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(function () {
|
|
lastFired = current;
|
|
fn.apply(scope, args);
|
|
}, until);
|
|
}
|
|
};
|
|
}
|
|
var ARDebug = function () {
|
|
function ARDebug(vrDisplay, scene, config) {
|
|
classCallCheck(this, ARDebug);
|
|
if (typeof config === 'undefined' && scene && scene.type !== 'Scene') {
|
|
config = scene;
|
|
scene = null;
|
|
}
|
|
this.config = Object.assign({}, DEFAULTS, config);
|
|
this.vrDisplay = vrDisplay;
|
|
this._view = new ARDebugView({ open: this.config.open });
|
|
if (this.config.showLastHit && this.vrDisplay.hitTest) {
|
|
this._view.addRow('hit-test', new ARDebugHitTestRow(vrDisplay));
|
|
}
|
|
if (this.config.showPoseStatus && this.vrDisplay.getFrameData) {
|
|
this._view.addRow('pose-status', new ARDebugPoseRow(vrDisplay));
|
|
}
|
|
if (this.config.showPlanes && this.vrDisplay.getPlanes) {
|
|
if (!scene) {
|
|
console.warn('ARDebug `{ showPlanes: true }` option requires ' + 'passing in a THREE.Scene as the second parameter ' + 'in the constructor.');
|
|
} else {
|
|
this._view.addRow('show-planes', new ARDebugPlanesRow(vrDisplay, scene));
|
|
}
|
|
}
|
|
}
|
|
createClass(ARDebug, [{
|
|
key: 'open',
|
|
value: function open() {
|
|
this._view.open();
|
|
}
|
|
}, {
|
|
key: 'close',
|
|
value: function close() {
|
|
this._view.close();
|
|
}
|
|
}, {
|
|
key: 'getElement',
|
|
value: function getElement() {
|
|
return this._view.getElement();
|
|
}
|
|
}]);
|
|
return ARDebug;
|
|
}();
|
|
var ARDebugView = function () {
|
|
function ARDebugView() {
|
|
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
classCallCheck(this, ARDebugView);
|
|
this.rows = new Map();
|
|
this.el = document.createElement('div');
|
|
this.el.style.backgroundColor = '#333';
|
|
this.el.style.padding = '5px';
|
|
this.el.style.fontFamily = 'Roboto, Ubuntu, Arial, sans-serif';
|
|
this.el.style.color = 'rgb(165, 165, 165)';
|
|
this.el.style.position = 'absolute';
|
|
this.el.style.right = '20px';
|
|
this.el.style.top = '0px';
|
|
this.el.style.width = '200px';
|
|
this.el.style.fontSize = '12px';
|
|
this.el.style.zIndex = 9999;
|
|
this._rowsEl = document.createElement('div');
|
|
this._rowsEl.style.transitionProperty = 'max-height';
|
|
this._rowsEl.style.transitionDuration = '0.5s';
|
|
this._rowsEl.style.transitionDelay = '0s';
|
|
this._rowsEl.style.transitionTimingFunction = 'ease-out';
|
|
this._rowsEl.style.overflow = 'hidden';
|
|
this._controls = document.createElement('div');
|
|
this._controls.style.fontSize = '13px';
|
|
this._controls.style.fontWeight = 'bold';
|
|
this._controls.style.paddingTop = '5px';
|
|
this._controls.style.textAlign = 'center';
|
|
this._controls.style.cursor = 'pointer';
|
|
this._controls.addEventListener('click', this.toggleControls.bind(this));
|
|
config.open ? this.open() : this.close();
|
|
this.el.appendChild(this._rowsEl);
|
|
this.el.appendChild(this._controls);
|
|
}
|
|
createClass(ARDebugView, [{
|
|
key: 'toggleControls',
|
|
value: function toggleControls() {
|
|
if (this._isOpen) {
|
|
this.close();
|
|
} else {
|
|
this.open();
|
|
}
|
|
}
|
|
}, {
|
|
key: 'open',
|
|
value: function open() {
|
|
this._rowsEl.style.maxHeight = '100px';
|
|
this._isOpen = true;
|
|
this._controls.textContent = 'Close ARDebug';
|
|
var _iteratorNormalCompletion = true;
|
|
var _didIteratorError = false;
|
|
var _iteratorError = undefined;
|
|
try {
|
|
for (var _iterator = this.rows[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
var _ref = _step.value;
|
|
var _ref2 = slicedToArray(_ref, 2);
|
|
var row = _ref2[1];
|
|
row.enable();
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError = true;
|
|
_iteratorError = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion && _iterator.return) {
|
|
_iterator.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError) {
|
|
throw _iteratorError;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}, {
|
|
key: 'close',
|
|
value: function close() {
|
|
this._rowsEl.style.maxHeight = '0px';
|
|
this._isOpen = false;
|
|
this._controls.textContent = 'Open ARDebug';
|
|
var _iteratorNormalCompletion2 = true;
|
|
var _didIteratorError2 = false;
|
|
var _iteratorError2 = undefined;
|
|
try {
|
|
for (var _iterator2 = this.rows[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
|
|
var _ref3 = _step2.value;
|
|
var _ref4 = slicedToArray(_ref3, 2);
|
|
var row = _ref4[1];
|
|
row.disable();
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError2 = true;
|
|
_iteratorError2 = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion2 && _iterator2.return) {
|
|
_iterator2.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError2) {
|
|
throw _iteratorError2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}, {
|
|
key: 'getElement',
|
|
value: function getElement() {
|
|
return this.el;
|
|
}
|
|
}, {
|
|
key: 'addRow',
|
|
value: function addRow(id, row) {
|
|
this.rows.set(id, row);
|
|
if (this._isOpen) {
|
|
row.enable();
|
|
}
|
|
this._rowsEl.appendChild(row.getElement());
|
|
}
|
|
}]);
|
|
return ARDebugView;
|
|
}();
|
|
var ARDebugRow = function () {
|
|
function ARDebugRow(title) {
|
|
classCallCheck(this, ARDebugRow);
|
|
this.el = document.createElement('div');
|
|
this.el.style.width = '100%';
|
|
this.el.style.borderTop = '1px solid rgb(54, 54, 54)';
|
|
this.el.style.borderBottom = '1px solid #14171A';
|
|
this.el.style.position = 'relative';
|
|
this.el.style.padding = '3px 0px';
|
|
this.el.style.overflow = 'hidden';
|
|
this._titleEl = document.createElement('span');
|
|
this._titleEl.style.fontWeight = 'bold';
|
|
this._titleEl.textContent = title;
|
|
this._dataEl = document.createElement('span');
|
|
this._dataEl.style.position = 'absolute';
|
|
this._dataEl.style.left = '40px';
|
|
this._dataElText = document.createTextNode('');
|
|
this._dataEl.appendChild(this._dataElText);
|
|
this.el.appendChild(this._titleEl);
|
|
this.el.appendChild(this._dataEl);
|
|
this._throttledWriteToDOM = throttle(this._writeToDOM, THROTTLE_SPEED, this);
|
|
}
|
|
createClass(ARDebugRow, [{
|
|
key: 'enable',
|
|
value: function enable() {
|
|
throw new Error('Implement in child class');
|
|
}
|
|
}, {
|
|
key: 'disable',
|
|
value: function disable() {
|
|
throw new Error('Implement in child class');
|
|
}
|
|
}, {
|
|
key: 'getElement',
|
|
value: function getElement() {
|
|
return this.el;
|
|
}
|
|
}, {
|
|
key: 'update',
|
|
value: function update(value, isSuccess, renderImmediately) {
|
|
if (renderImmediately) {
|
|
this._writeToDOM(value, isSuccess);
|
|
} else {
|
|
this._throttledWriteToDOM(value, isSuccess);
|
|
}
|
|
}
|
|
}, {
|
|
key: '_writeToDOM',
|
|
value: function _writeToDOM(value, isSuccess) {
|
|
this._dataElText.nodeValue = value;
|
|
this._dataEl.style.color = isSuccess ? SUCCESS_COLOR : FAILURE_COLOR;
|
|
}
|
|
}]);
|
|
return ARDebugRow;
|
|
}();
|
|
var ARDebugHitTestRow = function (_ARDebugRow) {
|
|
inherits(ARDebugHitTestRow, _ARDebugRow);
|
|
function ARDebugHitTestRow(vrDisplay) {
|
|
classCallCheck(this, ARDebugHitTestRow);
|
|
var _this = possibleConstructorReturn(this, (ARDebugHitTestRow.__proto__ || Object.getPrototypeOf(ARDebugHitTestRow)).call(this, 'Hit'));
|
|
_this.vrDisplay = vrDisplay;
|
|
_this._onHitTest = _this._onHitTest.bind(_this);
|
|
_this._nativeHitTest = cachedVRDisplayMethods.get('hitTest') || _this.vrDisplay.hitTest;
|
|
cachedVRDisplayMethods.set('hitTest', _this._nativeHitTest);
|
|
_this._didPreviouslyHit = null;
|
|
return _this;
|
|
}
|
|
createClass(ARDebugHitTestRow, [{
|
|
key: 'enable',
|
|
value: function enable() {
|
|
this.vrDisplay.hitTest = this._onHitTest;
|
|
}
|
|
}, {
|
|
key: 'disable',
|
|
value: function disable() {
|
|
this.vrDisplay.hitTest = this._nativeHitTest;
|
|
}
|
|
}, {
|
|
key: '_hitToString',
|
|
value: function _hitToString(hit) {
|
|
var mm = hit.modelMatrix;
|
|
return mm[12].toFixed(2) + ', ' + mm[13].toFixed(2) + ', ' + mm[14].toFixed(2);
|
|
}
|
|
}, {
|
|
key: '_onHitTest',
|
|
value: function _onHitTest(x, y) {
|
|
var hits = this._nativeHitTest.call(this.vrDisplay, x, y);
|
|
var t = (parseInt(performance.now(), 10) / 1000).toFixed(1);
|
|
var didHit = hits && hits.length;
|
|
var value = (didHit ? this._hitToString(hits[0]) : 'MISS') + ' @ ' + t + 's';
|
|
this.update(value, didHit, didHit !== this._didPreviouslyHit);
|
|
this._didPreviouslyHit = didHit;
|
|
return hits;
|
|
}
|
|
}]);
|
|
return ARDebugHitTestRow;
|
|
}(ARDebugRow);
|
|
var ARDebugPoseRow = function (_ARDebugRow2) {
|
|
inherits(ARDebugPoseRow, _ARDebugRow2);
|
|
function ARDebugPoseRow(vrDisplay) {
|
|
classCallCheck(this, ARDebugPoseRow);
|
|
var _this2 = possibleConstructorReturn(this, (ARDebugPoseRow.__proto__ || Object.getPrototypeOf(ARDebugPoseRow)).call(this, 'Pose'));
|
|
_this2.vrDisplay = vrDisplay;
|
|
_this2._onGetFrameData = _this2._onGetFrameData.bind(_this2);
|
|
_this2._nativeGetFrameData = cachedVRDisplayMethods.get('getFrameData') || _this2.vrDisplay.getFrameData;
|
|
cachedVRDisplayMethods.set('getFrameData', _this2._nativeGetFrameData);
|
|
_this2.update('Looking for position...', false, true);
|
|
_this2._initialPose = false;
|
|
return _this2;
|
|
}
|
|
createClass(ARDebugPoseRow, [{
|
|
key: 'enable',
|
|
value: function enable() {
|
|
this.vrDisplay.getFrameData = this._onGetFrameData;
|
|
}
|
|
}, {
|
|
key: 'disable',
|
|
value: function disable() {
|
|
this.vrDisplay.getFrameData = this._nativeGetFrameData;
|
|
}
|
|
}, {
|
|
key: '_poseToString',
|
|
value: function _poseToString(pose) {
|
|
return pose[0].toFixed(2) + ', ' + pose[1].toFixed(2) + ', ' + pose[2].toFixed(2);
|
|
}
|
|
}, {
|
|
key: '_onGetFrameData',
|
|
value: function _onGetFrameData(frameData) {
|
|
var results = this._nativeGetFrameData.call(this.vrDisplay, frameData);
|
|
var pose = frameData && frameData.pose && frameData.pose.position;
|
|
var isValidPose = pose && typeof pose[0] === 'number' && typeof pose[1] === 'number' && typeof pose[2] === 'number' && !(pose[0] === 0 && pose[1] === 0 && pose[2] === 0);
|
|
if (!this._initialPose && !isValidPose) {
|
|
return results;
|
|
}
|
|
var renderImmediately = isValidPose !== this._lastPoseValid;
|
|
if (isValidPose) {
|
|
this.update(this._poseToString(pose), true, renderImmediately);
|
|
} else if (!isValidPose && this._lastPoseValid !== false) {
|
|
this.update('Position lost', false, renderImmediately);
|
|
}
|
|
this._lastPoseValid = isValidPose;
|
|
this._initialPose = true;
|
|
return results;
|
|
}
|
|
}]);
|
|
return ARDebugPoseRow;
|
|
}(ARDebugRow);
|
|
var ARDebugPlanesRow = function (_ARDebugRow3) {
|
|
inherits(ARDebugPlanesRow, _ARDebugRow3);
|
|
function ARDebugPlanesRow(vrDisplay, scene) {
|
|
classCallCheck(this, ARDebugPlanesRow);
|
|
var _this3 = possibleConstructorReturn(this, (ARDebugPlanesRow.__proto__ || Object.getPrototypeOf(ARDebugPlanesRow)).call(this, 'Planes'));
|
|
_this3.vrDisplay = vrDisplay;
|
|
_this3.planes = new ARPlanes(_this3.vrDisplay);
|
|
_this3._onPoll = _this3._onPoll.bind(_this3);
|
|
_this3.update('Looking for planes...', false, true);
|
|
if (scene) {
|
|
scene.add(_this3.planes);
|
|
}
|
|
return _this3;
|
|
}
|
|
createClass(ARDebugPlanesRow, [{
|
|
key: 'enable',
|
|
value: function enable() {
|
|
if (this._timer) {
|
|
this.disable();
|
|
}
|
|
this._timer = setInterval(this._onPoll, PLANES_POLLING_TIMER);
|
|
this.planes.enable();
|
|
}
|
|
}, {
|
|
key: 'disable',
|
|
value: function disable() {
|
|
clearInterval(this._timer);
|
|
this._timer = null;
|
|
this.planes.disable();
|
|
}
|
|
}, {
|
|
key: '_planesToString',
|
|
value: function _planesToString(count) {
|
|
return count + ' plane' + (count === 1 ? '' : 's') + ' found';
|
|
}
|
|
}, {
|
|
key: '_onPoll',
|
|
value: function _onPoll() {
|
|
var planeCount = this.planes.size();
|
|
if (this._lastPlaneCount !== planeCount) {
|
|
this.update(this._planesToString(planeCount), planeCount > 0, true);
|
|
}
|
|
this._lastPlaneCount = planeCount;
|
|
}
|
|
}]);
|
|
return ARDebugPlanesRow;
|
|
}(ARDebugRow);
|
|
|
|
var frameData = void 0;
|
|
var ARPerspectiveCamera = function (_PerspectiveCamera) {
|
|
inherits(ARPerspectiveCamera, _PerspectiveCamera);
|
|
function ARPerspectiveCamera(vrDisplay, fov, aspect, near, far) {
|
|
classCallCheck(this, ARPerspectiveCamera);
|
|
var _this = possibleConstructorReturn(this, (ARPerspectiveCamera.__proto__ || Object.getPrototypeOf(ARPerspectiveCamera)).call(this, fov, aspect, near, far));
|
|
_this.isARPerpsectiveCamera = true;
|
|
_this.vrDisplay = vrDisplay;
|
|
_this.updateProjectionMatrix();
|
|
if (!vrDisplay || !vrDisplay.capabilities.hasPassThroughCamera) {
|
|
console.warn('ARPerspectiveCamera does not a VRDisplay with\n a pass through camera. Using supplied values and defaults\n instead of device camera intrinsics');
|
|
}
|
|
return _this;
|
|
}
|
|
createClass(ARPerspectiveCamera, [{
|
|
key: 'updateProjectionMatrix',
|
|
value: function updateProjectionMatrix() {
|
|
var projMatrix = this.getProjectionMatrix();
|
|
if (!projMatrix) {
|
|
get(ARPerspectiveCamera.prototype.__proto__ || Object.getPrototypeOf(ARPerspectiveCamera.prototype), 'updateProjectionMatrix', this).call(this);
|
|
return;
|
|
}
|
|
this.projectionMatrix.fromArray(projMatrix);
|
|
}
|
|
}, {
|
|
key: 'getProjectionMatrix',
|
|
value: function getProjectionMatrix() {
|
|
if (this.vrDisplay && this.vrDisplay.getFrameData) {
|
|
if (!frameData) {
|
|
frameData = new VRFrameData();
|
|
}
|
|
this.vrDisplay.getFrameData(frameData);
|
|
return frameData.leftProjectionMatrix;
|
|
}
|
|
return null;
|
|
}
|
|
}]);
|
|
return ARPerspectiveCamera;
|
|
}(PerspectiveCamera);
|
|
|
|
var ARReticle = function (_Mesh) {
|
|
inherits(ARReticle, _Mesh);
|
|
function ARReticle(vrDisplay) {
|
|
var innerRadius = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.02;
|
|
var outerRadius = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0.05;
|
|
var color = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0xff0077;
|
|
var easing = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0.25;
|
|
classCallCheck(this, ARReticle);
|
|
var geometry = new RingGeometry(innerRadius, outerRadius, 36, 64);
|
|
var material = new MeshBasicMaterial({ color: color });
|
|
geometry.applyMatrix(new Matrix4().makeRotationX(Math$1.degToRad(-90)));
|
|
var _this = possibleConstructorReturn(this, (ARReticle.__proto__ || Object.getPrototypeOf(ARReticle)).call(this, geometry, material));
|
|
_this.visible = false;
|
|
_this.easing = easing;
|
|
_this.applyOrientation = true;
|
|
_this.vrDisplay = vrDisplay;
|
|
_this._planeDir = new Vector3();
|
|
return _this;
|
|
}
|
|
createClass(ARReticle, [{
|
|
key: 'update',
|
|
value: function update() {
|
|
var x = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0.5;
|
|
var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.5;
|
|
if (!this.vrDisplay || !this.vrDisplay.hitTest) {
|
|
return;
|
|
}
|
|
var hit = this.vrDisplay.hitTest(x, y);
|
|
if (hit && hit.length > 0) {
|
|
this.visible = true;
|
|
placeObjectAtHit(this, hit[0], this.applyOrientation, this.easing);
|
|
}
|
|
}
|
|
}]);
|
|
return ARReticle;
|
|
}(Mesh);
|
|
|
|
var vertexSource = "attribute vec3 aVertexPosition;attribute vec2 aTextureCoord;varying vec2 vTextureCoord;void main(void){gl_Position=vec4(aVertexPosition,1.0);vTextureCoord=aTextureCoord;}";
|
|
|
|
var fragmentSource = "precision mediump float;varying vec2 vTextureCoord;uniform sampler2D uSampler;void main(void){gl_FragColor=texture2D(uSampler,vTextureCoord);}";
|
|
|
|
var fragmentSourceOES = "\n#extension GL_OES_EGL_image_external : require\nprecision mediump float;varying vec2 vTextureCoord;uniform samplerExternalOES uSampler;void main(void){gl_FragColor=texture2D(uSampler,vTextureCoord);}";
|
|
|
|
function WGLUPreserveGLState(gl, bindings, callback) {
|
|
if (!bindings) {
|
|
callback(gl);
|
|
return;
|
|
}
|
|
var boundValues = [];
|
|
var activeTexture = null;
|
|
for (var i = 0; i < bindings.length; ++i) {
|
|
var binding = bindings[i];
|
|
switch (binding) {
|
|
case gl.TEXTURE_BINDING_2D:
|
|
case gl.TEXTURE_BINDING_CUBE_MAP:
|
|
var textureUnit = bindings[++i];
|
|
if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) {
|
|
console.error("TEXTURE_BINDING_2D or TEXTURE_BINDING_CUBE_MAP must be followed by a valid texture unit");
|
|
boundValues.push(null, null);
|
|
break;
|
|
}
|
|
if (!activeTexture) {
|
|
activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE);
|
|
}
|
|
gl.activeTexture(textureUnit);
|
|
boundValues.push(gl.getParameter(binding), null);
|
|
break;
|
|
case gl.ACTIVE_TEXTURE:
|
|
activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE);
|
|
boundValues.push(null);
|
|
break;
|
|
default:
|
|
boundValues.push(gl.getParameter(binding));
|
|
break;
|
|
}
|
|
}
|
|
callback(gl);
|
|
for (var i = 0; i < bindings.length; ++i) {
|
|
var binding = bindings[i];
|
|
var boundValue = boundValues[i];
|
|
switch (binding) {
|
|
case gl.ACTIVE_TEXTURE:
|
|
break;
|
|
case gl.ARRAY_BUFFER_BINDING:
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, boundValue);
|
|
break;
|
|
case gl.COLOR_CLEAR_VALUE:
|
|
gl.clearColor(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
|
|
break;
|
|
case gl.COLOR_WRITEMASK:
|
|
gl.colorMask(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
|
|
break;
|
|
case gl.CURRENT_PROGRAM:
|
|
gl.useProgram(boundValue);
|
|
break;
|
|
case gl.ELEMENT_ARRAY_BUFFER_BINDING:
|
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, boundValue);
|
|
break;
|
|
case gl.FRAMEBUFFER_BINDING:
|
|
gl.bindFramebuffer(gl.FRAMEBUFFER, boundValue);
|
|
break;
|
|
case gl.RENDERBUFFER_BINDING:
|
|
gl.bindRenderbuffer(gl.RENDERBUFFER, boundValue);
|
|
break;
|
|
case gl.TEXTURE_BINDING_2D:
|
|
var textureUnit = bindings[++i];
|
|
if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31)
|
|
break;
|
|
gl.activeTexture(textureUnit);
|
|
gl.bindTexture(gl.TEXTURE_2D, boundValue);
|
|
break;
|
|
case gl.TEXTURE_BINDING_CUBE_MAP:
|
|
var textureUnit = bindings[++i];
|
|
if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31)
|
|
break;
|
|
gl.activeTexture(textureUnit);
|
|
gl.bindTexture(gl.TEXTURE_CUBE_MAP, boundValue);
|
|
break;
|
|
case gl.VIEWPORT:
|
|
gl.viewport(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
|
|
break;
|
|
case gl.BLEND:
|
|
case gl.CULL_FACE:
|
|
case gl.DEPTH_TEST:
|
|
case gl.SCISSOR_TEST:
|
|
case gl.STENCIL_TEST:
|
|
if (boundValue) {
|
|
gl.enable(binding);
|
|
} else {
|
|
gl.disable(binding);
|
|
}
|
|
break;
|
|
default:
|
|
console.log("No GL restore behavior for 0x" + binding.toString(16));
|
|
break;
|
|
}
|
|
if (activeTexture) {
|
|
gl.activeTexture(activeTexture);
|
|
}
|
|
}
|
|
}
|
|
var glPreserveState = WGLUPreserveGLState;
|
|
|
|
function getShader(gl, str, type) {
|
|
var shader = void 0;
|
|
if (type == 'fragment') {
|
|
shader = gl.createShader(gl.FRAGMENT_SHADER);
|
|
} else if (type == 'vertex') {
|
|
shader = gl.createShader(gl.VERTEX_SHADER);
|
|
} else {
|
|
return null;
|
|
}
|
|
gl.shaderSource(shader, str);
|
|
gl.compileShader(shader);
|
|
var result = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
|
|
if (!result) {
|
|
alert(gl.getShaderInfoLog(shader));
|
|
return null;
|
|
}
|
|
return shader;
|
|
}
|
|
function getProgram(gl, vs, fs) {
|
|
var vertexShader = getShader(gl, vs, 'vertex');
|
|
var fragmentShader = getShader(gl, fs, 'fragment');
|
|
if (!fragmentShader) {
|
|
return null;
|
|
}
|
|
var shaderProgram = gl.createProgram();
|
|
gl.attachShader(shaderProgram, vertexShader);
|
|
gl.attachShader(shaderProgram, fragmentShader);
|
|
gl.linkProgram(shaderProgram);
|
|
var result = gl.getProgramParameter(shaderProgram, gl.LINK_STATUS);
|
|
if (!result) {
|
|
alert('Could not initialise arview shaders');
|
|
}
|
|
return shaderProgram;
|
|
}
|
|
function combineOrientations(screenOrientation, seeThroughCameraOrientation) {
|
|
var seeThroughCameraOrientationIndex = 0;
|
|
switch (seeThroughCameraOrientation) {
|
|
case 90:
|
|
seeThroughCameraOrientationIndex = 1;
|
|
break;
|
|
case 180:
|
|
seeThroughCameraOrientationIndex = 2;
|
|
break;
|
|
case 270:
|
|
seeThroughCameraOrientationIndex = 3;
|
|
break;
|
|
default:
|
|
seeThroughCameraOrientationIndex = 0;
|
|
break;
|
|
}
|
|
var screenOrientationIndex = 0;
|
|
switch (screenOrientation) {
|
|
case 90:
|
|
screenOrientationIndex = 1;
|
|
break;
|
|
case 180:
|
|
screenOrientationIndex = 2;
|
|
break;
|
|
case 270:
|
|
screenOrientationIndex = 3;
|
|
break;
|
|
default:
|
|
screenOrientationIndex = 0;
|
|
break;
|
|
}
|
|
var ret = screenOrientationIndex - seeThroughCameraOrientationIndex;
|
|
if (ret < 0) {
|
|
ret += 4;
|
|
}
|
|
return ret % 4;
|
|
}
|
|
var ARVideoRenderer = function () {
|
|
function ARVideoRenderer(vrDisplay, gl) {
|
|
classCallCheck(this, ARVideoRenderer);
|
|
this.vrDisplay = vrDisplay;
|
|
this.gl = gl;
|
|
if (this.vrDisplay) {
|
|
this.passThroughCamera = vrDisplay.getPassThroughCamera();
|
|
if (this.passThroughCamera instanceof Image) {
|
|
this.textureTarget = gl.TEXTURE_2D;
|
|
this.fragmentSource = fragmentSource;
|
|
} else {
|
|
this.textureTarget = gl.TEXTURE_EXTERNAL_OES;
|
|
this.fragmentSource = fragmentSourceOES;
|
|
}
|
|
this.program = getProgram(gl, vertexSource, this.fragmentSource);
|
|
}
|
|
gl.useProgram(this.program);
|
|
this.vertexPositionAttribute = gl.getAttribLocation(this.program, 'aVertexPosition');
|
|
this.textureCoordAttribute = gl.getAttribLocation(this.program, 'aTextureCoord');
|
|
this.samplerUniform = gl.getUniformLocation(this.program, 'uSampler');
|
|
this.vertexPositionBuffer = gl.createBuffer();
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexPositionBuffer);
|
|
var vertices = [-1.0, 1.0, 0.0, -1.0, -1.0, 0.0, 1.0, 1.0, 0.0, 1.0, -1.0, 0.0];
|
|
var f32Vertices = new Float32Array(vertices);
|
|
gl.bufferData(gl.ARRAY_BUFFER, f32Vertices, gl.STATIC_DRAW);
|
|
this.vertexPositionBuffer.itemSize = 3;
|
|
this.vertexPositionBuffer.numItems = 12;
|
|
this.textureCoordBuffer = gl.createBuffer();
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.textureCoordBuffer);
|
|
var textureCoords = null;
|
|
if (this.vrDisplay) {
|
|
var u = window.WebARonARKitSendsCameraFrames ? 1.0 : this.passThroughCamera.width / this.passThroughCamera.textureWidth;
|
|
var v = window.WebARonARKitSendsCameraFrames ? 1.0 : this.passThroughCamera.height / this.passThroughCamera.textureHeight;
|
|
textureCoords = [[0.0, 0.0, 0.0, v, u, 0.0, u, v], [u, 0.0, 0.0, 0.0, u, v, 0.0, v], [u, v, u, 0.0, 0.0, v, 0.0, 0.0], [0.0, v, u, v, 0.0, 0.0, u, 0.0]];
|
|
} else {
|
|
textureCoords = [[0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0], [1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0], [1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0], [0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0]];
|
|
}
|
|
this.f32TextureCoords = [];
|
|
for (var i = 0; i < textureCoords.length; i++) {
|
|
this.f32TextureCoords.push(new Float32Array(textureCoords[i]));
|
|
}
|
|
this.combinedOrientation = combineOrientations(screen.orientation ? screen.orientation.angle : window.orientation, this.passThroughCamera.orientation);
|
|
gl.bufferData(gl.ARRAY_BUFFER, this.f32TextureCoords[this.combinedOrientation], gl.STATIC_DRAW);
|
|
this.textureCoordBuffer.itemSize = 2;
|
|
this.textureCoordBuffer.numItems = 8;
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
this.indexBuffer = gl.createBuffer();
|
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
|
|
var indices = [0, 1, 2, 2, 1, 3];
|
|
var ui16Indices = new Uint16Array(indices);
|
|
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, ui16Indices, gl.STATIC_DRAW);
|
|
this.indexBuffer.itemSize = 1;
|
|
this.indexBuffer.numItems = 6;
|
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
|
|
this.texture = gl.createTexture();
|
|
gl.useProgram(null);
|
|
this.projectionMatrix = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
|
|
this.mvMatrix = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
|
|
return this;
|
|
}
|
|
createClass(ARVideoRenderer, [{
|
|
key: 'render',
|
|
value: function render() {
|
|
var _this = this;
|
|
var gl = this.gl;
|
|
var bindings = [gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING, gl.CURRENT_PROGRAM, gl.TEXTURE_BINDING_2D];
|
|
glPreserveState(gl, bindings, function () {
|
|
if (_this.passThroughCamera.textureWidth === 0 || _this.passThroughCamera.textureHeight === 0) {
|
|
return;
|
|
}
|
|
var previousFlipY = gl.getParameter(gl.UNPACK_FLIP_Y_WEBGL);
|
|
var previousWinding = gl.getParameter(gl.FRONT_FACE);
|
|
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
|
|
gl.frontFace(gl.CCW);
|
|
gl.useProgram(_this.program);
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, _this.vertexPositionBuffer);
|
|
gl.enableVertexAttribArray(_this.vertexPositionAttribute);
|
|
gl.vertexAttribPointer(_this.vertexPositionAttribute, _this.vertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, _this.textureCoordBuffer);
|
|
var combinedOrientation = combineOrientations(screen.orientation ? screen.orientation.angle : window.orientation, _this.passThroughCamera.orientation);
|
|
if (combinedOrientation !== _this.combinedOrientation) {
|
|
_this.combinedOrientation = combinedOrientation;
|
|
gl.bufferData(gl.ARRAY_BUFFER, _this.f32TextureCoords[_this.combinedOrientation], gl.STATIC_DRAW);
|
|
}
|
|
gl.enableVertexAttribArray(_this.textureCoordAttribute);
|
|
gl.vertexAttribPointer(_this.textureCoordAttribute, _this.textureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);
|
|
gl.activeTexture(gl.TEXTURE0);
|
|
gl.bindTexture(_this.textureTarget, _this.texture);
|
|
gl.texImage2D(_this.textureTarget, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, _this.passThroughCamera);
|
|
gl.uniform1i(_this.samplerUniform, 0);
|
|
if (window.WebARonARKitSendsCameraFrames) {
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
}
|
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, _this.indexBuffer);
|
|
gl.drawElements(gl.TRIANGLES, _this.indexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
|
|
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, previousFlipY);
|
|
gl.frontFace(previousWinding);
|
|
});
|
|
}
|
|
}]);
|
|
return ARVideoRenderer;
|
|
}();
|
|
var ARView = function () {
|
|
function ARView(vrDisplay, renderer) {
|
|
classCallCheck(this, ARView);
|
|
this.vrDisplay = vrDisplay;
|
|
if (isARKit(this.vrDisplay) && !window.WebARonARKitSendsCameraFrames) {
|
|
return;
|
|
}
|
|
this.renderer = renderer;
|
|
this.gl = renderer.context;
|
|
this.videoRenderer = new ARVideoRenderer(vrDisplay, this.gl);
|
|
this.width = window.innerWidth;
|
|
this.height = window.innerHeight;
|
|
window.addEventListener('resize', this.onWindowResize.bind(this), false);
|
|
}
|
|
createClass(ARView, [{
|
|
key: 'onWindowResize',
|
|
value: function onWindowResize() {
|
|
this.width = window.innerWidth;
|
|
this.height = window.innerHeight;
|
|
}
|
|
}, {
|
|
key: 'render',
|
|
value: function render() {
|
|
if (isARKit(this.vrDisplay) && !window.WebARonARKitSendsCameraFrames) {
|
|
return;
|
|
}
|
|
var gl = this.gl;
|
|
var dpr = window.devicePixelRatio;
|
|
var width = this.width * dpr;
|
|
var height = this.height * dpr;
|
|
if (gl.viewportWidth !== width) {
|
|
gl.viewportWidth = width;
|
|
}
|
|
if (gl.viewportHeight !== height) {
|
|
gl.viewportHeight = height;
|
|
}
|
|
this.gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
|
|
this.videoRenderer.render();
|
|
}
|
|
}]);
|
|
return ARView;
|
|
}();
|
|
|
|
var ARAnchorManager = function (_EventDispatcher) {
|
|
inherits(ARAnchorManager, _EventDispatcher);
|
|
function ARAnchorManager(vrDisplay) {
|
|
classCallCheck(this, ARAnchorManager);
|
|
var _this = possibleConstructorReturn(this, (ARAnchorManager.__proto__ || Object.getPrototypeOf(ARAnchorManager)).call(this));
|
|
if (!(vrDisplay instanceof window.VRDisplay)) {
|
|
throw new Error('A correct VRDisplay instance is required to ' + 'initialize an ARAnchorManager.');
|
|
}
|
|
if (typeof vrDisplay.getAnchors !== 'function') {
|
|
throw new Error('VRDisplay does not support anchors. Upgrade ' + 'to latest AR browser to get anchor support.');
|
|
}
|
|
_this.vrDisplay_ = vrDisplay;
|
|
_this.anchorsToObject3Ds_ = new Map();
|
|
_this.object3DsToAnchors_ = new Map();
|
|
_this.vrDisplay_.addEventListener('anchorsupdated', function (event) {
|
|
return _this.onAnchorsUpdated_(event);
|
|
});
|
|
_this.scale_ = new Vector3();
|
|
_this.matrix_ = new Matrix4();
|
|
return _this;
|
|
}
|
|
createClass(ARAnchorManager, [{
|
|
key: 'add',
|
|
value: function add(object3d) {
|
|
if (!(object3d instanceof Object3D)) {
|
|
throw new Error('Invalid Object3D trying to add an anchor');
|
|
}
|
|
if (this.object3DsToAnchors_.has(object3d)) {
|
|
return this;
|
|
}
|
|
this.scale_.set(1, 1, 1);
|
|
this.matrix_.compose(object3d.position, object3d.quaternion, this.scale_);
|
|
var anchor = this.vrDisplay_.addAnchor(this.matrix_.elements);
|
|
this.anchorsToObject3Ds_.set(anchor, object3d);
|
|
this.object3DsToAnchors_.set(object3d, anchor);
|
|
return this;
|
|
}
|
|
}, {
|
|
key: 'remove',
|
|
value: function remove(object3d) {
|
|
if (!(object3d instanceof Object3D)) {
|
|
throw new Error('Invalid Object3D trying to remove anchor');
|
|
}
|
|
var anchor = this.object3DsToAnchors_.get(object3d);
|
|
if (!anchor) {
|
|
return false;
|
|
}
|
|
this.anchorsToObject3Ds_.delete(anchor);
|
|
this.object3DsToAnchors_.delete(object3d);
|
|
this.vrDisplay_.removeAnchor(anchor);
|
|
return true;
|
|
}
|
|
}, {
|
|
key: 'onAnchorsUpdated_',
|
|
value: function onAnchorsUpdated_(event) {
|
|
var updatedObject3Ds = [];
|
|
var _iteratorNormalCompletion = true;
|
|
var _didIteratorError = false;
|
|
var _iteratorError = undefined;
|
|
try {
|
|
for (var _iterator = event.anchors[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
var anchor = _step.value;
|
|
var object3d = this.anchorsToObject3Ds_.get(anchor);
|
|
if (!object3d) {
|
|
continue;
|
|
}
|
|
object3d.matrix.fromArray(anchor.modelMatrix);
|
|
object3d.matrix.decompose(object3d.position, object3d.quaternion, this.scale_);
|
|
updatedObject3Ds.push(object3d);
|
|
}
|
|
} catch (err) {
|
|
_didIteratorError = true;
|
|
_iteratorError = err;
|
|
} finally {
|
|
try {
|
|
if (!_iteratorNormalCompletion && _iterator.return) {
|
|
_iterator.return();
|
|
}
|
|
} finally {
|
|
if (_didIteratorError) {
|
|
throw _iteratorError;
|
|
}
|
|
}
|
|
}
|
|
this.dispatchEvent({ type: 'anchorsupdated', anchors: updatedObject3Ds });
|
|
}
|
|
}]);
|
|
return ARAnchorManager;
|
|
}(EventDispatcher);
|
|
|
|
(function () {
|
|
if (window.webarSpeechRecognitionInstance) {
|
|
var addEventHandlingToObject = function addEventHandlingToObject(object) {
|
|
object.listeners = {};
|
|
object.addEventListener = function (eventType, callback) {
|
|
if (!callback) {
|
|
return this;
|
|
}
|
|
var listeners = this.listeners[eventType];
|
|
if (!listeners) {
|
|
this.listeners[eventType] = listeners = [];
|
|
}
|
|
if (listeners.indexOf(callback) < 0) {
|
|
listeners.push(callback);
|
|
}
|
|
return this;
|
|
};
|
|
object.removeEventListener = function (eventType, callback) {
|
|
if (!callback) {
|
|
return this;
|
|
}
|
|
var listeners = this.listeners[eventType];
|
|
if (listeners) {
|
|
var i = listeners.indexOf(callback);
|
|
if (i >= 0) {
|
|
this.listeners[eventType] = listeners.splice(i, 1);
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
object.callEventListeners = function (eventType, event) {
|
|
if (!event) {
|
|
event = { target: this };
|
|
}
|
|
if (!event.target) {
|
|
event.target = this;
|
|
}
|
|
event.type = eventType;
|
|
var onEventType = 'on' + eventType;
|
|
if (typeof this[onEventType] === 'function') {
|
|
this[onEventType](event);
|
|
}
|
|
var listeners = this.listeners[eventType];
|
|
if (listeners) {
|
|
for (var i = 0; i < listeners.length; i++) {
|
|
var typeofListener = _typeof(listeners[i]);
|
|
if (typeofListener === 'object') {
|
|
listeners[i].handleEvent(event);
|
|
} else if (typeofListener === 'function') {
|
|
listeners[i](event);
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
};
|
|
addEventHandlingToObject(window.webarSpeechRecognitionInstance);
|
|
window.webkitSpeechRecognition = function () {
|
|
return window.webarSpeechRecognitionInstance;
|
|
};
|
|
}
|
|
})();
|
|
|
|
if (typeof window !== 'undefined' && _typeof(window.THREE) === 'object') {
|
|
window.THREE.ARDebug = ARDebug;
|
|
window.THREE.ARPerspectiveCamera = ARPerspectiveCamera;
|
|
window.THREE.ARReticle = ARReticle;
|
|
window.THREE.ARUtils = ARUtils;
|
|
window.THREE.ARView = ARView;
|
|
window.THREE.ARAnchorManager = ARAnchorManager;
|
|
}
|
|
|
|
export { ARDebug, ARPerspectiveCamera, ARReticle, ARUtils, ARView, ARAnchorManager };
|