|
@@ -219,10 +219,8 @@
|
|
/**
|
|
/**
|
|
* https://github.com/mrdoob/eventdispatcher.js/
|
|
* https://github.com/mrdoob/eventdispatcher.js/
|
|
*/
|
|
*/
|
|
- function EventDispatcher() {}
|
|
|
|
-
|
|
|
|
- Object.assign(EventDispatcher.prototype, {
|
|
|
|
- addEventListener: function (type, listener) {
|
|
|
|
|
|
+ class EventDispatcher {
|
|
|
|
+ addEventListener(type, listener) {
|
|
if (this._listeners === undefined) this._listeners = {};
|
|
if (this._listeners === undefined) this._listeners = {};
|
|
const listeners = this._listeners;
|
|
const listeners = this._listeners;
|
|
|
|
|
|
@@ -233,13 +231,15 @@
|
|
if (listeners[type].indexOf(listener) === -1) {
|
|
if (listeners[type].indexOf(listener) === -1) {
|
|
listeners[type].push(listener);
|
|
listeners[type].push(listener);
|
|
}
|
|
}
|
|
- },
|
|
|
|
- hasEventListener: function (type, listener) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ hasEventListener(type, listener) {
|
|
if (this._listeners === undefined) return false;
|
|
if (this._listeners === undefined) return false;
|
|
const listeners = this._listeners;
|
|
const listeners = this._listeners;
|
|
return listeners[type] !== undefined && listeners[type].indexOf(listener) !== -1;
|
|
return listeners[type] !== undefined && listeners[type].indexOf(listener) !== -1;
|
|
- },
|
|
|
|
- removeEventListener: function (type, listener) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ removeEventListener(type, listener) {
|
|
if (this._listeners === undefined) return;
|
|
if (this._listeners === undefined) return;
|
|
const listeners = this._listeners;
|
|
const listeners = this._listeners;
|
|
const listenerArray = listeners[type];
|
|
const listenerArray = listeners[type];
|
|
@@ -251,8 +251,9 @@
|
|
listenerArray.splice(index, 1);
|
|
listenerArray.splice(index, 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- },
|
|
|
|
- dispatchEvent: function (event) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ dispatchEvent(event) {
|
|
if (this._listeners === undefined) return;
|
|
if (this._listeners === undefined) return;
|
|
const listeners = this._listeners;
|
|
const listeners = this._listeners;
|
|
const listenerArray = listeners[event.type];
|
|
const listenerArray = listeners[event.type];
|
|
@@ -269,7 +270,8 @@
|
|
event.target = null;
|
|
event.target = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- });
|
|
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
|
|
const _lut = [];
|
|
const _lut = [];
|
|
|
|
|
|
@@ -4907,25 +4909,25 @@
|
|
|
|
|
|
let _object3DId = 0;
|
|
let _object3DId = 0;
|
|
|
|
|
|
- const _v1$4 = new Vector3();
|
|
|
|
|
|
+ const _v1$4 = new /*@__PURE__*/Vector3();
|
|
|
|
|
|
- const _q1 = new Quaternion();
|
|
|
|
|
|
+ const _q1 = new /*@__PURE__*/Quaternion();
|
|
|
|
|
|
- const _m1$1 = new Matrix4();
|
|
|
|
|
|
+ const _m1$1 = new /*@__PURE__*/Matrix4();
|
|
|
|
|
|
- const _target = new Vector3();
|
|
|
|
|
|
+ const _target = new /*@__PURE__*/Vector3();
|
|
|
|
|
|
- const _position$3 = new Vector3();
|
|
|
|
|
|
+ const _position$3 = new /*@__PURE__*/Vector3();
|
|
|
|
|
|
- const _scale$2 = new Vector3();
|
|
|
|
|
|
+ const _scale$2 = new /*@__PURE__*/Vector3();
|
|
|
|
|
|
- const _quaternion$2 = new Quaternion();
|
|
|
|
|
|
+ const _quaternion$2 = new /*@__PURE__*/Quaternion();
|
|
|
|
|
|
- const _xAxis = new Vector3(1, 0, 0);
|
|
|
|
|
|
+ const _xAxis = new /*@__PURE__*/Vector3(1, 0, 0);
|
|
|
|
|
|
- const _yAxis = new Vector3(0, 1, 0);
|
|
|
|
|
|
+ const _yAxis = new /*@__PURE__*/Vector3(0, 1, 0);
|
|
|
|
|
|
- const _zAxis = new Vector3(0, 0, 1);
|
|
|
|
|
|
+ const _zAxis = new /*@__PURE__*/Vector3(0, 0, 1);
|
|
|
|
|
|
const _addedEvent = {
|
|
const _addedEvent = {
|
|
type: 'added'
|
|
type: 'added'
|
|
@@ -4934,115 +4936,121 @@
|
|
type: 'removed'
|
|
type: 'removed'
|
|
};
|
|
};
|
|
|
|
|
|
- function Object3D() {
|
|
|
|
- Object.defineProperty(this, 'id', {
|
|
|
|
- value: _object3DId++
|
|
|
|
- });
|
|
|
|
- this.uuid = MathUtils.generateUUID();
|
|
|
|
- this.name = '';
|
|
|
|
- this.type = 'Object3D';
|
|
|
|
- this.parent = null;
|
|
|
|
- this.children = [];
|
|
|
|
- this.up = Object3D.DefaultUp.clone();
|
|
|
|
- const position = new Vector3();
|
|
|
|
- const rotation = new Euler();
|
|
|
|
- const quaternion = new Quaternion();
|
|
|
|
- const scale = new Vector3(1, 1, 1);
|
|
|
|
|
|
+ class Object3D extends EventDispatcher {
|
|
|
|
+ constructor() {
|
|
|
|
+ super();
|
|
|
|
+ Object.defineProperty(this, 'id', {
|
|
|
|
+ value: _object3DId++
|
|
|
|
+ });
|
|
|
|
+ this.uuid = MathUtils.generateUUID();
|
|
|
|
+ this.name = '';
|
|
|
|
+ this.type = 'Object3D';
|
|
|
|
+ this.parent = null;
|
|
|
|
+ this.children = [];
|
|
|
|
+ this.up = Object3D.DefaultUp.clone();
|
|
|
|
+ const position = new Vector3();
|
|
|
|
+ const rotation = new Euler();
|
|
|
|
+ const quaternion = new Quaternion();
|
|
|
|
+ const scale = new Vector3(1, 1, 1);
|
|
|
|
|
|
- function onRotationChange() {
|
|
|
|
- quaternion.setFromEuler(rotation, false);
|
|
|
|
- }
|
|
|
|
|
|
+ function onRotationChange() {
|
|
|
|
+ quaternion.setFromEuler(rotation, false);
|
|
|
|
+ }
|
|
|
|
|
|
- function onQuaternionChange() {
|
|
|
|
- rotation.setFromQuaternion(quaternion, undefined, false);
|
|
|
|
- }
|
|
|
|
|
|
+ function onQuaternionChange() {
|
|
|
|
+ rotation.setFromQuaternion(quaternion, undefined, false);
|
|
|
|
+ }
|
|
|
|
|
|
- rotation._onChange(onRotationChange);
|
|
|
|
|
|
+ rotation._onChange(onRotationChange);
|
|
|
|
|
|
- quaternion._onChange(onQuaternionChange);
|
|
|
|
|
|
+ quaternion._onChange(onQuaternionChange);
|
|
|
|
|
|
- Object.defineProperties(this, {
|
|
|
|
- position: {
|
|
|
|
- configurable: true,
|
|
|
|
- enumerable: true,
|
|
|
|
- value: position
|
|
|
|
- },
|
|
|
|
- rotation: {
|
|
|
|
- configurable: true,
|
|
|
|
- enumerable: true,
|
|
|
|
- value: rotation
|
|
|
|
- },
|
|
|
|
- quaternion: {
|
|
|
|
- configurable: true,
|
|
|
|
- enumerable: true,
|
|
|
|
- value: quaternion
|
|
|
|
- },
|
|
|
|
- scale: {
|
|
|
|
- configurable: true,
|
|
|
|
- enumerable: true,
|
|
|
|
- value: scale
|
|
|
|
- },
|
|
|
|
- modelViewMatrix: {
|
|
|
|
- value: new Matrix4()
|
|
|
|
- },
|
|
|
|
- normalMatrix: {
|
|
|
|
- value: new Matrix3()
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
- this.matrix = new Matrix4();
|
|
|
|
- this.matrixWorld = new Matrix4();
|
|
|
|
- this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;
|
|
|
|
- this.matrixWorldNeedsUpdate = false;
|
|
|
|
- this.layers = new Layers();
|
|
|
|
- this.visible = true;
|
|
|
|
- this.castShadow = false;
|
|
|
|
- this.receiveShadow = false;
|
|
|
|
- this.frustumCulled = true;
|
|
|
|
- this.renderOrder = 0;
|
|
|
|
- this.animations = [];
|
|
|
|
- this.userData = {};
|
|
|
|
- }
|
|
|
|
|
|
+ Object.defineProperties(this, {
|
|
|
|
+ position: {
|
|
|
|
+ configurable: true,
|
|
|
|
+ enumerable: true,
|
|
|
|
+ value: position
|
|
|
|
+ },
|
|
|
|
+ rotation: {
|
|
|
|
+ configurable: true,
|
|
|
|
+ enumerable: true,
|
|
|
|
+ value: rotation
|
|
|
|
+ },
|
|
|
|
+ quaternion: {
|
|
|
|
+ configurable: true,
|
|
|
|
+ enumerable: true,
|
|
|
|
+ value: quaternion
|
|
|
|
+ },
|
|
|
|
+ scale: {
|
|
|
|
+ configurable: true,
|
|
|
|
+ enumerable: true,
|
|
|
|
+ value: scale
|
|
|
|
+ },
|
|
|
|
+ modelViewMatrix: {
|
|
|
|
+ value: new Matrix4()
|
|
|
|
+ },
|
|
|
|
+ normalMatrix: {
|
|
|
|
+ value: new Matrix3()
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ this.matrix = new Matrix4();
|
|
|
|
+ this.matrixWorld = new Matrix4();
|
|
|
|
+ this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;
|
|
|
|
+ this.matrixWorldNeedsUpdate = false;
|
|
|
|
+ this.layers = new Layers();
|
|
|
|
+ this.visible = true;
|
|
|
|
+ this.castShadow = false;
|
|
|
|
+ this.receiveShadow = false;
|
|
|
|
+ this.frustumCulled = true;
|
|
|
|
+ this.renderOrder = 0;
|
|
|
|
+ this.animations = [];
|
|
|
|
+ this.userData = {};
|
|
|
|
+ }
|
|
|
|
|
|
- Object3D.DefaultUp = new Vector3(0, 1, 0);
|
|
|
|
- Object3D.DefaultMatrixAutoUpdate = true;
|
|
|
|
- Object3D.prototype = Object.assign(Object.create(EventDispatcher.prototype), {
|
|
|
|
- constructor: Object3D,
|
|
|
|
- isObject3D: true,
|
|
|
|
- onBeforeRender: function () {},
|
|
|
|
- onAfterRender: function () {},
|
|
|
|
- applyMatrix4: function (matrix) {
|
|
|
|
|
|
+ onBeforeRender() {}
|
|
|
|
+
|
|
|
|
+ onAfterRender() {}
|
|
|
|
+
|
|
|
|
+ applyMatrix4(matrix) {
|
|
if (this.matrixAutoUpdate) this.updateMatrix();
|
|
if (this.matrixAutoUpdate) this.updateMatrix();
|
|
this.matrix.premultiply(matrix);
|
|
this.matrix.premultiply(matrix);
|
|
this.matrix.decompose(this.position, this.quaternion, this.scale);
|
|
this.matrix.decompose(this.position, this.quaternion, this.scale);
|
|
- },
|
|
|
|
- applyQuaternion: function (q) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ applyQuaternion(q) {
|
|
this.quaternion.premultiply(q);
|
|
this.quaternion.premultiply(q);
|
|
return this;
|
|
return this;
|
|
- },
|
|
|
|
- setRotationFromAxisAngle: function (axis, angle) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ setRotationFromAxisAngle(axis, angle) {
|
|
// assumes axis is normalized
|
|
// assumes axis is normalized
|
|
this.quaternion.setFromAxisAngle(axis, angle);
|
|
this.quaternion.setFromAxisAngle(axis, angle);
|
|
- },
|
|
|
|
- setRotationFromEuler: function (euler) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ setRotationFromEuler(euler) {
|
|
this.quaternion.setFromEuler(euler, true);
|
|
this.quaternion.setFromEuler(euler, true);
|
|
- },
|
|
|
|
- setRotationFromMatrix: function (m) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ setRotationFromMatrix(m) {
|
|
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
|
|
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
|
|
this.quaternion.setFromRotationMatrix(m);
|
|
this.quaternion.setFromRotationMatrix(m);
|
|
- },
|
|
|
|
- setRotationFromQuaternion: function (q) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ setRotationFromQuaternion(q) {
|
|
// assumes q is normalized
|
|
// assumes q is normalized
|
|
this.quaternion.copy(q);
|
|
this.quaternion.copy(q);
|
|
- },
|
|
|
|
- rotateOnAxis: function (axis, angle) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rotateOnAxis(axis, angle) {
|
|
// rotate object on axis in object space
|
|
// rotate object on axis in object space
|
|
// axis is assumed to be normalized
|
|
// axis is assumed to be normalized
|
|
_q1.setFromAxisAngle(axis, angle);
|
|
_q1.setFromAxisAngle(axis, angle);
|
|
|
|
|
|
this.quaternion.multiply(_q1);
|
|
this.quaternion.multiply(_q1);
|
|
return this;
|
|
return this;
|
|
- },
|
|
|
|
- rotateOnWorldAxis: function (axis, angle) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rotateOnWorldAxis(axis, angle) {
|
|
// rotate object on axis in world space
|
|
// rotate object on axis in world space
|
|
// axis is assumed to be normalized
|
|
// axis is assumed to be normalized
|
|
// method assumes no rotated parent
|
|
// method assumes no rotated parent
|
|
@@ -5050,40 +5058,50 @@
|
|
|
|
|
|
this.quaternion.premultiply(_q1);
|
|
this.quaternion.premultiply(_q1);
|
|
return this;
|
|
return this;
|
|
- },
|
|
|
|
- rotateX: function (angle) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rotateX(angle) {
|
|
return this.rotateOnAxis(_xAxis, angle);
|
|
return this.rotateOnAxis(_xAxis, angle);
|
|
- },
|
|
|
|
- rotateY: function (angle) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rotateY(angle) {
|
|
return this.rotateOnAxis(_yAxis, angle);
|
|
return this.rotateOnAxis(_yAxis, angle);
|
|
- },
|
|
|
|
- rotateZ: function (angle) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rotateZ(angle) {
|
|
return this.rotateOnAxis(_zAxis, angle);
|
|
return this.rotateOnAxis(_zAxis, angle);
|
|
- },
|
|
|
|
- translateOnAxis: function (axis, distance) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ translateOnAxis(axis, distance) {
|
|
// translate object by distance along axis in object space
|
|
// translate object by distance along axis in object space
|
|
// axis is assumed to be normalized
|
|
// axis is assumed to be normalized
|
|
_v1$4.copy(axis).applyQuaternion(this.quaternion);
|
|
_v1$4.copy(axis).applyQuaternion(this.quaternion);
|
|
|
|
|
|
this.position.add(_v1$4.multiplyScalar(distance));
|
|
this.position.add(_v1$4.multiplyScalar(distance));
|
|
return this;
|
|
return this;
|
|
- },
|
|
|
|
- translateX: function (distance) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ translateX(distance) {
|
|
return this.translateOnAxis(_xAxis, distance);
|
|
return this.translateOnAxis(_xAxis, distance);
|
|
- },
|
|
|
|
- translateY: function (distance) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ translateY(distance) {
|
|
return this.translateOnAxis(_yAxis, distance);
|
|
return this.translateOnAxis(_yAxis, distance);
|
|
- },
|
|
|
|
- translateZ: function (distance) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ translateZ(distance) {
|
|
return this.translateOnAxis(_zAxis, distance);
|
|
return this.translateOnAxis(_zAxis, distance);
|
|
- },
|
|
|
|
- localToWorld: function (vector) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ localToWorld(vector) {
|
|
return vector.applyMatrix4(this.matrixWorld);
|
|
return vector.applyMatrix4(this.matrixWorld);
|
|
- },
|
|
|
|
- worldToLocal: function (vector) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ worldToLocal(vector) {
|
|
return vector.applyMatrix4(_m1$1.copy(this.matrixWorld).invert());
|
|
return vector.applyMatrix4(_m1$1.copy(this.matrixWorld).invert());
|
|
- },
|
|
|
|
- lookAt: function (x, y, z) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ lookAt(x, y, z) {
|
|
// This method does not support objects having non-uniformly-scaled parent(s)
|
|
// This method does not support objects having non-uniformly-scaled parent(s)
|
|
if (x.isVector3) {
|
|
if (x.isVector3) {
|
|
_target.copy(x);
|
|
_target.copy(x);
|
|
@@ -5111,8 +5129,9 @@
|
|
|
|
|
|
this.quaternion.premultiply(_q1.invert());
|
|
this.quaternion.premultiply(_q1.invert());
|
|
}
|
|
}
|
|
- },
|
|
|
|
- add: function (object) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ add(object) {
|
|
if (arguments.length > 1) {
|
|
if (arguments.length > 1) {
|
|
for (let i = 0; i < arguments.length; i++) {
|
|
for (let i = 0; i < arguments.length; i++) {
|
|
this.add(arguments[i]);
|
|
this.add(arguments[i]);
|
|
@@ -5139,8 +5158,9 @@
|
|
}
|
|
}
|
|
|
|
|
|
return this;
|
|
return this;
|
|
- },
|
|
|
|
- remove: function (object) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ remove(object) {
|
|
if (arguments.length > 1) {
|
|
if (arguments.length > 1) {
|
|
for (let i = 0; i < arguments.length; i++) {
|
|
for (let i = 0; i < arguments.length; i++) {
|
|
this.remove(arguments[i]);
|
|
this.remove(arguments[i]);
|
|
@@ -5158,8 +5178,9 @@
|
|
}
|
|
}
|
|
|
|
|
|
return this;
|
|
return this;
|
|
- },
|
|
|
|
- clear: function () {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ clear() {
|
|
for (let i = 0; i < this.children.length; i++) {
|
|
for (let i = 0; i < this.children.length; i++) {
|
|
const object = this.children[i];
|
|
const object = this.children[i];
|
|
object.parent = null;
|
|
object.parent = null;
|
|
@@ -5168,8 +5189,9 @@
|
|
|
|
|
|
this.children.length = 0;
|
|
this.children.length = 0;
|
|
return this;
|
|
return this;
|
|
- },
|
|
|
|
- attach: function (object) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ attach(object) {
|
|
// adds object as a child of this, while maintaining the object's world transform
|
|
// adds object as a child of this, while maintaining the object's world transform
|
|
this.updateWorldMatrix(true, false);
|
|
this.updateWorldMatrix(true, false);
|
|
|
|
|
|
@@ -5185,14 +5207,17 @@
|
|
this.add(object);
|
|
this.add(object);
|
|
object.updateWorldMatrix(false, true);
|
|
object.updateWorldMatrix(false, true);
|
|
return this;
|
|
return this;
|
|
- },
|
|
|
|
- getObjectById: function (id) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ getObjectById(id) {
|
|
return this.getObjectByProperty('id', id);
|
|
return this.getObjectByProperty('id', id);
|
|
- },
|
|
|
|
- getObjectByName: function (name) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ getObjectByName(name) {
|
|
return this.getObjectByProperty('name', name);
|
|
return this.getObjectByProperty('name', name);
|
|
- },
|
|
|
|
- getObjectByProperty: function (name, value) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ getObjectByProperty(name, value) {
|
|
if (this[name] === value) return this;
|
|
if (this[name] === value) return this;
|
|
|
|
|
|
for (let i = 0, l = this.children.length; i < l; i++) {
|
|
for (let i = 0, l = this.children.length; i < l; i++) {
|
|
@@ -5205,8 +5230,9 @@
|
|
}
|
|
}
|
|
|
|
|
|
return undefined;
|
|
return undefined;
|
|
- },
|
|
|
|
- getWorldPosition: function (target) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ getWorldPosition(target) {
|
|
if (target === undefined) {
|
|
if (target === undefined) {
|
|
console.warn('THREE.Object3D: .getWorldPosition() target is now required');
|
|
console.warn('THREE.Object3D: .getWorldPosition() target is now required');
|
|
target = new Vector3();
|
|
target = new Vector3();
|
|
@@ -5214,8 +5240,9 @@
|
|
|
|
|
|
this.updateWorldMatrix(true, false);
|
|
this.updateWorldMatrix(true, false);
|
|
return target.setFromMatrixPosition(this.matrixWorld);
|
|
return target.setFromMatrixPosition(this.matrixWorld);
|
|
- },
|
|
|
|
- getWorldQuaternion: function (target) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ getWorldQuaternion(target) {
|
|
if (target === undefined) {
|
|
if (target === undefined) {
|
|
console.warn('THREE.Object3D: .getWorldQuaternion() target is now required');
|
|
console.warn('THREE.Object3D: .getWorldQuaternion() target is now required');
|
|
target = new Quaternion();
|
|
target = new Quaternion();
|
|
@@ -5224,8 +5251,9 @@
|
|
this.updateWorldMatrix(true, false);
|
|
this.updateWorldMatrix(true, false);
|
|
this.matrixWorld.decompose(_position$3, target, _scale$2);
|
|
this.matrixWorld.decompose(_position$3, target, _scale$2);
|
|
return target;
|
|
return target;
|
|
- },
|
|
|
|
- getWorldScale: function (target) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ getWorldScale(target) {
|
|
if (target === undefined) {
|
|
if (target === undefined) {
|
|
console.warn('THREE.Object3D: .getWorldScale() target is now required');
|
|
console.warn('THREE.Object3D: .getWorldScale() target is now required');
|
|
target = new Vector3();
|
|
target = new Vector3();
|
|
@@ -5234,8 +5262,9 @@
|
|
this.updateWorldMatrix(true, false);
|
|
this.updateWorldMatrix(true, false);
|
|
this.matrixWorld.decompose(_position$3, _quaternion$2, target);
|
|
this.matrixWorld.decompose(_position$3, _quaternion$2, target);
|
|
return target;
|
|
return target;
|
|
- },
|
|
|
|
- getWorldDirection: function (target) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ getWorldDirection(target) {
|
|
if (target === undefined) {
|
|
if (target === undefined) {
|
|
console.warn('THREE.Object3D: .getWorldDirection() target is now required');
|
|
console.warn('THREE.Object3D: .getWorldDirection() target is now required');
|
|
target = new Vector3();
|
|
target = new Vector3();
|
|
@@ -5244,17 +5273,20 @@
|
|
this.updateWorldMatrix(true, false);
|
|
this.updateWorldMatrix(true, false);
|
|
const e = this.matrixWorld.elements;
|
|
const e = this.matrixWorld.elements;
|
|
return target.set(e[8], e[9], e[10]).normalize();
|
|
return target.set(e[8], e[9], e[10]).normalize();
|
|
- },
|
|
|
|
- raycast: function () {},
|
|
|
|
- traverse: function (callback) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ raycast() {}
|
|
|
|
+
|
|
|
|
+ traverse(callback) {
|
|
callback(this);
|
|
callback(this);
|
|
const children = this.children;
|
|
const children = this.children;
|
|
|
|
|
|
for (let i = 0, l = children.length; i < l; i++) {
|
|
for (let i = 0, l = children.length; i < l; i++) {
|
|
children[i].traverse(callback);
|
|
children[i].traverse(callback);
|
|
}
|
|
}
|
|
- },
|
|
|
|
- traverseVisible: function (callback) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ traverseVisible(callback) {
|
|
if (this.visible === false) return;
|
|
if (this.visible === false) return;
|
|
callback(this);
|
|
callback(this);
|
|
const children = this.children;
|
|
const children = this.children;
|
|
@@ -5262,20 +5294,23 @@
|
|
for (let i = 0, l = children.length; i < l; i++) {
|
|
for (let i = 0, l = children.length; i < l; i++) {
|
|
children[i].traverseVisible(callback);
|
|
children[i].traverseVisible(callback);
|
|
}
|
|
}
|
|
- },
|
|
|
|
- traverseAncestors: function (callback) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ traverseAncestors(callback) {
|
|
const parent = this.parent;
|
|
const parent = this.parent;
|
|
|
|
|
|
if (parent !== null) {
|
|
if (parent !== null) {
|
|
callback(parent);
|
|
callback(parent);
|
|
parent.traverseAncestors(callback);
|
|
parent.traverseAncestors(callback);
|
|
}
|
|
}
|
|
- },
|
|
|
|
- updateMatrix: function () {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ updateMatrix() {
|
|
this.matrix.compose(this.position, this.quaternion, this.scale);
|
|
this.matrix.compose(this.position, this.quaternion, this.scale);
|
|
this.matrixWorldNeedsUpdate = true;
|
|
this.matrixWorldNeedsUpdate = true;
|
|
- },
|
|
|
|
- updateMatrixWorld: function (force) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ updateMatrixWorld(force) {
|
|
if (this.matrixAutoUpdate) this.updateMatrix();
|
|
if (this.matrixAutoUpdate) this.updateMatrix();
|
|
|
|
|
|
if (this.matrixWorldNeedsUpdate || force) {
|
|
if (this.matrixWorldNeedsUpdate || force) {
|
|
@@ -5295,8 +5330,9 @@
|
|
for (let i = 0, l = children.length; i < l; i++) {
|
|
for (let i = 0, l = children.length; i < l; i++) {
|
|
children[i].updateMatrixWorld(force);
|
|
children[i].updateMatrixWorld(force);
|
|
}
|
|
}
|
|
- },
|
|
|
|
- updateWorldMatrix: function (updateParents, updateChildren) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ updateWorldMatrix(updateParents, updateChildren) {
|
|
const parent = this.parent;
|
|
const parent = this.parent;
|
|
|
|
|
|
if (updateParents === true && parent !== null) {
|
|
if (updateParents === true && parent !== null) {
|
|
@@ -5319,8 +5355,9 @@
|
|
children[i].updateWorldMatrix(false, true);
|
|
children[i].updateWorldMatrix(false, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- },
|
|
|
|
- toJSON: function (meta) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ toJSON(meta) {
|
|
// meta is a string when called from JSON.stringify
|
|
// meta is a string when called from JSON.stringify
|
|
const isRootObject = meta === undefined || typeof meta === 'string';
|
|
const isRootObject = meta === undefined || typeof meta === 'string';
|
|
const output = {}; // meta is a hash used to collect geometries, materials.
|
|
const output = {}; // meta is a hash used to collect geometries, materials.
|
|
@@ -5470,11 +5507,13 @@
|
|
|
|
|
|
return values;
|
|
return values;
|
|
}
|
|
}
|
|
- },
|
|
|
|
- clone: function (recursive) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ clone(recursive) {
|
|
return new this.constructor().copy(this, recursive);
|
|
return new this.constructor().copy(this, recursive);
|
|
- },
|
|
|
|
- copy: function (source, recursive = true) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ copy(source, recursive = true) {
|
|
this.name = source.name;
|
|
this.name = source.name;
|
|
this.up.copy(source.up);
|
|
this.up.copy(source.up);
|
|
this.position.copy(source.position);
|
|
this.position.copy(source.position);
|
|
@@ -5502,7 +5541,12 @@
|
|
|
|
|
|
return this;
|
|
return this;
|
|
}
|
|
}
|
|
- });
|
|
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Object3D.DefaultUp = new Vector3(0, 1, 0);
|
|
|
|
+ Object3D.DefaultMatrixAutoUpdate = true;
|
|
|
|
+ Object3D.prototype.isObject3D = true;
|
|
|
|
|
|
const _vector1 = /*@__PURE__*/new Vector3();
|
|
const _vector1 = /*@__PURE__*/new Vector3();
|
|
|
|
|
|
@@ -16226,356 +16270,358 @@
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
- function WebXRManager(renderer, gl) {
|
|
|
|
- const scope = this;
|
|
|
|
- const state = renderer.state;
|
|
|
|
- let session = null;
|
|
|
|
- let framebufferScaleFactor = 1.0;
|
|
|
|
- let referenceSpace = null;
|
|
|
|
- let referenceSpaceType = 'local-floor';
|
|
|
|
- let pose = null;
|
|
|
|
- const controllers = [];
|
|
|
|
- const inputSourcesMap = new Map(); //
|
|
|
|
-
|
|
|
|
- const cameraL = new PerspectiveCamera();
|
|
|
|
- cameraL.layers.enable(1);
|
|
|
|
- cameraL.viewport = new Vector4();
|
|
|
|
- const cameraR = new PerspectiveCamera();
|
|
|
|
- cameraR.layers.enable(2);
|
|
|
|
- cameraR.viewport = new Vector4();
|
|
|
|
- const cameras = [cameraL, cameraR];
|
|
|
|
- const cameraVR = new ArrayCamera();
|
|
|
|
- cameraVR.layers.enable(1);
|
|
|
|
- cameraVR.layers.enable(2);
|
|
|
|
- let _currentDepthNear = null;
|
|
|
|
- let _currentDepthFar = null; //
|
|
|
|
|
|
+ class WebXRManager extends EventDispatcher {
|
|
|
|
+ constructor(renderer, gl) {
|
|
|
|
+ super();
|
|
|
|
+ const scope = this;
|
|
|
|
+ const state = renderer.state;
|
|
|
|
+ let session = null;
|
|
|
|
+ let framebufferScaleFactor = 1.0;
|
|
|
|
+ let referenceSpace = null;
|
|
|
|
+ let referenceSpaceType = 'local-floor';
|
|
|
|
+ let pose = null;
|
|
|
|
+ const controllers = [];
|
|
|
|
+ const inputSourcesMap = new Map(); //
|
|
|
|
+
|
|
|
|
+ const cameraL = new PerspectiveCamera();
|
|
|
|
+ cameraL.layers.enable(1);
|
|
|
|
+ cameraL.viewport = new Vector4();
|
|
|
|
+ const cameraR = new PerspectiveCamera();
|
|
|
|
+ cameraR.layers.enable(2);
|
|
|
|
+ cameraR.viewport = new Vector4();
|
|
|
|
+ const cameras = [cameraL, cameraR];
|
|
|
|
+ const cameraVR = new ArrayCamera();
|
|
|
|
+ cameraVR.layers.enable(1);
|
|
|
|
+ cameraVR.layers.enable(2);
|
|
|
|
+ let _currentDepthNear = null;
|
|
|
|
+ let _currentDepthFar = null; //
|
|
|
|
+
|
|
|
|
+ this.enabled = false;
|
|
|
|
+ this.isPresenting = false;
|
|
|
|
+
|
|
|
|
+ this.getController = function (index) {
|
|
|
|
+ let controller = controllers[index];
|
|
|
|
+
|
|
|
|
+ if (controller === undefined) {
|
|
|
|
+ controller = new WebXRController();
|
|
|
|
+ controllers[index] = controller;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return controller.getTargetRaySpace();
|
|
|
|
+ };
|
|
|
|
|
|
- this.enabled = false;
|
|
|
|
- this.isPresenting = false;
|
|
|
|
|
|
+ this.getControllerGrip = function (index) {
|
|
|
|
+ let controller = controllers[index];
|
|
|
|
|
|
- this.getController = function (index) {
|
|
|
|
- let controller = controllers[index];
|
|
|
|
|
|
+ if (controller === undefined) {
|
|
|
|
+ controller = new WebXRController();
|
|
|
|
+ controllers[index] = controller;
|
|
|
|
+ }
|
|
|
|
|
|
- if (controller === undefined) {
|
|
|
|
- controller = new WebXRController();
|
|
|
|
- controllers[index] = controller;
|
|
|
|
- }
|
|
|
|
|
|
+ return controller.getGripSpace();
|
|
|
|
+ };
|
|
|
|
|
|
- return controller.getTargetRaySpace();
|
|
|
|
- };
|
|
|
|
|
|
+ this.getHand = function (index) {
|
|
|
|
+ let controller = controllers[index];
|
|
|
|
|
|
- this.getControllerGrip = function (index) {
|
|
|
|
- let controller = controllers[index];
|
|
|
|
|
|
+ if (controller === undefined) {
|
|
|
|
+ controller = new WebXRController();
|
|
|
|
+ controllers[index] = controller;
|
|
|
|
+ }
|
|
|
|
|
|
- if (controller === undefined) {
|
|
|
|
- controller = new WebXRController();
|
|
|
|
- controllers[index] = controller;
|
|
|
|
- }
|
|
|
|
|
|
+ return controller.getHandSpace();
|
|
|
|
+ }; //
|
|
|
|
|
|
- return controller.getGripSpace();
|
|
|
|
- };
|
|
|
|
|
|
|
|
- this.getHand = function (index) {
|
|
|
|
- let controller = controllers[index];
|
|
|
|
|
|
+ function onSessionEvent(event) {
|
|
|
|
+ const controller = inputSourcesMap.get(event.inputSource);
|
|
|
|
|
|
- if (controller === undefined) {
|
|
|
|
- controller = new WebXRController();
|
|
|
|
- controllers[index] = controller;
|
|
|
|
|
|
+ if (controller) {
|
|
|
|
+ controller.dispatchEvent({
|
|
|
|
+ type: event.type,
|
|
|
|
+ data: event.inputSource
|
|
|
|
+ });
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- return controller.getHandSpace();
|
|
|
|
- }; //
|
|
|
|
-
|
|
|
|
|
|
+ function onSessionEnd() {
|
|
|
|
+ inputSourcesMap.forEach(function (controller, inputSource) {
|
|
|
|
+ controller.disconnect(inputSource);
|
|
|
|
+ });
|
|
|
|
+ inputSourcesMap.clear();
|
|
|
|
+ _currentDepthNear = null;
|
|
|
|
+ _currentDepthFar = null; // restore framebuffer/rendering state
|
|
|
|
|
|
- function onSessionEvent(event) {
|
|
|
|
- const controller = inputSourcesMap.get(event.inputSource);
|
|
|
|
|
|
+ state.bindXRFramebuffer(null);
|
|
|
|
+ renderer.setRenderTarget(renderer.getRenderTarget()); //
|
|
|
|
|
|
- if (controller) {
|
|
|
|
- controller.dispatchEvent({
|
|
|
|
- type: event.type,
|
|
|
|
- data: event.inputSource
|
|
|
|
|
|
+ animation.stop();
|
|
|
|
+ scope.isPresenting = false;
|
|
|
|
+ scope.dispatchEvent({
|
|
|
|
+ type: 'sessionend'
|
|
});
|
|
});
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
|
|
- function onSessionEnd() {
|
|
|
|
- inputSourcesMap.forEach(function (controller, inputSource) {
|
|
|
|
- controller.disconnect(inputSource);
|
|
|
|
- });
|
|
|
|
- inputSourcesMap.clear();
|
|
|
|
- _currentDepthNear = null;
|
|
|
|
- _currentDepthFar = null; // restore framebuffer/rendering state
|
|
|
|
|
|
+ this.setFramebufferScaleFactor = function (value) {
|
|
|
|
+ framebufferScaleFactor = value;
|
|
|
|
|
|
- state.bindXRFramebuffer(null);
|
|
|
|
- renderer.setRenderTarget(renderer.getRenderTarget()); //
|
|
|
|
|
|
+ if (scope.isPresenting === true) {
|
|
|
|
+ console.warn('THREE.WebXRManager: Cannot change framebuffer scale while presenting.');
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
|
|
- animation.stop();
|
|
|
|
- scope.isPresenting = false;
|
|
|
|
- scope.dispatchEvent({
|
|
|
|
- type: 'sessionend'
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
|
|
+ this.setReferenceSpaceType = function (value) {
|
|
|
|
+ referenceSpaceType = value;
|
|
|
|
|
|
- this.setFramebufferScaleFactor = function (value) {
|
|
|
|
- framebufferScaleFactor = value;
|
|
|
|
|
|
+ if (scope.isPresenting === true) {
|
|
|
|
+ console.warn('THREE.WebXRManager: Cannot change reference space type while presenting.');
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
|
|
- if (scope.isPresenting === true) {
|
|
|
|
- console.warn('THREE.WebXRManager: Cannot change framebuffer scale while presenting.');
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
|
|
+ this.getReferenceSpace = function () {
|
|
|
|
+ return referenceSpace;
|
|
|
|
+ };
|
|
|
|
|
|
- this.setReferenceSpaceType = function (value) {
|
|
|
|
- referenceSpaceType = value;
|
|
|
|
|
|
+ this.getSession = function () {
|
|
|
|
+ return session;
|
|
|
|
+ };
|
|
|
|
|
|
- if (scope.isPresenting === true) {
|
|
|
|
- console.warn('THREE.WebXRManager: Cannot change reference space type while presenting.');
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
|
|
+ this.setSession = async function (value) {
|
|
|
|
+ session = value;
|
|
|
|
+
|
|
|
|
+ if (session !== null) {
|
|
|
|
+ session.addEventListener('select', onSessionEvent);
|
|
|
|
+ session.addEventListener('selectstart', onSessionEvent);
|
|
|
|
+ session.addEventListener('selectend', onSessionEvent);
|
|
|
|
+ session.addEventListener('squeeze', onSessionEvent);
|
|
|
|
+ session.addEventListener('squeezestart', onSessionEvent);
|
|
|
|
+ session.addEventListener('squeezeend', onSessionEvent);
|
|
|
|
+ session.addEventListener('end', onSessionEnd);
|
|
|
|
+ session.addEventListener('inputsourceschange', onInputSourcesChange);
|
|
|
|
+ const attributes = gl.getContextAttributes();
|
|
|
|
+
|
|
|
|
+ if (attributes.xrCompatible !== true) {
|
|
|
|
+ await gl.makeXRCompatible();
|
|
|
|
+ }
|
|
|
|
|
|
- this.getReferenceSpace = function () {
|
|
|
|
- return referenceSpace;
|
|
|
|
- };
|
|
|
|
|
|
+ const layerInit = {
|
|
|
|
+ antialias: attributes.antialias,
|
|
|
|
+ alpha: attributes.alpha,
|
|
|
|
+ depth: attributes.depth,
|
|
|
|
+ stencil: attributes.stencil,
|
|
|
|
+ framebufferScaleFactor: framebufferScaleFactor
|
|
|
|
+ }; // eslint-disable-next-line no-undef
|
|
|
|
+
|
|
|
|
+ const baseLayer = new XRWebGLLayer(session, gl, layerInit);
|
|
|
|
+ session.updateRenderState({
|
|
|
|
+ baseLayer: baseLayer
|
|
|
|
+ });
|
|
|
|
+ referenceSpace = await session.requestReferenceSpace(referenceSpaceType);
|
|
|
|
+ animation.setContext(session);
|
|
|
|
+ animation.start();
|
|
|
|
+ scope.isPresenting = true;
|
|
|
|
+ scope.dispatchEvent({
|
|
|
|
+ type: 'sessionstart'
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
|
|
- this.getSession = function () {
|
|
|
|
- return session;
|
|
|
|
- };
|
|
|
|
|
|
+ function onInputSourcesChange(event) {
|
|
|
|
+ const inputSources = session.inputSources; // Assign inputSources to available controllers
|
|
|
|
|
|
- this.setSession = async function (value) {
|
|
|
|
- session = value;
|
|
|
|
-
|
|
|
|
- if (session !== null) {
|
|
|
|
- session.addEventListener('select', onSessionEvent);
|
|
|
|
- session.addEventListener('selectstart', onSessionEvent);
|
|
|
|
- session.addEventListener('selectend', onSessionEvent);
|
|
|
|
- session.addEventListener('squeeze', onSessionEvent);
|
|
|
|
- session.addEventListener('squeezestart', onSessionEvent);
|
|
|
|
- session.addEventListener('squeezeend', onSessionEvent);
|
|
|
|
- session.addEventListener('end', onSessionEnd);
|
|
|
|
- session.addEventListener('inputsourceschange', onInputSourcesChange);
|
|
|
|
- const attributes = gl.getContextAttributes();
|
|
|
|
-
|
|
|
|
- if (attributes.xrCompatible !== true) {
|
|
|
|
- await gl.makeXRCompatible();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- const layerInit = {
|
|
|
|
- antialias: attributes.antialias,
|
|
|
|
- alpha: attributes.alpha,
|
|
|
|
- depth: attributes.depth,
|
|
|
|
- stencil: attributes.stencil,
|
|
|
|
- framebufferScaleFactor: framebufferScaleFactor
|
|
|
|
- }; // eslint-disable-next-line no-undef
|
|
|
|
-
|
|
|
|
- const baseLayer = new XRWebGLLayer(session, gl, layerInit);
|
|
|
|
- session.updateRenderState({
|
|
|
|
- baseLayer: baseLayer
|
|
|
|
- });
|
|
|
|
- referenceSpace = await session.requestReferenceSpace(referenceSpaceType);
|
|
|
|
- animation.setContext(session);
|
|
|
|
- animation.start();
|
|
|
|
- scope.isPresenting = true;
|
|
|
|
- scope.dispatchEvent({
|
|
|
|
- type: 'sessionstart'
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
|
|
+ for (let i = 0; i < controllers.length; i++) {
|
|
|
|
+ inputSourcesMap.set(inputSources[i], controllers[i]);
|
|
|
|
+ } // Notify disconnected
|
|
|
|
|
|
- function onInputSourcesChange(event) {
|
|
|
|
- const inputSources = session.inputSources; // Assign inputSources to available controllers
|
|
|
|
|
|
|
|
- for (let i = 0; i < controllers.length; i++) {
|
|
|
|
- inputSourcesMap.set(inputSources[i], controllers[i]);
|
|
|
|
- } // Notify disconnected
|
|
|
|
|
|
+ for (let i = 0; i < event.removed.length; i++) {
|
|
|
|
+ const inputSource = event.removed[i];
|
|
|
|
+ const controller = inputSourcesMap.get(inputSource);
|
|
|
|
|
|
|
|
+ if (controller) {
|
|
|
|
+ controller.dispatchEvent({
|
|
|
|
+ type: 'disconnected',
|
|
|
|
+ data: inputSource
|
|
|
|
+ });
|
|
|
|
+ inputSourcesMap.delete(inputSource);
|
|
|
|
+ }
|
|
|
|
+ } // Notify connected
|
|
|
|
|
|
- for (let i = 0; i < event.removed.length; i++) {
|
|
|
|
- const inputSource = event.removed[i];
|
|
|
|
- const controller = inputSourcesMap.get(inputSource);
|
|
|
|
|
|
|
|
- if (controller) {
|
|
|
|
- controller.dispatchEvent({
|
|
|
|
- type: 'disconnected',
|
|
|
|
- data: inputSource
|
|
|
|
- });
|
|
|
|
- inputSourcesMap.delete(inputSource);
|
|
|
|
|
|
+ for (let i = 0; i < event.added.length; i++) {
|
|
|
|
+ const inputSource = event.added[i];
|
|
|
|
+ const controller = inputSourcesMap.get(inputSource);
|
|
|
|
+
|
|
|
|
+ if (controller) {
|
|
|
|
+ controller.dispatchEvent({
|
|
|
|
+ type: 'connected',
|
|
|
|
+ data: inputSource
|
|
|
|
+ });
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- } // Notify connected
|
|
|
|
|
|
+ } //
|
|
|
|
|
|
|
|
|
|
- for (let i = 0; i < event.added.length; i++) {
|
|
|
|
- const inputSource = event.added[i];
|
|
|
|
- const controller = inputSourcesMap.get(inputSource);
|
|
|
|
|
|
+ const cameraLPos = new Vector3();
|
|
|
|
+ const cameraRPos = new Vector3();
|
|
|
|
+ /**
|
|
|
|
+ * Assumes 2 cameras that are parallel and share an X-axis, and that
|
|
|
|
+ * the cameras' projection and world matrices have already been set.
|
|
|
|
+ * And that near and far planes are identical for both cameras.
|
|
|
|
+ * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765
|
|
|
|
+ */
|
|
|
|
|
|
- if (controller) {
|
|
|
|
- controller.dispatchEvent({
|
|
|
|
- type: 'connected',
|
|
|
|
- data: inputSource
|
|
|
|
- });
|
|
|
|
|
|
+ function setProjectionFromUnion(camera, cameraL, cameraR) {
|
|
|
|
+ cameraLPos.setFromMatrixPosition(cameraL.matrixWorld);
|
|
|
|
+ cameraRPos.setFromMatrixPosition(cameraR.matrixWorld);
|
|
|
|
+ const ipd = cameraLPos.distanceTo(cameraRPos);
|
|
|
|
+ const projL = cameraL.projectionMatrix.elements;
|
|
|
|
+ const projR = cameraR.projectionMatrix.elements; // VR systems will have identical far and near planes, and
|
|
|
|
+ // most likely identical top and bottom frustum extents.
|
|
|
|
+ // Use the left camera for these values.
|
|
|
|
+
|
|
|
|
+ const near = projL[14] / (projL[10] - 1);
|
|
|
|
+ const far = projL[14] / (projL[10] + 1);
|
|
|
|
+ const topFov = (projL[9] + 1) / projL[5];
|
|
|
|
+ const bottomFov = (projL[9] - 1) / projL[5];
|
|
|
|
+ const leftFov = (projL[8] - 1) / projL[0];
|
|
|
|
+ const rightFov = (projR[8] + 1) / projR[0];
|
|
|
|
+ const left = near * leftFov;
|
|
|
|
+ const right = near * rightFov; // Calculate the new camera's position offset from the
|
|
|
|
+ // left camera. xOffset should be roughly half `ipd`.
|
|
|
|
+
|
|
|
|
+ const zOffset = ipd / (-leftFov + rightFov);
|
|
|
|
+ const xOffset = zOffset * -leftFov; // TODO: Better way to apply this offset?
|
|
|
|
+
|
|
|
|
+ cameraL.matrixWorld.decompose(camera.position, camera.quaternion, camera.scale);
|
|
|
|
+ camera.translateX(xOffset);
|
|
|
|
+ camera.translateZ(zOffset);
|
|
|
|
+ camera.matrixWorld.compose(camera.position, camera.quaternion, camera.scale);
|
|
|
|
+ camera.matrixWorldInverse.copy(camera.matrixWorld).invert(); // Find the union of the frustum values of the cameras and scale
|
|
|
|
+ // the values so that the near plane's position does not change in world space,
|
|
|
|
+ // although must now be relative to the new union camera.
|
|
|
|
+
|
|
|
|
+ const near2 = near + zOffset;
|
|
|
|
+ const far2 = far + zOffset;
|
|
|
|
+ const left2 = left - xOffset;
|
|
|
|
+ const right2 = right + (ipd - xOffset);
|
|
|
|
+ const top2 = topFov * far / far2 * near2;
|
|
|
|
+ const bottom2 = bottomFov * far / far2 * near2;
|
|
|
|
+ camera.projectionMatrix.makePerspective(left2, right2, top2, bottom2, near2, far2);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function updateCamera(camera, parent) {
|
|
|
|
+ if (parent === null) {
|
|
|
|
+ camera.matrixWorld.copy(camera.matrix);
|
|
|
|
+ } else {
|
|
|
|
+ camera.matrixWorld.multiplyMatrices(parent.matrixWorld, camera.matrix);
|
|
}
|
|
}
|
|
- }
|
|
|
|
- } //
|
|
|
|
-
|
|
|
|
|
|
|
|
- const cameraLPos = new Vector3();
|
|
|
|
- const cameraRPos = new Vector3();
|
|
|
|
- /**
|
|
|
|
- * Assumes 2 cameras that are parallel and share an X-axis, and that
|
|
|
|
- * the cameras' projection and world matrices have already been set.
|
|
|
|
- * And that near and far planes are identical for both cameras.
|
|
|
|
- * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765
|
|
|
|
- */
|
|
|
|
-
|
|
|
|
- function setProjectionFromUnion(camera, cameraL, cameraR) {
|
|
|
|
- cameraLPos.setFromMatrixPosition(cameraL.matrixWorld);
|
|
|
|
- cameraRPos.setFromMatrixPosition(cameraR.matrixWorld);
|
|
|
|
- const ipd = cameraLPos.distanceTo(cameraRPos);
|
|
|
|
- const projL = cameraL.projectionMatrix.elements;
|
|
|
|
- const projR = cameraR.projectionMatrix.elements; // VR systems will have identical far and near planes, and
|
|
|
|
- // most likely identical top and bottom frustum extents.
|
|
|
|
- // Use the left camera for these values.
|
|
|
|
-
|
|
|
|
- const near = projL[14] / (projL[10] - 1);
|
|
|
|
- const far = projL[14] / (projL[10] + 1);
|
|
|
|
- const topFov = (projL[9] + 1) / projL[5];
|
|
|
|
- const bottomFov = (projL[9] - 1) / projL[5];
|
|
|
|
- const leftFov = (projL[8] - 1) / projL[0];
|
|
|
|
- const rightFov = (projR[8] + 1) / projR[0];
|
|
|
|
- const left = near * leftFov;
|
|
|
|
- const right = near * rightFov; // Calculate the new camera's position offset from the
|
|
|
|
- // left camera. xOffset should be roughly half `ipd`.
|
|
|
|
-
|
|
|
|
- const zOffset = ipd / (-leftFov + rightFov);
|
|
|
|
- const xOffset = zOffset * -leftFov; // TODO: Better way to apply this offset?
|
|
|
|
-
|
|
|
|
- cameraL.matrixWorld.decompose(camera.position, camera.quaternion, camera.scale);
|
|
|
|
- camera.translateX(xOffset);
|
|
|
|
- camera.translateZ(zOffset);
|
|
|
|
- camera.matrixWorld.compose(camera.position, camera.quaternion, camera.scale);
|
|
|
|
- camera.matrixWorldInverse.copy(camera.matrixWorld).invert(); // Find the union of the frustum values of the cameras and scale
|
|
|
|
- // the values so that the near plane's position does not change in world space,
|
|
|
|
- // although must now be relative to the new union camera.
|
|
|
|
-
|
|
|
|
- const near2 = near + zOffset;
|
|
|
|
- const far2 = far + zOffset;
|
|
|
|
- const left2 = left - xOffset;
|
|
|
|
- const right2 = right + (ipd - xOffset);
|
|
|
|
- const top2 = topFov * far / far2 * near2;
|
|
|
|
- const bottom2 = bottomFov * far / far2 * near2;
|
|
|
|
- camera.projectionMatrix.makePerspective(left2, right2, top2, bottom2, near2, far2);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- function updateCamera(camera, parent) {
|
|
|
|
- if (parent === null) {
|
|
|
|
- camera.matrixWorld.copy(camera.matrix);
|
|
|
|
- } else {
|
|
|
|
- camera.matrixWorld.multiplyMatrices(parent.matrixWorld, camera.matrix);
|
|
|
|
|
|
+ camera.matrixWorldInverse.copy(camera.matrixWorld).invert();
|
|
}
|
|
}
|
|
|
|
|
|
- camera.matrixWorldInverse.copy(camera.matrixWorld).invert();
|
|
|
|
- }
|
|
|
|
|
|
+ this.getCamera = function (camera) {
|
|
|
|
+ cameraVR.near = cameraR.near = cameraL.near = camera.near;
|
|
|
|
+ cameraVR.far = cameraR.far = cameraL.far = camera.far;
|
|
|
|
|
|
- this.getCamera = function (camera) {
|
|
|
|
- cameraVR.near = cameraR.near = cameraL.near = camera.near;
|
|
|
|
- cameraVR.far = cameraR.far = cameraL.far = camera.far;
|
|
|
|
|
|
+ if (_currentDepthNear !== cameraVR.near || _currentDepthFar !== cameraVR.far) {
|
|
|
|
+ // Note that the new renderState won't apply until the next frame. See #18320
|
|
|
|
+ session.updateRenderState({
|
|
|
|
+ depthNear: cameraVR.near,
|
|
|
|
+ depthFar: cameraVR.far
|
|
|
|
+ });
|
|
|
|
+ _currentDepthNear = cameraVR.near;
|
|
|
|
+ _currentDepthFar = cameraVR.far;
|
|
|
|
+ }
|
|
|
|
|
|
- if (_currentDepthNear !== cameraVR.near || _currentDepthFar !== cameraVR.far) {
|
|
|
|
- // Note that the new renderState won't apply until the next frame. See #18320
|
|
|
|
- session.updateRenderState({
|
|
|
|
- depthNear: cameraVR.near,
|
|
|
|
- depthFar: cameraVR.far
|
|
|
|
- });
|
|
|
|
- _currentDepthNear = cameraVR.near;
|
|
|
|
- _currentDepthFar = cameraVR.far;
|
|
|
|
- }
|
|
|
|
|
|
+ const parent = camera.parent;
|
|
|
|
+ const cameras = cameraVR.cameras;
|
|
|
|
+ updateCamera(cameraVR, parent);
|
|
|
|
|
|
- const parent = camera.parent;
|
|
|
|
- const cameras = cameraVR.cameras;
|
|
|
|
- updateCamera(cameraVR, parent);
|
|
|
|
|
|
+ for (let i = 0; i < cameras.length; i++) {
|
|
|
|
+ updateCamera(cameras[i], parent);
|
|
|
|
+ } // update camera and its children
|
|
|
|
|
|
- for (let i = 0; i < cameras.length; i++) {
|
|
|
|
- updateCamera(cameras[i], parent);
|
|
|
|
- } // update camera and its children
|
|
|
|
|
|
|
|
|
|
+ camera.matrixWorld.copy(cameraVR.matrixWorld);
|
|
|
|
+ camera.matrix.copy(cameraVR.matrix);
|
|
|
|
+ camera.matrix.decompose(camera.position, camera.quaternion, camera.scale);
|
|
|
|
+ const children = camera.children;
|
|
|
|
|
|
- camera.matrixWorld.copy(cameraVR.matrixWorld);
|
|
|
|
- camera.matrix.copy(cameraVR.matrix);
|
|
|
|
- camera.matrix.decompose(camera.position, camera.quaternion, camera.scale);
|
|
|
|
- const children = camera.children;
|
|
|
|
|
|
+ for (let i = 0, l = children.length; i < l; i++) {
|
|
|
|
+ children[i].updateMatrixWorld(true);
|
|
|
|
+ } // update projection matrix for proper view frustum culling
|
|
|
|
|
|
- for (let i = 0, l = children.length; i < l; i++) {
|
|
|
|
- children[i].updateMatrixWorld(true);
|
|
|
|
- } // update projection matrix for proper view frustum culling
|
|
|
|
|
|
|
|
|
|
+ if (cameras.length === 2) {
|
|
|
|
+ setProjectionFromUnion(cameraVR, cameraL, cameraR);
|
|
|
|
+ } else {
|
|
|
|
+ // assume single camera setup (AR)
|
|
|
|
+ cameraVR.projectionMatrix.copy(cameraL.projectionMatrix);
|
|
|
|
+ }
|
|
|
|
|
|
- if (cameras.length === 2) {
|
|
|
|
- setProjectionFromUnion(cameraVR, cameraL, cameraR);
|
|
|
|
- } else {
|
|
|
|
- // assume single camera setup (AR)
|
|
|
|
- cameraVR.projectionMatrix.copy(cameraL.projectionMatrix);
|
|
|
|
- }
|
|
|
|
|
|
+ return cameraVR;
|
|
|
|
+ }; // Animation Loop
|
|
|
|
|
|
- return cameraVR;
|
|
|
|
- }; // Animation Loop
|
|
|
|
|
|
|
|
|
|
+ let onAnimationFrameCallback = null;
|
|
|
|
|
|
- let onAnimationFrameCallback = null;
|
|
|
|
|
|
+ function onAnimationFrame(time, frame) {
|
|
|
|
+ pose = frame.getViewerPose(referenceSpace);
|
|
|
|
|
|
- function onAnimationFrame(time, frame) {
|
|
|
|
- pose = frame.getViewerPose(referenceSpace);
|
|
|
|
|
|
+ if (pose !== null) {
|
|
|
|
+ const views = pose.views;
|
|
|
|
+ const baseLayer = session.renderState.baseLayer;
|
|
|
|
+ state.bindXRFramebuffer(baseLayer.framebuffer);
|
|
|
|
+ let cameraVRNeedsUpdate = false; // check if it's necessary to rebuild cameraVR's camera list
|
|
|
|
|
|
- if (pose !== null) {
|
|
|
|
- const views = pose.views;
|
|
|
|
- const baseLayer = session.renderState.baseLayer;
|
|
|
|
- state.bindXRFramebuffer(baseLayer.framebuffer);
|
|
|
|
- let cameraVRNeedsUpdate = false; // check if it's necessary to rebuild cameraVR's camera list
|
|
|
|
|
|
+ if (views.length !== cameraVR.cameras.length) {
|
|
|
|
+ cameraVR.cameras.length = 0;
|
|
|
|
+ cameraVRNeedsUpdate = true;
|
|
|
|
+ }
|
|
|
|
|
|
- if (views.length !== cameraVR.cameras.length) {
|
|
|
|
- cameraVR.cameras.length = 0;
|
|
|
|
- cameraVRNeedsUpdate = true;
|
|
|
|
- }
|
|
|
|
|
|
+ for (let i = 0; i < views.length; i++) {
|
|
|
|
+ const view = views[i];
|
|
|
|
+ const viewport = baseLayer.getViewport(view);
|
|
|
|
+ const camera = cameras[i];
|
|
|
|
+ camera.matrix.fromArray(view.transform.matrix);
|
|
|
|
+ camera.projectionMatrix.fromArray(view.projectionMatrix);
|
|
|
|
+ camera.viewport.set(viewport.x, viewport.y, viewport.width, viewport.height);
|
|
|
|
|
|
- for (let i = 0; i < views.length; i++) {
|
|
|
|
- const view = views[i];
|
|
|
|
- const viewport = baseLayer.getViewport(view);
|
|
|
|
- const camera = cameras[i];
|
|
|
|
- camera.matrix.fromArray(view.transform.matrix);
|
|
|
|
- camera.projectionMatrix.fromArray(view.projectionMatrix);
|
|
|
|
- camera.viewport.set(viewport.x, viewport.y, viewport.width, viewport.height);
|
|
|
|
|
|
+ if (i === 0) {
|
|
|
|
+ cameraVR.matrix.copy(camera.matrix);
|
|
|
|
+ }
|
|
|
|
|
|
- if (i === 0) {
|
|
|
|
- cameraVR.matrix.copy(camera.matrix);
|
|
|
|
|
|
+ if (cameraVRNeedsUpdate === true) {
|
|
|
|
+ cameraVR.cameras.push(camera);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+ } //
|
|
|
|
|
|
- if (cameraVRNeedsUpdate === true) {
|
|
|
|
- cameraVR.cameras.push(camera);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- } //
|
|
|
|
|
|
|
|
|
|
+ const inputSources = session.inputSources;
|
|
|
|
|
|
- const inputSources = session.inputSources;
|
|
|
|
|
|
+ for (let i = 0; i < controllers.length; i++) {
|
|
|
|
+ const controller = controllers[i];
|
|
|
|
+ const inputSource = inputSources[i];
|
|
|
|
+ controller.update(inputSource, frame, referenceSpace);
|
|
|
|
+ }
|
|
|
|
|
|
- for (let i = 0; i < controllers.length; i++) {
|
|
|
|
- const controller = controllers[i];
|
|
|
|
- const inputSource = inputSources[i];
|
|
|
|
- controller.update(inputSource, frame, referenceSpace);
|
|
|
|
|
|
+ if (onAnimationFrameCallback) onAnimationFrameCallback(time, frame);
|
|
}
|
|
}
|
|
|
|
|
|
- if (onAnimationFrameCallback) onAnimationFrameCallback(time, frame);
|
|
|
|
- }
|
|
|
|
|
|
+ const animation = new WebGLAnimation();
|
|
|
|
+ animation.setAnimationLoop(onAnimationFrame);
|
|
|
|
|
|
- const animation = new WebGLAnimation();
|
|
|
|
- animation.setAnimationLoop(onAnimationFrame);
|
|
|
|
|
|
+ this.setAnimationLoop = function (callback) {
|
|
|
|
+ onAnimationFrameCallback = callback;
|
|
|
|
+ };
|
|
|
|
|
|
- this.setAnimationLoop = function (callback) {
|
|
|
|
- onAnimationFrameCallback = callback;
|
|
|
|
- };
|
|
|
|
|
|
+ this.dispose = function () {};
|
|
|
|
+ }
|
|
|
|
|
|
- this.dispose = function () {};
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- Object.assign(WebXRManager.prototype, EventDispatcher.prototype);
|
|
|
|
-
|
|
|
|
function WebGLMaterials(properties) {
|
|
function WebGLMaterials(properties) {
|
|
function refreshFogUniforms(uniforms, fog) {
|
|
function refreshFogUniforms(uniforms, fog) {
|
|
uniforms.fogColor.value.copy(fog.color);
|
|
uniforms.fogColor.value.copy(fog.color);
|