threepipe
Version:
A modern 3D viewer framework built on top of three.js, written in TypeScript, designed to make creating high-quality, modular, and extensible 3D experiences on the web simple and enjoyable.
145 lines • 7.06 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { Euler, EventDispatcher, MathUtils, Quaternion, Vector3 } from 'three';
import { now, serialize } from 'ts-browser-helpers';
import { uiButton, uiPanelContainer, uiSlider } from 'uiconfig.js';
// eslint-disable-next-line @typescript-eslint/naming-convention
const _zee = new Vector3(0, 0, 1);
// eslint-disable-next-line @typescript-eslint/naming-convention
const _euler = new Euler();
// eslint-disable-next-line @typescript-eslint/naming-convention
const _q0 = new Quaternion();
// eslint-disable-next-line @typescript-eslint/naming-convention
const _q1 = new Quaternion(-Math.sqrt(0.5), 0, 0, Math.sqrt(0.5)); // - PI/2 around the x-axis
// eslint-disable-next-line @typescript-eslint/naming-convention
const _q2 = new Quaternion(); // - PI/2 around the x-axis
// eslint-disable-next-line @typescript-eslint/naming-convention
const _changeEvent = { type: 'change' };
const EPS = 0.000001;
let DeviceOrientationControls2 = class DeviceOrientationControls2 extends EventDispatcher {
constructor(object) {
super();
this.enabled = false; // do not serialize this as it signifies weather this is active.
this.lastOrder = 'XYZ';
this.dampingFactor = 0.05;
this.lastQuaternion = new Quaternion();
this.onDeviceOrientationChangeEvent = (event) => {
this.deviceOrientation = event;
};
this.onScreenOrientationChangeEvent = () => {
this.screenOrientation = screen.orientation;
};
this._initQuaternion = new Quaternion();
this._initQuaternionInvert = new Quaternion();
this._initQuaternionDest = new Quaternion();
this._lastTime = -1;
if (window.isSecureContext === false) {
console.error('DeviceOrientationControls2: DeviceOrientationEvent is only available in secure contexts (https)');
}
this.object = object;
this.lastOrder = this.object.rotation.order;
this.object.rotation.reorder('YXZ');
// this.enabled = true
this.connect();
}
resetView() {
this._initQuaternionDest.__init = false;
}
connect() {
if (this.enabled)
return;
this.onScreenOrientationChangeEvent(); // run once on load
// iOS 13+
if (window.DeviceOrientationEvent !== undefined && typeof window.DeviceOrientationEvent.requestPermission === 'function') {
window.DeviceOrientationEvent.requestPermission().then((response) => {
if (response == 'granted') {
window.addEventListener('orientationchange', this.onScreenOrientationChangeEvent);
window.addEventListener('deviceorientation', this.onDeviceOrientationChangeEvent);
}
}).catch((error) => {
console.error('DeviceOrientationControls2: Unable to use DeviceOrientation API:', error);
});
}
else {
window.addEventListener('orientationchange', this.onScreenOrientationChangeEvent);
window.addEventListener('deviceorientation', this.onDeviceOrientationChangeEvent);
}
this.enabled = true;
this._initQuaternion.copy(this.object.quaternion);
this._initQuaternionInvert.copy(this.object.quaternion).invert();
}
disconnect() {
if (!this.enabled)
return;
window.removeEventListener('orientationchange', this.onScreenOrientationChangeEvent);
window.removeEventListener('deviceorientation', this.onDeviceOrientationChangeEvent);
this._initQuaternion.identity();
this._initQuaternionInvert.identity();
this._initQuaternionDest = new Quaternion(); // need to set a new instance here.
this.object.rotation.reorder(this.lastOrder);
this.lastOrder = 'XYZ';
this.enabled = false;
}
update() {
if (!this.enabled)
return;
const device = this.deviceOrientation;
if (device) {
const alpha = device.alpha !== null ? MathUtils.degToRad(device.alpha) : 0; // Z
const beta = device.beta !== null ? MathUtils.degToRad(device.beta) : 0; // X'
const gamma = device.gamma !== null ? MathUtils.degToRad(device.gamma) : 0; // Y''
const orient = this.screenOrientation ? MathUtils.degToRad(this.screenOrientation.angle) : 0; // O
this.setObjectQuaternion(alpha, beta, gamma, orient);
if (8 * (1 - this.lastQuaternion.dot(this.object.quaternion)) > EPS) {
this.lastQuaternion.copy(this.object.quaternion);
this.dispatchEvent(_changeEvent);
}
}
}
dispose() {
this.disconnect();
}
// The angles alpha, beta and gamma form a set of intrinsic Tait-Bryan angles of type Z-X'-Y''
setObjectQuaternion(alpha, beta, gamma, orient) {
// if(_lastTime < 0)
const time = now() / 1000;
_euler.set(beta, alpha, -gamma, 'YXZ'); // 'ZXY' for the device, but 'YXZ' for us
_q2.setFromEuler(_euler); // orient the device
_q2.multiply(_q1); // camera looks out the back of the device, not the top
_q2.multiply(_q0.setFromAxisAngle(_zee, -orient)); // adjust for screen orientation
// debugger
if (!this._initQuaternionDest.__init) {
this._initQuaternionDest.copy(_q2).invert();
this._initQuaternionDest.__init = true;
}
_q2.premultiply(this._initQuaternionDest);
const mTime = 1 / 60;
this.object.quaternion.multiply(this._initQuaternionInvert);
this.object.quaternion.slerp(_q2, this.dampingFactor / (Math.min(1, time - this._lastTime) / mTime));
this.object.quaternion.multiply(this._initQuaternion);
// console.log(time - this._lastTime, mTime)
this._lastTime = time;
}
};
__decorate([
serialize(),
uiSlider('Damping', [0, 1], 0.01)
], DeviceOrientationControls2.prototype, "dampingFactor", void 0);
__decorate([
uiButton('Reset View')
], DeviceOrientationControls2.prototype, "resetView", null);
__decorate([
uiButton()
], DeviceOrientationControls2.prototype, "connect", null);
__decorate([
uiButton()
], DeviceOrientationControls2.prototype, "disconnect", null);
DeviceOrientationControls2 = __decorate([
uiPanelContainer('Device Orientation Controls')
], DeviceOrientationControls2);
export { DeviceOrientationControls2 };
//# sourceMappingURL=DeviceOrientationControls2.js.map