UNPKG

296 kBJavaScriptView Raw
1/*
2Copyright (c) 2020-present NAVER Corp.
3name: @egjs/view3d
4license: MIT
5author: NAVER Corp.
6repository: https://github.com/naver/egjs-view3d
7version: 1.1.0
8*/
9(function (global, factory) {
10 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('three'), require('three/examples/jsm/loaders/DRACOLoader'), require('three/examples/jsm/loaders/GLTFLoader'), require('three/examples/jsm/loaders/RGBELoader')) :
11 typeof define === 'function' && define.amd ? define(['three', 'three/examples/jsm/loaders/DRACOLoader', 'three/examples/jsm/loaders/GLTFLoader', 'three/examples/jsm/loaders/RGBELoader'], factory) :
12 (global = global || self, global.View3D = factory(global.THREE, global.DRACOLoader, global.GLTFLoader$1, global.RGBELoader));
13}(this, (function (THREE, DRACOLoader, GLTFLoader$1, RGBELoader) { 'use strict';
14
15 /*! *****************************************************************************
16 Copyright (c) Microsoft Corporation. All rights reserved.
17 Licensed under the Apache License, Version 2.0 (the "License"); you may not use
18 this file except in compliance with the License. You may obtain a copy of the
19 License at http://www.apache.org/licenses/LICENSE-2.0
20
21 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
22 KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
23 WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
24 MERCHANTABLITY OR NON-INFRINGEMENT.
25
26 See the Apache Version 2.0 License for specific language governing permissions
27 and limitations under the License.
28 ***************************************************************************** */
29
30 /* global Reflect, Promise */
31 var extendStatics = function (d, b) {
32 extendStatics = Object.setPrototypeOf || {
33 __proto__: []
34 } instanceof Array && function (d, b) {
35 d.__proto__ = b;
36 } || function (d, b) {
37 for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
38 };
39
40 return extendStatics(d, b);
41 };
42
43 function __extends(d, b) {
44 extendStatics(d, b);
45
46 function __() {
47 this.constructor = d;
48 }
49
50 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
51 }
52 var __assign = function () {
53 __assign = Object.assign || function __assign(t) {
54 for (var s, i = 1, n = arguments.length; i < n; i++) {
55 s = arguments[i];
56
57 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
58 }
59
60 return t;
61 };
62
63 return __assign.apply(this, arguments);
64 };
65 function __awaiter(thisArg, _arguments, P, generator) {
66 function adopt(value) {
67 return value instanceof P ? value : new P(function (resolve) {
68 resolve(value);
69 });
70 }
71
72 return new (P || (P = Promise))(function (resolve, reject) {
73 function fulfilled(value) {
74 try {
75 step(generator.next(value));
76 } catch (e) {
77 reject(e);
78 }
79 }
80
81 function rejected(value) {
82 try {
83 step(generator["throw"](value));
84 } catch (e) {
85 reject(e);
86 }
87 }
88
89 function step(result) {
90 result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
91 }
92
93 step((generator = generator.apply(thisArg, _arguments || [])).next());
94 });
95 }
96 function __generator(thisArg, body) {
97 var _ = {
98 label: 0,
99 sent: function () {
100 if (t[0] & 1) throw t[1];
101 return t[1];
102 },
103 trys: [],
104 ops: []
105 },
106 f,
107 y,
108 t,
109 g;
110 return g = {
111 next: verb(0),
112 "throw": verb(1),
113 "return": verb(2)
114 }, typeof Symbol === "function" && (g[Symbol.iterator] = function () {
115 return this;
116 }), g;
117
118 function verb(n) {
119 return function (v) {
120 return step([n, v]);
121 };
122 }
123
124 function step(op) {
125 if (f) throw new TypeError("Generator is already executing.");
126
127 while (_) try {
128 if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
129 if (y = 0, t) op = [op[0] & 2, t.value];
130
131 switch (op[0]) {
132 case 0:
133 case 1:
134 t = op;
135 break;
136
137 case 4:
138 _.label++;
139 return {
140 value: op[1],
141 done: false
142 };
143
144 case 5:
145 _.label++;
146 y = op[1];
147 op = [0];
148 continue;
149
150 case 7:
151 op = _.ops.pop();
152
153 _.trys.pop();
154
155 continue;
156
157 default:
158 if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
159 _ = 0;
160 continue;
161 }
162
163 if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
164 _.label = op[1];
165 break;
166 }
167
168 if (op[0] === 6 && _.label < t[1]) {
169 _.label = t[1];
170 t = op;
171 break;
172 }
173
174 if (t && _.label < t[2]) {
175 _.label = t[2];
176
177 _.ops.push(op);
178
179 break;
180 }
181
182 if (t[2]) _.ops.pop();
183
184 _.trys.pop();
185
186 continue;
187 }
188
189 op = body.call(thisArg, _);
190 } catch (e) {
191 op = [6, e];
192 y = 0;
193 } finally {
194 f = t = 0;
195 }
196
197 if (op[0] & 5) throw op[1];
198 return {
199 value: op[0] ? op[1] : void 0,
200 done: true
201 };
202 }
203 }
204 function __values(o) {
205 var s = typeof Symbol === "function" && Symbol.iterator,
206 m = s && o[s],
207 i = 0;
208 if (m) return m.call(o);
209 if (o && typeof o.length === "number") return {
210 next: function () {
211 if (o && i >= o.length) o = void 0;
212 return {
213 value: o && o[i++],
214 done: !o
215 };
216 }
217 };
218 throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
219 }
220 function __read(o, n) {
221 var m = typeof Symbol === "function" && o[Symbol.iterator];
222 if (!m) return o;
223 var i = m.call(o),
224 r,
225 ar = [],
226 e;
227
228 try {
229 while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
230 } catch (error) {
231 e = {
232 error: error
233 };
234 } finally {
235 try {
236 if (r && !r.done && (m = i["return"])) m.call(i);
237 } finally {
238 if (e) throw e.error;
239 }
240 }
241
242 return ar;
243 }
244 function __spread() {
245 for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
246
247 return ar;
248 }
249
250 /*
251 * Copyright (c) 2020 NAVER Corp.
252 * egjs projects are licensed under the MIT license
253 */
254
255 var EventEmitter =
256 /*#__PURE__*/
257 function () {
258 function EventEmitter() {
259 this._listenerMap = {};
260 }
261
262 var __proto = EventEmitter.prototype;
263
264 __proto.on = function (eventName, callback) {
265 var listenerMap = this._listenerMap;
266 var listeners = listenerMap[eventName];
267
268 if (listeners && listeners.indexOf(callback) < 0) {
269 listeners.push(callback);
270 } else {
271 listenerMap[eventName] = [callback];
272 }
273
274 return this;
275 };
276
277 __proto.once = function (eventName, callback) {
278
279 var listenerMap = this._listenerMap;
280 var listeners = listenerMap[eventName];
281
282 if (listeners && listeners.indexOf(callback) < 0) {
283 listeners.push(callback);
284 } else {
285 listenerMap[eventName] = [callback];
286 }
287
288 return this;
289 };
290
291 __proto.off = function (eventName, callback) {
292 var listenerMap = this._listenerMap;
293
294 if (!eventName) {
295 this._listenerMap = {};
296 return this;
297 }
298
299 if (!callback) {
300 delete listenerMap[eventName];
301 return this;
302 }
303
304 var listeners = listenerMap[eventName];
305
306 if (listeners) {
307 var callbackIdx = listeners.indexOf(callback);
308
309 if (callbackIdx >= 0) {
310 listeners.splice(callbackIdx, 1);
311 }
312 }
313
314 return this;
315 };
316
317 __proto.emit = function (eventName) {
318 var event = [];
319
320 for (var _i = 1; _i < arguments.length; _i++) {
321 event[_i - 1] = arguments[_i];
322 }
323
324 var listeners = this._listenerMap[eventName];
325
326 if (listeners) {
327 listeners.forEach(function (callback) {
328 callback.apply(void 0, __spread(event));
329 });
330 }
331
332 return this;
333 };
334
335 return EventEmitter;
336 }();
337
338 /*
339 * Copyright (c) 2020 NAVER Corp.
340 * egjs projects are licensed under the MIT license
341 */
342 /**
343 * Renderer that renders View3D's Scene
344 * @category Core
345 */
346
347 var Renderer =
348 /*#__PURE__*/
349 function () {
350 /**
351 * Create new Renderer instance
352 * @param canvas \<canvas\> element to render 3d model
353 */
354 function Renderer(canvas) {
355 this._canvas = canvas;
356 this._renderer = new THREE.WebGLRenderer({
357 canvas: this._canvas,
358 alpha: true,
359 antialias: true,
360 preserveDrawingBuffer: true
361 });
362 this._renderer.xr.enabled = true;
363 this._renderer.outputEncoding = THREE.sRGBEncoding;
364 this._clock = new THREE.Clock(false);
365 this.enableShadow();
366 }
367
368 var __proto = Renderer.prototype;
369 Object.defineProperty(__proto, "canvas", {
370 /**
371 * {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement HTMLCanvasElement} given when creating View3D instance
372 * @type HTMLCanvasElement
373 * @readonly
374 */
375 get: function () {
376 return this._canvas;
377 },
378 enumerable: false,
379 configurable: true
380 });
381 Object.defineProperty(__proto, "context", {
382 /**
383 * Current {@link https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext WebGLRenderingContext}
384 * @type WebGLRenderingContext
385 * @readonly
386 */
387 get: function () {
388 return this._renderer.context;
389 },
390 enumerable: false,
391 configurable: true
392 });
393 Object.defineProperty(__proto, "size", {
394 /**
395 * The width and height of the renderer's output canvas
396 * @see https://threejs.org/docs/#api/en/math/Vector2
397 * @type THREE.Vector2
398 */
399 get: function () {
400 return this._renderer.getSize(new THREE.Vector2());
401 },
402 set: function (val) {
403 this._renderer.setSize(val.x, val.y, false);
404 },
405 enumerable: false,
406 configurable: true
407 });
408 Object.defineProperty(__proto, "threeRenderer", {
409 /**
410 * Three.js {@link https://threejs.org/docs/#api/en/renderers/WebGLRenderer WebGLRenderer} instance
411 * @type THREE.WebGLRenderer
412 * @readonly
413 */
414 get: function () {
415 return this._renderer;
416 },
417 enumerable: false,
418 configurable: true
419 });
420 /**
421 * Resize the renderer based on current canvas width / height
422 * @returns {void} Nothing
423 */
424
425 __proto.resize = function () {
426 var renderer = this._renderer;
427 var canvas = this._canvas;
428 if (renderer.xr.isPresenting) return;
429 renderer.setPixelRatio(window.devicePixelRatio);
430 renderer.setSize(canvas.offsetWidth, canvas.offsetHeight, false);
431 };
432 /**
433 * Render a scene using a camera.
434 * @see https://threejs.org/docs/#api/en/renderers/WebGLRenderer.render
435 * @param scene {@link Scene} to render
436 * @param camera {@link Camera} to render
437 */
438
439
440 __proto.render = function (scene, camera) {
441 this._renderer.render(scene.root, camera.threeCamera);
442 };
443
444 __proto.setAnimationLoop = function (callback) {
445 var _this = this;
446
447 this._clock.start();
448
449 this._renderer.setAnimationLoop(function (timestamp, frame) {
450 var delta = _this._clock.getDelta();
451
452 callback(delta, frame);
453 });
454 };
455
456 __proto.stopAnimationLoop = function () {
457 this._clock.stop(); // See https://threejs.org/docs/#api/en/renderers/WebGLRenderer.setAnimationLoop
458
459
460 this._renderer.setAnimationLoop(null);
461 };
462 /**
463 * Enable shadow map
464 */
465
466
467 __proto.enableShadow = function () {
468 var threeRenderer = this._renderer;
469 threeRenderer.shadowMap.enabled = true;
470 threeRenderer.shadowMap.type = THREE.PCFSoftShadowMap;
471 };
472 /**
473 * Disable shadow map
474 */
475
476
477 __proto.disableShadow = function () {
478 var threeRenderer = this._renderer;
479 threeRenderer.shadowMap.enabled = false;
480 };
481
482 return Renderer;
483 }();
484
485 /*
486 * Copyright (c) 2020 NAVER Corp.
487 * egjs projects are licensed under the MIT license
488 */
489 // Constants that used internally
490 // Texture map names that used in THREE#MeshStandardMaterial
491 var STANDARD_MAPS = ["alphaMap", "aoMap", "bumpMap", "displacementMap", "emissiveMap", "envMap", "lightMap", "map", "metalnessMap", "normalMap", "roughnessMap"];
492
493 /*
494 * Copyright (c) 2020 NAVER Corp.
495 * egjs projects are licensed under the MIT license
496 */
497
498 var View3DError =
499 /*#__PURE__*/
500 function (_super) {
501 __extends(View3DError, _super);
502
503 function View3DError(message, code) {
504 var _this = _super.call(this, message) || this;
505
506 _this.message = message;
507 _this.code = code;
508 Object.setPrototypeOf(_this, View3DError.prototype);
509 _this.name = "View3DError";
510 return _this;
511 }
512
513 return View3DError;
514 }(Error);
515
516 /*
517 * Copyright (c) 2020 NAVER Corp.
518 * egjs projects are licensed under the MIT license
519 */
520
521 /**
522 * Error codes of {@link View3DError}
523 * @name ERROR_CODES
524 * @memberof Constants
525 * @type object
526 * @property {number} WRONG_TYPE 0
527 * @property {number} ELEMENT_NOT_FOUND 1
528 * @property {number} CANVAS_NOT_FOUND 2
529 * @property {number} WEBGL_NOT_SUPPORTED 3
530 * @property {number} ADD_CONTROL_FIRST 4
531 * @property {number} PROVIDE_WIDTH_OR_HEIGHT 5
532 */
533 var CODES = {
534 WRONG_TYPE: 0,
535 ELEMENT_NOT_FOUND: 1,
536 ELEMENT_NOT_CANVAS: 2,
537 WEBGL_NOT_SUPPORTED: 3,
538 ADD_CONTROL_FIRST: 4,
539 PROVIDE_WIDTH_OR_HEIGHT: 5
540 };
541 var MESSAGES = {
542 WRONG_TYPE: function (val, types) {
543 return typeof val + " is not a " + types.map(function (type) {
544 return "\"" + type + "\"";
545 }).join(" or ") + ".";
546 },
547 ELEMENT_NOT_FOUND: function (query) {
548 return "Element with selector \"" + query + "\" not found.";
549 },
550 ELEMENT_NOT_CANVAS: function (el) {
551 return "Given element <" + el.tagName + "> is not a canvas.";
552 },
553 WEBGL_NOT_SUPPORTED: "WebGL is not supported on this browser.",
554 ADD_CONTROL_FIRST: "Control is enabled before setting a target element.",
555 PROVIDE_WIDTH_OR_HEIGHT: "Either width or height should be given."
556 };
557
558 /*
559 * Copyright (c) 2020 NAVER Corp.
560 * egjs projects are licensed under the MIT license
561 */
562 function getElement(el, parent) {
563 var targetEl = null;
564
565 if (typeof el === "string") {
566 var parentEl = parent ? parent : document;
567 var queryResult = parentEl.querySelector(el);
568
569 if (!queryResult) {
570 throw new View3DError(MESSAGES.ELEMENT_NOT_FOUND(el), CODES.ELEMENT_NOT_FOUND);
571 }
572
573 targetEl = queryResult;
574 } else if (el && el.nodeType === Node.ELEMENT_NODE) {
575 targetEl = el;
576 }
577
578 return targetEl;
579 }
580 function getCanvas(el) {
581 var targetEl = getElement(el);
582
583 if (!targetEl) {
584 throw new View3DError(MESSAGES.WRONG_TYPE(el, ["HTMLElement", "string"]), CODES.WRONG_TYPE);
585 }
586
587 if (!/^canvas$/i.test(targetEl.tagName)) {
588 throw new View3DError(MESSAGES.ELEMENT_NOT_CANVAS(targetEl), CODES.ELEMENT_NOT_CANVAS);
589 }
590
591 return targetEl;
592 }
593 function range(end) {
594 if (!end || end <= 0) {
595 return [];
596 }
597
598 return Array.apply(0, Array(end)).map(function (undef, idx) {
599 return idx;
600 });
601 }
602 function toRadian(x) {
603 return x * Math.PI / 180;
604 }
605 function clamp(x, min, max) {
606 return Math.max(Math.min(x, max), min);
607 }
608 function findIndex(target, list) {
609 var e_1, _a;
610
611 var index = -1;
612
613 try {
614 for (var _b = __values(range(list.length)), _c = _b.next(); !_c.done; _c = _b.next()) {
615 var itemIndex = _c.value;
616
617 if (list[itemIndex] === target) {
618 index = itemIndex;
619 break;
620 }
621 }
622 } catch (e_1_1) {
623 e_1 = {
624 error: e_1_1
625 };
626 } finally {
627 try {
628 if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
629 } finally {
630 if (e_1) throw e_1.error;
631 }
632 }
633
634 return index;
635 } // Linear interpolation between a and b
636
637 function mix(a, b, t) {
638 return a * (1 - t) + b * t;
639 }
640 function circulate(val, min, max) {
641 var size = Math.abs(max - min);
642
643 if (val < min) {
644 var offset = (min - val) % size;
645 val = max - offset;
646 } else if (val > max) {
647 var offset = (val - max) % size;
648 val = min + offset;
649 }
650
651 return val;
652 }
653 function merge(target) {
654 var srcs = [];
655
656 for (var _i = 1; _i < arguments.length; _i++) {
657 srcs[_i - 1] = arguments[_i];
658 }
659
660 srcs.forEach(function (source) {
661 Object.keys(source).forEach(function (key) {
662 var value = source[key];
663
664 if (Array.isArray(target[key]) && Array.isArray(value)) {
665 target[key] = __spread(target[key], value);
666 } else {
667 target[key] = value;
668 }
669 });
670 });
671 return target;
672 }
673 function getBoxPoints(box) {
674 return [box.min.clone(), new THREE.Vector3(box.min.x, box.min.y, box.max.z), new THREE.Vector3(box.min.x, box.max.y, box.min.z), new THREE.Vector3(box.min.x, box.max.y, box.max.z), new THREE.Vector3(box.max.x, box.min.y, box.min.z), new THREE.Vector3(box.max.x, box.min.y, box.max.z), new THREE.Vector3(box.max.x, box.max.y, box.min.z), box.max.clone()];
675 }
676 function toPowerOfTwo(val) {
677 var result = 1;
678
679 while (result < val) {
680 result *= 2;
681 }
682
683 return result;
684 }
685 function getPrimaryAxisIndex(basis, viewDir) {
686 var primaryIdx = 0;
687 var maxDot = 0;
688 basis.forEach(function (axes, axesIdx) {
689 var dotProduct = Math.abs(viewDir.dot(axes));
690
691 if (dotProduct > maxDot) {
692 primaryIdx = axesIdx;
693 maxDot = dotProduct;
694 }
695 });
696 return primaryIdx;
697 } // In radian
698
699 function getRotationAngle(center, v1, v2) {
700 var centerToV1 = new THREE.Vector2().subVectors(v1, center).normalize();
701 var centerToV2 = new THREE.Vector2().subVectors(v2, center).normalize(); // Get the rotation angle with the model's NDC coordinates as the center.
702
703 var deg = centerToV2.angle() - centerToV1.angle();
704 var compDeg = -Math.sign(deg) * (2 * Math.PI - Math.abs(deg)); // Take the smaller deg
705
706 var rotationAngle = Math.abs(deg) < Math.abs(compDeg) ? deg : compDeg;
707 return rotationAngle;
708 }
709
710 /*
711 * Copyright (c) 2020 NAVER Corp.
712 * egjs projects are licensed under the MIT license
713 */
714 /**
715 * Scene that View3D will render.
716 * All model datas including Mesh, Lights, etc. will be included on this
717 * @category Core
718 */
719
720 var Scene =
721 /*#__PURE__*/
722 function () {
723 /**
724 * Create new Scene instance
725 */
726 function Scene() {
727 this._root = new THREE.Scene();
728 this._userObjects = new THREE.Group();
729 this._envObjects = new THREE.Group();
730 this._envs = [];
731 var root = this._root;
732 var userObjects = this._userObjects;
733 var envObjects = this._envObjects;
734 userObjects.name = "userObjects";
735 envObjects.name = "envObjects";
736 root.add(userObjects);
737 root.add(envObjects);
738 }
739
740 var __proto = Scene.prototype;
741 Object.defineProperty(__proto, "root", {
742 /**
743 * Root {@link https://threejs.org/docs/#api/en/scenes/Scene THREE.Scene} object
744 */
745 get: function () {
746 return this._root;
747 },
748 enumerable: false,
749 configurable: true
750 });
751 Object.defineProperty(__proto, "environments", {
752 /**
753 * {@link Environment}s inside scene
754 */
755 get: function () {
756 return this._envs;
757 },
758 enumerable: false,
759 configurable: true
760 });
761 Object.defineProperty(__proto, "visible", {
762 /**
763 * Return the visibility of the root scene
764 */
765 get: function () {
766 return this._root.visible;
767 },
768 enumerable: false,
769 configurable: true
770 });
771 /**
772 * Update scene to fit the given model
773 * @param model model to fit
774 * @param override options for specific environments
775 */
776
777 __proto.update = function (model, override) {
778 this._envs.forEach(function (env) {
779 return env.fit(model, override);
780 });
781 };
782 /**
783 * Reset scene to initial state
784 * @returns {void} Nothing
785 */
786
787
788 __proto.reset = function () {
789 this.resetModel();
790 this.resetEnv();
791 };
792 /**
793 * Fully remove all objects that added by calling {@link Scene#add add()}
794 * @returns {void} Nothing
795 */
796
797
798 __proto.resetModel = function () {
799 this._removeChildsOf(this._userObjects);
800 };
801 /**
802 * Remove all objects that added by calling {@link Scene#addEnv addEnv()}
803 * This will also reset scene background & envmap
804 * @returns {void} Nothing
805 */
806
807
808 __proto.resetEnv = function () {
809 this._removeChildsOf(this._envObjects);
810
811 this._envs = [];
812 this._root.background = null;
813 this._root.environment = null;
814 };
815 /**
816 * Add new Three.js {@link https://threejs.org/docs/#api/en/core/Object3D Object3D} into the scene
817 * @param object {@link https://threejs.org/docs/#api/en/core/Object3D THREE.Object3D}s to add
818 * @returns {void} Nothing
819 */
820
821
822 __proto.add = function () {
823 var _a;
824
825 var object = [];
826
827 for (var _i = 0; _i < arguments.length; _i++) {
828 object[_i] = arguments[_i];
829 }
830
831 (_a = this._userObjects).add.apply(_a, __spread(object));
832 };
833 /**
834 * Add new {@link Environment} or Three.js {@link https://threejs.org/docs/#api/en/core/Object3D Object3D}s to the scene, which won't be removed after displaying another 3D model
835 * @param envs {@link Environment} | {@link https://threejs.org/docs/#api/en/core/Object3D THREE.Object3D}s to add
836 * @returns {void} Nothing
837 */
838
839
840 __proto.addEnv = function () {
841 var _this = this;
842
843 var envs = [];
844
845 for (var _i = 0; _i < arguments.length; _i++) {
846 envs[_i] = arguments[_i];
847 }
848
849 envs.forEach(function (env) {
850 var _a;
851
852 if (env.isObject3D) {
853 _this._envObjects.add(env);
854 } else {
855 _this._envs.push(env);
856
857 (_a = _this._envObjects).add.apply(_a, __spread(env.objects));
858 }
859 });
860 };
861 /**
862 * Remove Three.js {@link https://threejs.org/docs/#api/en/core/Object3D Object3D} into the scene
863 * @param object {@link https://threejs.org/docs/#api/en/core/Object3D THREE.Object3D}s to add
864 * @returns {void} Nothing
865 */
866
867
868 __proto.remove = function () {
869 var _a;
870
871 var object = [];
872
873 for (var _i = 0; _i < arguments.length; _i++) {
874 object[_i] = arguments[_i];
875 }
876
877 (_a = this._userObjects).remove.apply(_a, __spread(object));
878 };
879 /**
880 * Remove {@link Environment} or Three.js {@link https://threejs.org/docs/#api/en/core/Object3D Object3D}s to the scene, which won't be removed after displaying another 3D model
881 * @param envs {@link Environment} | {@link https://threejs.org/docs/#api/en/core/Object3D THREE.Object3D}s to add
882 * @returns {void} Nothing
883 */
884
885
886 __proto.removeEnv = function () {
887 var _this = this;
888
889 var envs = [];
890
891 for (var _i = 0; _i < arguments.length; _i++) {
892 envs[_i] = arguments[_i];
893 }
894
895 envs.forEach(function (env) {
896 var _a;
897
898 if (env.isObject3D) {
899 _this._envObjects.remove(env);
900 } else {
901 var envIndex = findIndex(env, _this._envs);
902
903 if (envIndex > -1) {
904 _this._envs.splice(envIndex, 1);
905 }
906
907 (_a = _this._envObjects).remove.apply(_a, __spread(env.objects));
908 }
909 });
910 };
911 /**
912 * Set background of the scene.
913 * @see {@link https://threejs.org/docs/#api/en/scenes/Scene.background THREE.Scene.background}
914 * @param background A texture to set as background
915 * @returns {void} Nothing
916 */
917
918
919 __proto.setBackground = function (background) {
920 // Three.js's type definition does not include WebGLCubeRenderTarget, but it works and defined on their document
921 // See https://threejs.org/docs/#api/en/scenes/Scene.background
922 this._root.background = background;
923 };
924 /**
925 * Set scene's environment map that affects all physical materials in the scene
926 * @see {@link https://threejs.org/docs/#api/en/scenes/Scene.environment THREE.Scene.environment}
927 * @param envmap A texture to set as environment map
928 * @returns {void} Nothing
929 */
930
931
932 __proto.setEnvMap = function (envmap) {
933 // Next line written to silence Three.js's warning
934 var environment = envmap.texture ? envmap.texture : envmap;
935 this._root.environment = environment;
936 };
937 /**
938 * Make this scene visible
939 * @returns {void} Nothing
940 */
941
942
943 __proto.show = function () {
944 this._root.visible = true;
945 };
946 /**
947 * Make this scene invisible
948 * @returns {void} Nothing
949 */
950
951
952 __proto.hide = function () {
953 this._root.visible = false;
954 };
955
956 __proto._removeChildsOf = function (obj) {
957 obj.traverse(function (child) {
958 if (child.isMesh) {
959 var mesh = child; // Release geometry & material memory
960
961 mesh.geometry.dispose();
962 var materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
963 materials.forEach(function (mat) {
964 STANDARD_MAPS.forEach(function (map) {
965 if (mat[map]) {
966 mat[map].dispose();
967 }
968 });
969 });
970 }
971 });
972
973 while (obj.children.length > 0) {
974 obj.remove(obj.children[0]);
975 }
976 };
977
978 return Scene;
979 }();
980
981 /*
982 * Copyright (c) 2020 NAVER Corp.
983 * egjs projects are licensed under the MIT license
984 */
985 /**
986 * Controller that controls camera of the View3D
987 * @category Core
988 */
989
990 var Controller =
991 /*#__PURE__*/
992 function () {
993 /**
994 * Create new Controller instance
995 */
996 function Controller(canvas, camera) {
997 this._controls = [];
998 this._canvas = canvas;
999 this._camera = camera;
1000 }
1001
1002 var __proto = Controller.prototype;
1003 Object.defineProperty(__proto, "controls", {
1004 /**
1005 * {@link CameraControl CameraControl} instances that is added on this controller.
1006 */
1007 get: function () {
1008 return this._controls;
1009 },
1010 enumerable: false,
1011 configurable: true
1012 });
1013 /**
1014 * Remove all attached controls, and removes all event listeners attached by that controls.
1015 * @returns {void} Nothing
1016 */
1017
1018 __proto.clear = function () {
1019 this._controls.forEach(function (control) {
1020 return control.destroy();
1021 });
1022
1023 this._controls = [];
1024 };
1025 /**
1026 * Add a new control
1027 * @param control {@link CameraControl CameraControl} instance to add
1028 * @see Adding Controls
1029 * @returns {void} Nothing
1030 */
1031
1032
1033 __proto.add = function (control) {
1034 var canvas = this._canvas;
1035
1036 if (!control.element) {
1037 // Set canvas as default element
1038 control.setElement(canvas);
1039 }
1040
1041 control.sync(this._camera);
1042 control.enable();
1043
1044 this._controls.push(control);
1045 };
1046 /**
1047 * Remove control and disable it
1048 * @param control {@link CameraControl CameraControl} instance to remove
1049 * @returns removed control or null if it doesn't exists
1050 */
1051
1052
1053 __proto.remove = function (control) {
1054 var controls = this._controls;
1055 var controlIndex = findIndex(control, controls);
1056 if (controlIndex < 0) return null;
1057 var removedControl = controls.splice(controlIndex, 1)[0];
1058 removedControl.disable();
1059 return removedControl;
1060 };
1061 /**
1062 * Enable all controls attached
1063 * @returns {void} Nothing
1064 */
1065
1066
1067 __proto.enableAll = function () {
1068 this._controls.forEach(function (control) {
1069 return control.enable();
1070 });
1071
1072 this.syncToCamera();
1073 };
1074 /**
1075 * Disable all controls attached
1076 * @returns {void} Nothing
1077 */
1078
1079
1080 __proto.disableAll = function () {
1081 this._controls.forEach(function (control) {
1082 return control.disable();
1083 });
1084 };
1085 /**
1086 * Update all controls attached to given screen size.
1087 * @param size Size of the screen. Noramlly size of the canvas is used.
1088 * @returns {void} Nothing
1089 */
1090
1091
1092 __proto.resize = function (size) {
1093 this._controls.forEach(function (control) {
1094 return control.resize(size);
1095 });
1096 };
1097 /**
1098 * Synchronize all controls attached to current camera position.
1099 * @returns {void} Nothing
1100 */
1101
1102
1103 __proto.syncToCamera = function () {
1104 var _this = this;
1105
1106 this._controls.forEach(function (control) {
1107 return control.sync(_this._camera);
1108 });
1109 };
1110 /**
1111 * Update all controls attached to this controller & update camera position based on it.
1112 * @param delta number of seconds to update controls
1113 * @returns {void} Nothing
1114 */
1115
1116
1117 __proto.update = function (delta) {
1118 var deltaMiliSec = delta * 1000;
1119 var camera = this._camera;
1120
1121 this._controls.forEach(function (control) {
1122 control.update(camera, deltaMiliSec);
1123 });
1124
1125 camera.updatePosition();
1126 };
1127
1128 return Controller;
1129 }();
1130
1131 /*
1132 * Copyright (c) 2020 NAVER Corp.
1133 * egjs projects are licensed under the MIT license
1134 */
1135 /**
1136 * Data class of camera's pose
1137 */
1138
1139 var Pose =
1140 /*#__PURE__*/
1141 function () {
1142 /**
1143 * Create new instance of pose
1144 * @param yaw yaw
1145 * @param pitch pitch
1146 * @param distance distance
1147 * @param pivot pivot
1148 * @see https://threejs.org/docs/#api/en/math/Vector3
1149 * @example
1150 * import { THREE, Pose } from "@egjs/view3d";
1151 *
1152 * const pose = new Pose(180, 45, 150, new THREE.Vector3(5, -1, 3));
1153 */
1154 function Pose(yaw, pitch, distance, pivot) {
1155 if (pivot === void 0) {
1156 pivot = new THREE.Vector3(0, 0, 0);
1157 }
1158
1159 this.yaw = yaw;
1160 this.pitch = pitch;
1161 this.distance = distance;
1162 this.pivot = pivot;
1163 }
1164 /**
1165 * Clone this pose
1166 * @returns Cloned pose
1167 */
1168
1169
1170 var __proto = Pose.prototype;
1171
1172 __proto.clone = function () {
1173 return new Pose(this.yaw, this.pitch, this.distance, this.pivot.clone());
1174 };
1175
1176 return Pose;
1177 }();
1178
1179 /*
1180 * Copyright (c) 2020 NAVER Corp.
1181 * egjs projects are licensed under the MIT license
1182 */
1183
1184 /**
1185 * Collection of easing functions
1186 * @namespace EASING
1187 * @example
1188 * import View3D, { RotateControl, EASING } from "@egjs/view3d";
1189 *
1190 * new RotateControl({
1191 * easing: EASING.EASE_OUT_CUBIC,
1192 * });
1193 */
1194
1195 /**
1196 * @memberof EASING
1197 * @name SINE_WAVE
1198 */
1199 var SINE_WAVE = function (x) {
1200 return Math.sin(x * Math.PI * 2);
1201 };
1202 /**
1203 * @memberof EASING
1204 * @name EASE_OUT_CUBIC
1205 */
1206
1207 var EASE_OUT_CUBIC = function (x) {
1208 return 1 - Math.pow(1 - x, 3);
1209 };
1210 /**
1211 * @memberof EASING
1212 * @name EASE_OUT_BOUNCE
1213 */
1214
1215 var EASE_OUT_BOUNCE = function (x) {
1216 var n1 = 7.5625;
1217 var d1 = 2.75;
1218
1219 if (x < 1 / d1) {
1220 return n1 * x * x;
1221 } else if (x < 2 / d1) {
1222 return n1 * (x -= 1.5 / d1) * x + 0.75;
1223 } else if (x < 2.5 / d1) {
1224 return n1 * (x -= 2.25 / d1) * x + 0.9375;
1225 } else {
1226 return n1 * (x -= 2.625 / d1) * x + 0.984375;
1227 }
1228 };
1229
1230 var EASING = {
1231 __proto__: null,
1232 SINE_WAVE: SINE_WAVE,
1233 EASE_OUT_CUBIC: EASE_OUT_CUBIC,
1234 EASE_OUT_BOUNCE: EASE_OUT_BOUNCE
1235 };
1236
1237 /*
1238 * Copyright (c) 2020 NAVER Corp.
1239 * egjs projects are licensed under the MIT license
1240 */
1241 var MODEL_SIZE = 80; // Animation related
1242
1243 var EASING$1 = EASE_OUT_CUBIC;
1244 var ANIMATION_DURATION = 500;
1245 var ANIMATION_LOOP = false;
1246 var ANIMATION_RANGE = {
1247 min: 0,
1248 max: 1
1249 }; // Camera related
1250
1251 var CAMERA_POSE = new Pose(0, 0, 100, new THREE.Vector3(0, 0, 0));
1252 var INFINITE_RANGE = {
1253 min: -Infinity,
1254 max: Infinity
1255 };
1256 var PITCH_RANGE = {
1257 min: -89.9,
1258 max: 89.9
1259 };
1260 var DISTANCE_RANGE = {
1261 min: 0,
1262 max: 500
1263 };
1264 var MINIMUM_DISTANCE = 1;
1265 var MAXIMUM_DISTANCE = 500;
1266 var NULL_ELEMENT = null;
1267 var DRACO_DECODER_URL = "https://www.gstatic.com/draco/v1/decoders/";
1268
1269 /*
1270 * Copyright (c) 2020 NAVER Corp.
1271 * egjs projects are licensed under the MIT license
1272 */
1273
1274 var Motion =
1275 /*#__PURE__*/
1276 function () {
1277 function Motion(_a) {
1278 var _b = _a === void 0 ? {} : _a,
1279 _c = _b.duration,
1280 duration = _c === void 0 ? ANIMATION_DURATION : _c,
1281 _d = _b.loop,
1282 loop = _d === void 0 ? ANIMATION_LOOP : _d,
1283 _e = _b.range,
1284 range = _e === void 0 ? ANIMATION_RANGE : _e,
1285 _f = _b.easing,
1286 easing = _f === void 0 ? EASING$1 : _f;
1287
1288 this._duration = duration;
1289 this._loop = loop;
1290 this._range = range;
1291 this._easing = easing;
1292 this._activated = false;
1293 this.reset(0);
1294 }
1295
1296 var __proto = Motion.prototype;
1297 Object.defineProperty(__proto, "val", {
1298 get: function () {
1299 return this._val;
1300 },
1301 enumerable: false,
1302 configurable: true
1303 });
1304 Object.defineProperty(__proto, "start", {
1305 get: function () {
1306 return this._start;
1307 },
1308 enumerable: false,
1309 configurable: true
1310 });
1311 Object.defineProperty(__proto, "end", {
1312 get: function () {
1313 return this._end;
1314 },
1315 enumerable: false,
1316 configurable: true
1317 });
1318 Object.defineProperty(__proto, "progress", {
1319 get: function () {
1320 return this._progress;
1321 },
1322 enumerable: false,
1323 configurable: true
1324 });
1325 Object.defineProperty(__proto, "duration", {
1326 get: function () {
1327 return this._duration;
1328 },
1329 set: function (val) {
1330 this._duration = val;
1331 },
1332 enumerable: false,
1333 configurable: true
1334 });
1335 Object.defineProperty(__proto, "loop", {
1336 get: function () {
1337 return this._loop;
1338 },
1339 set: function (val) {
1340 this._loop = val;
1341 },
1342 enumerable: false,
1343 configurable: true
1344 });
1345 Object.defineProperty(__proto, "range", {
1346 get: function () {
1347 return this._range;
1348 },
1349 set: function (val) {
1350 this._range = val;
1351 },
1352 enumerable: false,
1353 configurable: true
1354 });
1355 Object.defineProperty(__proto, "easing", {
1356 get: function () {
1357 return this._easing;
1358 },
1359 set: function (val) {
1360 this._easing = val;
1361 },
1362 enumerable: false,
1363 configurable: true
1364 });
1365 /**
1366 * Update motion and progress it by given deltaTime
1367 * @param deltaTime number of milisec to update motion
1368 * @returns Difference(delta) of the value from the last update.
1369 */
1370
1371 __proto.update = function (deltaTime) {
1372 if (!this._activated) return 0;
1373 var start = this._start;
1374 var end = this._end;
1375 var duration = this._duration;
1376 var prev = this._val;
1377 var loop = this._loop;
1378 var nextProgress = this._progress + deltaTime / duration;
1379 this._progress = loop ? circulate(nextProgress, 0, 1) : clamp(nextProgress, 0, 1);
1380
1381 var easedProgress = this._easing(this._progress);
1382
1383 this._val = mix(start, end, easedProgress);
1384
1385 if (!loop && this._progress >= 1) {
1386 this._activated = false;
1387 }
1388
1389 return this._val - prev;
1390 };
1391
1392 __proto.reset = function (defaultVal) {
1393 var range = this._range;
1394 var val = clamp(defaultVal, range.min, range.max);
1395 this._start = val;
1396 this._end = val;
1397 this._val = val;
1398 this._progress = 0;
1399 this._activated = false;
1400 };
1401
1402 __proto.setEndDelta = function (delta) {
1403 var range = this._range;
1404 this._start = this._val;
1405 this._end = clamp(this._end + delta, range.min, range.max);
1406 this._progress = 0;
1407 this._activated = true;
1408 };
1409
1410 return Motion;
1411 }();
1412
1413 /*
1414 * Copyright (c) 2020 NAVER Corp.
1415 * egjs projects are licensed under the MIT license
1416 */
1417 /**
1418 * Control that animates model without user input
1419 * @category Controls
1420 */
1421
1422 var AnimationControl =
1423 /*#__PURE__*/
1424 function () {
1425 /**
1426 * Create new instance of AnimationControl
1427 * @param from Start pose
1428 * @param to End pose
1429 * @param {object} options Options
1430 * @param {number} [options.duration=500] Animation duration
1431 * @param {function} [options.easing=(x: number) => 1 - Math.pow(1 - x, 3)] Animation easing function
1432 */
1433 function AnimationControl(from, to, _a) {
1434 var _b = _a === void 0 ? {} : _a,
1435 _c = _b.duration,
1436 duration = _c === void 0 ? ANIMATION_DURATION : _c,
1437 _d = _b.easing,
1438 easing = _d === void 0 ? EASING$1 : _d;
1439
1440 this._enabled = false;
1441 this._finishCallbacks = [];
1442 from = from.clone();
1443 to = to.clone();
1444 from.yaw = circulate(from.yaw, 0, 360);
1445 to.yaw = circulate(to.yaw, 0, 360); // Take the smaller degree
1446
1447 if (Math.abs(to.yaw - from.yaw) > 180) {
1448 to.yaw = to.yaw < from.yaw ? to.yaw + 360 : to.yaw - 360;
1449 }
1450
1451 this._motion = new Motion({
1452 duration: duration,
1453 range: ANIMATION_RANGE,
1454 easing: easing
1455 });
1456 this._from = from;
1457 this._to = to;
1458 }
1459
1460 var __proto = AnimationControl.prototype;
1461 Object.defineProperty(__proto, "element", {
1462 get: function () {
1463 return null;
1464 },
1465 enumerable: false,
1466 configurable: true
1467 });
1468 Object.defineProperty(__proto, "enabled", {
1469 /**
1470 * Whether this control is enabled or not
1471 * @readonly
1472 */
1473 get: function () {
1474 return this._enabled;
1475 },
1476 enumerable: false,
1477 configurable: true
1478 });
1479 Object.defineProperty(__proto, "duration", {
1480 /**
1481 * Duration of the animation
1482 */
1483 get: function () {
1484 return this._motion.duration;
1485 },
1486 set: function (val) {
1487 this._motion.duration = val;
1488 },
1489 enumerable: false,
1490 configurable: true
1491 });
1492 Object.defineProperty(__proto, "easing", {
1493 /**
1494 * Easing function of the animation
1495 */
1496 get: function () {
1497 return this._motion.easing;
1498 },
1499 set: function (val) {
1500 this._motion.easing = val;
1501 },
1502 enumerable: false,
1503 configurable: true
1504 });
1505 /**
1506 * Destroy the instance and remove all event listeners attached
1507 * This also will reset CSS cursor to intial
1508 * @returns {void} Nothing
1509 */
1510
1511 __proto.destroy = function () {
1512 this.disable();
1513 };
1514 /**
1515 * Update control by given deltaTime
1516 * @param camera Camera to update position
1517 * @param deltaTime Number of milisec to update
1518 * @returns {void} Nothing
1519 */
1520
1521
1522 __proto.update = function (camera, deltaTime) {
1523 if (!this._enabled) return;
1524 var from = this._from;
1525 var to = this._to;
1526 var motion = this._motion;
1527 motion.update(deltaTime); // Progress that easing is applied
1528
1529 var progress = motion.val;
1530 camera.yaw = mix(from.yaw, to.yaw, progress);
1531 camera.pitch = mix(from.pitch, to.pitch, progress);
1532 camera.distance = mix(from.distance, to.distance, progress);
1533 camera.pivot = from.pivot.clone().lerp(to.pivot, progress);
1534
1535 if (motion.progress >= 1) {
1536 this.disable();
1537
1538 this._finishCallbacks.forEach(function (callback) {
1539 return callback();
1540 });
1541 }
1542 };
1543 /**
1544 * Enable this input and add event listeners
1545 * @returns {void} Nothing
1546 */
1547
1548
1549 __proto.enable = function () {
1550 if (this._enabled) return;
1551 this._enabled = true;
1552
1553 this._motion.reset(0);
1554
1555 this._motion.setEndDelta(1);
1556 };
1557 /**
1558 * Disable this input and remove all event handlers
1559 * @returns {void} Nothing
1560 */
1561
1562
1563 __proto.disable = function () {
1564 if (!this._enabled) return;
1565 this._enabled = false;
1566 };
1567 /**
1568 * Add callback which is called when animation is finished
1569 * @param callback Callback that will be called when animation finishes
1570 * @returns {void} Nothing
1571 */
1572
1573
1574 __proto.onFinished = function (callback) {
1575 this._finishCallbacks.push(callback);
1576 };
1577 /**
1578 * Remove all onFinished callbacks
1579 * @returns {void} Nothing
1580 */
1581
1582
1583 __proto.clearFinished = function () {
1584 this._finishCallbacks = [];
1585 };
1586
1587 __proto.resize = function (size) {// DO NOTHING
1588 };
1589
1590 __proto.setElement = function (element) {// DO NOTHING
1591 };
1592
1593 __proto.sync = function (camera) {// Do nothing
1594 };
1595
1596 return AnimationControl;
1597 }();
1598
1599 /*
1600 * Copyright (c) 2020 NAVER Corp.
1601 * egjs projects are licensed under the MIT license
1602 */
1603 /**
1604 * Camera that renders the scene of View3D
1605 * @category Core
1606 */
1607
1608 var Camera =
1609 /*#__PURE__*/
1610 function () {
1611 /**
1612 * Create new Camera instance
1613 * @param canvas \<canvas\> element to render 3d model
1614 */
1615 function Camera(canvas) {
1616 this._minDistance = MINIMUM_DISTANCE;
1617 this._maxDistance = MAXIMUM_DISTANCE;
1618 this._defaultPose = CAMERA_POSE;
1619 this._currentPose = this._defaultPose.clone();
1620 this._threeCamera = new THREE.PerspectiveCamera();
1621 this._controller = new Controller(canvas, this);
1622 }
1623
1624 var __proto = Camera.prototype;
1625 Object.defineProperty(__proto, "threeCamera", {
1626 /**
1627 * Three.js {@link https://threejs.org/docs/#api/en/cameras/PerspectiveCamera PerspectiveCamera} instance
1628 * @readonly
1629 * @type THREE.PerspectiveCamera
1630 */
1631 get: function () {
1632 return this._threeCamera;
1633 },
1634 enumerable: false,
1635 configurable: true
1636 });
1637 Object.defineProperty(__proto, "controller", {
1638 /**
1639 * Controller of the camera
1640 * @readonly
1641 * @type Controller
1642 */
1643 get: function () {
1644 return this._controller;
1645 },
1646 enumerable: false,
1647 configurable: true
1648 });
1649 Object.defineProperty(__proto, "defaultPose", {
1650 /**
1651 * Camera's default pose(yaw, pitch, distance, pivot)
1652 * This will be new currentPose when {@link Camera#reset reset()} is called
1653 * @readonly
1654 * @type Pose
1655 */
1656 get: function () {
1657 return this._defaultPose;
1658 },
1659 enumerable: false,
1660 configurable: true
1661 });
1662 Object.defineProperty(__proto, "currentPose", {
1663 /**
1664 * Camera's current pose value
1665 * @readonly
1666 * @type Pose
1667 */
1668 get: function () {
1669 return this._currentPose.clone();
1670 },
1671 enumerable: false,
1672 configurable: true
1673 });
1674 Object.defineProperty(__proto, "yaw", {
1675 /**
1676 * Camera's current yaw
1677 * {@link Camera#updatePosition} should be called after changing this value, and normally it is called every frame.
1678 * @type number
1679 */
1680 get: function () {
1681 return this._currentPose.yaw;
1682 },
1683 set: function (val) {
1684 this._currentPose.yaw = val;
1685 },
1686 enumerable: false,
1687 configurable: true
1688 });
1689 Object.defineProperty(__proto, "pitch", {
1690 /**
1691 * Camera's current pitch
1692 * {@link Camera#updatePosition} should be called after changing this value, and normally it is called every frame.
1693 * @type number
1694 */
1695 get: function () {
1696 return this._currentPose.pitch;
1697 },
1698 set: function (val) {
1699 this._currentPose.pitch = val;
1700 },
1701 enumerable: false,
1702 configurable: true
1703 });
1704 Object.defineProperty(__proto, "distance", {
1705 /**
1706 * Camera's current distance
1707 * {@link Camera#updatePosition} should be called after changing this value, and normally it is called every frame.
1708 * @type number
1709 */
1710 get: function () {
1711 return this._currentPose.distance;
1712 },
1713 set: function (val) {
1714 this._currentPose.distance = val;
1715 },
1716 enumerable: false,
1717 configurable: true
1718 });
1719 Object.defineProperty(__proto, "pivot", {
1720 /**
1721 * Current pivot point of camera rotation
1722 * @readonly
1723 * @type THREE.Vector3
1724 * @see {@link https://threejs.org/docs/#api/en/math/Vector3 THREE#Vector3}
1725 */
1726 get: function () {
1727 return this._currentPose.pivot;
1728 },
1729 set: function (val) {
1730 this._currentPose.pivot = val;
1731 },
1732 enumerable: false,
1733 configurable: true
1734 });
1735 Object.defineProperty(__proto, "minDistance", {
1736 /**
1737 * Minimum distance from lookAtPosition
1738 * @type number
1739 * @example
1740 * import View3D from "@egjs/view3d";
1741 *
1742 * const view3d = new View3D("#view3d-canvas");
1743 * view3d.camera.minDistance = 100;
1744 */
1745 get: function () {
1746 return this._minDistance;
1747 },
1748 set: function (val) {
1749 this._minDistance = val;
1750 },
1751 enumerable: false,
1752 configurable: true
1753 });
1754 Object.defineProperty(__proto, "maxDistance", {
1755 /**
1756 * Maximum distance from lookAtPosition
1757 * @type number
1758 * @example
1759 * import View3D from "@egjs/view3d";
1760 *
1761 * const view3d = new View3D("#view3d-canvas");
1762 * view3d.camera.maxDistance = 400;
1763 */
1764 get: function () {
1765 return this._maxDistance;
1766 },
1767 set: function (val) {
1768 this._maxDistance = val;
1769 },
1770 enumerable: false,
1771 configurable: true
1772 });
1773 Object.defineProperty(__proto, "fov", {
1774 /**
1775 * Camera's focus of view value
1776 * @type number
1777 * @see {@link https://threejs.org/docs/#api/en/cameras/PerspectiveCamera.fov THREE#PerspectiveCamera}
1778 */
1779 get: function () {
1780 return this._threeCamera.fov;
1781 },
1782 set: function (val) {
1783 this._threeCamera.fov = val;
1784
1785 this._threeCamera.updateProjectionMatrix();
1786 },
1787 enumerable: false,
1788 configurable: true
1789 });
1790 Object.defineProperty(__proto, "renderWidth", {
1791 /**
1792 * Camera's frustum width on current distance value
1793 * @type number
1794 */
1795 get: function () {
1796 return this.renderHeight * this._threeCamera.aspect;
1797 },
1798 enumerable: false,
1799 configurable: true
1800 });
1801 Object.defineProperty(__proto, "renderHeight", {
1802 /**
1803 * Camera's frustum height on current distance value
1804 * @type number
1805 */
1806 get: function () {
1807 return 2 * this.distance * Math.tan(toRadian(this.fov / 2));
1808 },
1809 enumerable: false,
1810 configurable: true
1811 });
1812 Object.defineProperty(__proto, "pose", {
1813 set: function (val) {
1814 this._currentPose = val;
1815
1816 this._controller.syncToCamera();
1817 },
1818 enumerable: false,
1819 configurable: true
1820 });
1821 /**
1822 * Reset camera to default pose
1823 * @param duration Duration of the reset animation
1824 * @param easing Easing function for the reset animation
1825 * @returns Promise that resolves when the animation finishes
1826 */
1827
1828 __proto.reset = function (duration, easing) {
1829 if (duration === void 0) {
1830 duration = 0;
1831 }
1832
1833 if (easing === void 0) {
1834 easing = EASING$1;
1835 }
1836
1837 var controller = this._controller;
1838 var currentPose = this._currentPose;
1839 var defaultPose = this._defaultPose;
1840
1841 if (duration <= 0) {
1842 // Reset camera immediately
1843 this._currentPose = defaultPose.clone();
1844 controller.syncToCamera();
1845 return Promise.resolve();
1846 } else {
1847 // Add reset animation control to controller
1848 var resetControl_1 = new AnimationControl(currentPose, defaultPose);
1849 resetControl_1.duration = duration;
1850 resetControl_1.easing = easing;
1851 return new Promise(function (resolve) {
1852 resetControl_1.onFinished(function () {
1853 controller.remove(resetControl_1);
1854 controller.syncToCamera();
1855 resolve();
1856 });
1857 controller.add(resetControl_1);
1858 });
1859 }
1860 };
1861 /**
1862 * Update camera's aspect to given size
1863 * @param size {@link THREE.Vector2} instance that has width(x), height(y)
1864 * @returns {void} Nothing
1865 */
1866
1867
1868 __proto.resize = function (size) {
1869 var cam = this._threeCamera;
1870 var aspect = size.x / size.y;
1871 cam.aspect = aspect;
1872 cam.updateProjectionMatrix();
1873
1874 this._controller.resize(size);
1875 };
1876 /**
1877 * Set default position of camera relative to the 3d model
1878 * New default pose will be used when {@link Camera#reset reset()} is called
1879 * @param newDefaultPose new default pose to apply
1880 * @returns {void} Nothing
1881 */
1882
1883
1884 __proto.setDefaultPose = function (newDefaultPose) {
1885 var defaultPose = this._defaultPose;
1886 var yaw = newDefaultPose.yaw,
1887 pitch = newDefaultPose.pitch,
1888 distance = newDefaultPose.distance,
1889 pivot = newDefaultPose.pivot;
1890
1891 if (yaw != null) {
1892 defaultPose.yaw = yaw;
1893 }
1894
1895 if (pitch != null) {
1896 defaultPose.pitch = pitch;
1897 }
1898
1899 if (distance != null) {
1900 defaultPose.distance = distance;
1901 }
1902
1903 if (pivot != null) {
1904 defaultPose.pivot = pivot;
1905 }
1906 };
1907 /**
1908 * Update camera position base on the {@link Camera#currentPose currentPose} value
1909 * @returns {void} Nothing
1910 */
1911
1912
1913 __proto.updatePosition = function () {
1914 this._clampCurrentPose();
1915
1916 var threeCamera = this._threeCamera;
1917 var pose = this._currentPose;
1918 var yaw = toRadian(pose.yaw);
1919 var pitch = toRadian(pose.pitch); // Should use minimum distance to prevent distance becomes 0, which makes whole x,y,z to 0 regardless of pose
1920
1921 var distance = Math.max(pose.distance + this._minDistance, MINIMUM_DISTANCE);
1922 var newCamPos = new THREE.Vector3(0, 0, 0);
1923 newCamPos.y = distance * Math.sin(pitch);
1924 newCamPos.z = distance * Math.cos(pitch);
1925 newCamPos.x = newCamPos.z * Math.sin(-yaw);
1926 newCamPos.z = newCamPos.z * Math.cos(-yaw);
1927 newCamPos.add(pose.pivot);
1928 threeCamera.position.copy(newCamPos);
1929 threeCamera.lookAt(pose.pivot);
1930 threeCamera.updateProjectionMatrix();
1931 };
1932
1933 __proto._clampCurrentPose = function () {
1934 var currentPose = this._currentPose;
1935 currentPose.yaw = circulate(currentPose.yaw, 0, 360);
1936 currentPose.pitch = clamp(currentPose.pitch, PITCH_RANGE.min, PITCH_RANGE.max);
1937 currentPose.distance = clamp(currentPose.distance, this._minDistance, this._maxDistance);
1938 };
1939
1940 return Camera;
1941 }();
1942
1943 /*
1944 * Copyright (c) 2020 NAVER Corp.
1945 * egjs projects are licensed under the MIT license
1946 */
1947 /**
1948 * Component that manages animations of the 3D Model
1949 * @category Core
1950 */
1951
1952 var ModelAnimator =
1953 /*#__PURE__*/
1954 function () {
1955 /**
1956 * Create new ModelAnimator instance
1957 * @param scene {@link https://threejs.org/docs/index.html#api/en/scenes/Scene THREE.Scene} instance that is root of all 3d objects
1958 */
1959 function ModelAnimator(scene) {
1960 this._mixer = new THREE.AnimationMixer(scene);
1961 this._clips = [];
1962 this._actions = [];
1963 }
1964
1965 var __proto = ModelAnimator.prototype;
1966 Object.defineProperty(__proto, "clips", {
1967 /**
1968 * Three.js {@link https://threejs.org/docs/#api/en/animation/AnimationClip AnimationClip}s that stored
1969 * @type THREE.AnimationClip
1970 * @readonly
1971 */
1972 get: function () {
1973 return this._clips;
1974 },
1975 enumerable: false,
1976 configurable: true
1977 });
1978 Object.defineProperty(__proto, "mixer", {
1979 /**
1980 * {@link https://threejs.org/docs/index.html#api/en/animation/AnimationMixer THREE.AnimationMixer} instance
1981 * @type THREE.AnimationMixer
1982 * @readonly
1983 */
1984 get: function () {
1985 return this._mixer;
1986 },
1987 enumerable: false,
1988 configurable: true
1989 });
1990 /**
1991 * Store the given clips
1992 * @param clips Three.js {@link https://threejs.org/docs/#api/en/animation/AnimationClip AnimationClip}s of the model
1993 * @returns {void} Nothing
1994 * @example
1995 * // After loading model
1996 * view3d.animator.setClips(model.animations);
1997 */
1998
1999 __proto.setClips = function (clips) {
2000 var mixer = this._mixer;
2001 this._clips = clips;
2002 this._actions = clips.map(function (clip) {
2003 return mixer.clipAction(clip);
2004 });
2005 };
2006 /**
2007 * Play one of the model's animation
2008 * @param index Index of the animation to play
2009 * @returns {void} Nothing
2010 */
2011
2012
2013 __proto.play = function (index) {
2014 var action = this._actions[index];
2015
2016 if (action) {
2017 action.play();
2018 }
2019 };
2020 /**
2021 * Pause one of the model's animation
2022 * If you want to stop animation completely, you should call {@link ModelAnimator#stop stop} instead
2023 * You should call {@link ModelAnimator#resume resume} to resume animation
2024 * @param index Index of the animation to pause
2025 * @returns {void} Nothing
2026 */
2027
2028
2029 __proto.pause = function (index) {
2030 var action = this._actions[index];
2031
2032 if (action) {
2033 action.timeScale = 0;
2034 }
2035 };
2036 /**
2037 * Resume one of the model's animation
2038 * This will play animation from the point when the animation is paused
2039 * @param index Index of the animation to resume
2040 * @returns {void} Nothing
2041 */
2042
2043
2044 __proto.resume = function (index) {
2045 var action = this._actions[index];
2046
2047 if (action) {
2048 action.timeScale = 1;
2049 }
2050 };
2051 /**
2052 * Fully stops one of the model's animation
2053 * @param index Index of the animation to stop
2054 * @returns {void} Nothing
2055 */
2056
2057
2058 __proto.stop = function (index) {
2059 var action = this._actions[index];
2060
2061 if (action) {
2062 action.stop();
2063 }
2064 };
2065 /**
2066 * Update animations
2067 * @param delta number of seconds to play animations attached
2068 * @returns {void} Nothing
2069 */
2070
2071
2072 __proto.update = function (delta) {
2073 this._mixer.update(delta);
2074 };
2075 /**
2076 * Reset the instance and remove all cached animation clips attached to it
2077 * @returns {void} Nothing
2078 */
2079
2080
2081 __proto.reset = function () {
2082 var mixer = this._mixer;
2083 mixer.uncacheRoot(mixer.getRoot());
2084 this._clips = [];
2085 this._actions = [];
2086 };
2087
2088 return ModelAnimator;
2089 }();
2090
2091 /*
2092 * Copyright (c) 2020 NAVER Corp.
2093 * egjs projects are licensed under the MIT license
2094 */
2095 /**
2096 * XRManager that manages XRSessions
2097 * @category Core
2098 */
2099
2100 var XRManager =
2101 /*#__PURE__*/
2102 function () {
2103 /**
2104 * Create a new instance of the XRManager
2105 * @param view3d Instance of the View3D
2106 */
2107 function XRManager(view3d) {
2108 this._view3d = view3d;
2109 this._sessions = [];
2110 this._currentSession = null;
2111 }
2112
2113 var __proto = XRManager.prototype;
2114 Object.defineProperty(__proto, "sessions", {
2115 /**
2116 * Array of {@link XRSession}s added
2117 */
2118 get: function () {
2119 return this._sessions;
2120 },
2121 enumerable: false,
2122 configurable: true
2123 });
2124 Object.defineProperty(__proto, "currentSession", {
2125 /**
2126 * Current entry session. Note that only WebXR type session can be returned.
2127 */
2128 get: function () {
2129 return this._currentSession;
2130 },
2131 enumerable: false,
2132 configurable: true
2133 });
2134 /**
2135 * Return a Promise containing whether any of the added session is available
2136 */
2137
2138 __proto.isAvailable = function () {
2139 return __awaiter(this, void 0, void 0, function () {
2140 var results;
2141 return __generator(this, function (_a) {
2142 switch (_a.label) {
2143 case 0:
2144 return [4
2145 /*yield*/
2146 , Promise.all(this._sessions.map(function (session) {
2147 return session.isAvailable();
2148 }))];
2149
2150 case 1:
2151 results = _a.sent();
2152 return [2
2153 /*return*/
2154 , results.some(function (result) {
2155 return result === true;
2156 })];
2157 }
2158 });
2159 });
2160 };
2161 /**
2162 * Add new {@link XRSession}.
2163 * The XRSession's order added is the same as the order of entry.
2164 * @param xrSession XRSession to add
2165 */
2166
2167
2168 __proto.addSession = function () {
2169 var _a;
2170
2171 var xrSession = [];
2172
2173 for (var _i = 0; _i < arguments.length; _i++) {
2174 xrSession[_i] = arguments[_i];
2175 }
2176
2177 (_a = this._sessions).push.apply(_a, __spread(xrSession));
2178 };
2179 /**
2180 * Enter XR Session.
2181 */
2182
2183
2184 __proto.enter = function () {
2185 return __awaiter(this, void 0, void 0, function () {
2186 return __generator(this, function (_a) {
2187 return [2
2188 /*return*/
2189 , this._enterSession(0, [])];
2190 });
2191 });
2192 };
2193 /**
2194 * Exit current XR Session.
2195 */
2196
2197
2198 __proto.exit = function () {
2199 if (this._currentSession) {
2200 this._currentSession.exit(this._view3d);
2201
2202 this._currentSession = null;
2203 }
2204 };
2205
2206 __proto._enterSession = function (sessionIdx, errors) {
2207 return __awaiter(this, void 0, void 0, function () {
2208 var view3d, sessions, xrSession, isSessionAvailable;
2209
2210 var _this = this;
2211
2212 return __generator(this, function (_a) {
2213 switch (_a.label) {
2214 case 0:
2215 view3d = this._view3d;
2216 sessions = this._sessions;
2217
2218 if (sessionIdx >= sessions.length) {
2219 if (errors.length < 1) {
2220 errors.push(new Error("No sessions available"));
2221 }
2222
2223 return [2
2224 /*return*/
2225 , Promise.reject(errors)];
2226 }
2227
2228 xrSession = sessions[sessionIdx];
2229 return [4
2230 /*yield*/
2231 , xrSession.isAvailable()];
2232
2233 case 1:
2234 isSessionAvailable = _a.sent();
2235
2236 if (!isSessionAvailable) {
2237 return [2
2238 /*return*/
2239 , this._enterSession(sessionIdx + 1, errors)];
2240 }
2241
2242 return [4
2243 /*yield*/
2244 , xrSession.enter(view3d).then(function () {
2245 if (xrSession.isWebXRSession) {
2246 // Non-webxr sessions are ignored
2247 _this._currentSession = xrSession;
2248 xrSession.session.addEventListener("end", function () {
2249 _this._currentSession = null;
2250 });
2251 }
2252
2253 return errors;
2254 }).catch(function (e) {
2255 errors.push(e);
2256 return _this._enterSession(sessionIdx + 1, errors);
2257 })];
2258
2259 case 2:
2260 return [2
2261 /*return*/
2262 , _a.sent()];
2263 }
2264 });
2265 });
2266 };
2267
2268 return XRManager;
2269 }();
2270
2271 /*
2272 * Copyright (c) 2020 NAVER Corp.
2273 * egjs projects are licensed under the MIT license
2274 */
2275 var EVENTS = {
2276 MOUSE_DOWN: "mousedown",
2277 MOUSE_MOVE: "mousemove",
2278 MOUSE_UP: "mouseup",
2279 TOUCH_START: "touchstart",
2280 TOUCH_MOVE: "touchmove",
2281 TOUCH_END: "touchend",
2282 WHEEL: "wheel",
2283 RESIZE: "resize",
2284 CONTEXT_MENU: "contextmenu",
2285 MOUSE_ENTER: "mouseenter",
2286 MOUSE_LEAVE: "mouseleave"
2287 }; // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent.button
2288
2289 var MOUSE_BUTTON;
2290
2291 (function (MOUSE_BUTTON) {
2292 MOUSE_BUTTON[MOUSE_BUTTON["LEFT"] = 0] = "LEFT";
2293 MOUSE_BUTTON[MOUSE_BUTTON["MIDDLE"] = 1] = "MIDDLE";
2294 MOUSE_BUTTON[MOUSE_BUTTON["RIGHT"] = 2] = "RIGHT";
2295 })(MOUSE_BUTTON || (MOUSE_BUTTON = {}));
2296
2297 /*
2298 * Copyright (c) 2020 NAVER Corp.
2299 * egjs projects are licensed under the MIT license
2300 */
2301 /**
2302 * Yet another 3d model viewer
2303 * @category Core
2304 * @mermaid
2305 * classDiagram
2306 * class View3D
2307 * View3D *-- Camera
2308 * View3D *-- Renderer
2309 * View3D *-- Scene
2310 * View3D *-- ModelAnimator
2311 * Camera *-- Controller
2312 * @event resize
2313 * @event beforeRender
2314 * @event afterRender
2315 */
2316
2317 var View3D =
2318 /*#__PURE__*/
2319 function (_super) {
2320 __extends(View3D, _super);
2321 /**
2322 * Creates new View3D instance
2323 * @example
2324 * import View3D, { ERROR_CODES } from "@egjs/view3d";
2325 *
2326 * try {
2327 * const view3d = new View3D("#wrapper")
2328 * } catch (e) {
2329 * if (e.code === ERROR_CODES.ELEMENT_NOT_FOUND) {
2330 * console.error("Element not found")
2331 * }
2332 * }
2333 * @throws {View3DError} `CODES.WRONG_TYPE`<br/>When the parameter is not either string or the canvas element.
2334 * @throws {View3DError} `CODES.ELEMENT_NOT_FOUND`<br/>When the element with given query does not exist.
2335 * @throws {View3DError} `CODES.ELEMENT_NOT_CANVAS`<br/>When the element given is not a \<canvas\> element.
2336 * @throws {View3DError} `CODES.WEBGL_NOT_SUPPORTED`<br/>When browser does not support WebGL.
2337 * @see Model
2338 * @see Camera
2339 * @see Renderer
2340 * @see Scene
2341 * @see Controller
2342 * @see XRManager
2343 */
2344
2345
2346 function View3D(el) {
2347 var _this = _super.call(this) || this;
2348 /**
2349 * Resize View3D instance to fit current canvas size
2350 * @method
2351 * @returns {void} Nothing
2352 */
2353
2354
2355 _this.resize = function () {
2356 _this._renderer.resize();
2357
2358 var newSize = _this._renderer.size;
2359
2360 _this._camera.resize(newSize);
2361
2362 _this.emit("resize", __assign(__assign({}, newSize), {
2363 target: _this
2364 }));
2365 };
2366 /**
2367 * View3D's basic render loop function
2368 * @param delta Number of seconds passed since last frame
2369 */
2370
2371
2372 _this.renderLoop = function (delta) {
2373 var renderer = _this._renderer;
2374 var scene = _this._scene;
2375 var camera = _this._camera;
2376 var controller = _this.controller;
2377 var animator = _this._animator;
2378 animator.update(delta);
2379 controller.update(delta);
2380
2381 _this.emit("beforeRender", _this);
2382
2383 renderer.render(scene, camera);
2384
2385 _this.emit("afterRender", _this);
2386 };
2387
2388 var canvas = getCanvas(el);
2389 _this._renderer = new Renderer(canvas);
2390 _this._camera = new Camera(canvas);
2391 _this._scene = new Scene();
2392 _this._animator = new ModelAnimator(_this._scene.root);
2393 _this._xr = new XRManager(_this);
2394 _this._model = null;
2395
2396 _this.resize();
2397
2398 window.addEventListener(EVENTS.RESIZE, _this.resize);
2399 return _this;
2400 }
2401
2402 var __proto = View3D.prototype;
2403 Object.defineProperty(__proto, "renderer", {
2404 /**
2405 * {@link Renderer} instance of the View3D
2406 * @type {Renderer}
2407 */
2408 get: function () {
2409 return this._renderer;
2410 },
2411 enumerable: false,
2412 configurable: true
2413 });
2414 Object.defineProperty(__proto, "scene", {
2415 /**
2416 * {@link Scene} instance of the View3D
2417 * @type {Scene}
2418 */
2419 get: function () {
2420 return this._scene;
2421 },
2422 enumerable: false,
2423 configurable: true
2424 });
2425 Object.defineProperty(__proto, "camera", {
2426 /**
2427 * {@link Camera} instance of the View3D
2428 * @type {Camera}
2429 */
2430 get: function () {
2431 return this._camera;
2432 },
2433 enumerable: false,
2434 configurable: true
2435 });
2436 Object.defineProperty(__proto, "controller", {
2437 /**
2438 * {@link Controller} instance of the Camera
2439 * @type {Controller}
2440 */
2441 get: function () {
2442 return this._camera.controller;
2443 },
2444 enumerable: false,
2445 configurable: true
2446 });
2447 Object.defineProperty(__proto, "animator", {
2448 /**
2449 * {@link ModelAnimator} instance of the View3D
2450 * @type {ModelAnimator}
2451 */
2452 get: function () {
2453 return this._animator;
2454 },
2455 enumerable: false,
2456 configurable: true
2457 });
2458 Object.defineProperty(__proto, "xr", {
2459 /**
2460 * {@link XRManager} instance of the View3D
2461 * @type {XRManager}
2462 */
2463 get: function () {
2464 return this._xr;
2465 },
2466 enumerable: false,
2467 configurable: true
2468 });
2469 Object.defineProperty(__proto, "model", {
2470 /**
2471 * {@link Model} that View3D is currently showing
2472 * @type {Model|null}
2473 */
2474 get: function () {
2475 return this._model;
2476 },
2477 enumerable: false,
2478 configurable: true
2479 });
2480 /**
2481 * Destroy View3D instance and remove all events attached to it
2482 * @returns {void} Nothing
2483 */
2484
2485 __proto.destroy = function () {
2486 this._scene.reset();
2487
2488 this.controller.clear();
2489 this._model = null;
2490 window.removeEventListener(EVENTS.RESIZE, this.resize);
2491 };
2492 /**
2493 * Display the given model.
2494 * This method will remove the current displaying model, and reset the camera & control to default position.
2495 * View3D can only show one model at a time
2496 * @param model {@link Model} instance to show
2497 * @param {object} [options={}] Display options
2498 * @param {number} [options.applySize=true] Whether to change model size to given "size" option.
2499 * @param {number} [options.size=80] Size of the model to show as.
2500 * @param {boolean} [options.resetView=true] Whether to reset the view to the camera's default pose.
2501 * @returns {void} Nothing
2502 */
2503
2504
2505 __proto.display = function (model, _a) {
2506 var _b = _a === void 0 ? {} : _a,
2507 _c = _b.applySize,
2508 applySize = _c === void 0 ? true : _c,
2509 _d = _b.size,
2510 size = _d === void 0 ? MODEL_SIZE : _d,
2511 _e = _b.resetView,
2512 resetView = _e === void 0 ? true : _e;
2513
2514 var renderer = this._renderer;
2515 var scene = this._scene;
2516 var camera = this._camera;
2517 var animator = this._animator;
2518
2519 if (applySize) {
2520 model.size = size;
2521 } // model.moveToOrigin();
2522
2523
2524 scene.resetModel();
2525
2526 if (resetView) {
2527 camera.reset();
2528 }
2529
2530 animator.reset();
2531 this._model = model;
2532 scene.add(model.scene);
2533 animator.setClips(model.animations);
2534 scene.update(model);
2535 renderer.stopAnimationLoop();
2536 renderer.setAnimationLoop(this.renderLoop);
2537 };
2538 /**
2539 * Current version of the View3D
2540 */
2541
2542
2543 View3D.VERSION = "1.1.0";
2544 return View3D;
2545 }(EventEmitter);
2546
2547 /*
2548 * Copyright (c) 2020 NAVER Corp.
2549 * egjs projects are licensed under the MIT license
2550 */
2551 /**
2552 * Data class for loaded 3d model
2553 * @category Core
2554 */
2555
2556 var Model =
2557 /*#__PURE__*/
2558 function () {
2559 /**
2560 * Create new Model instance
2561 */
2562 function Model(_a) {
2563 var scenes = _a.scenes,
2564 _b = _a.animations,
2565 animations = _b === void 0 ? [] : _b,
2566 _c = _a.fixSkinnedBbox,
2567 fixSkinnedBbox = _c === void 0 ? false : _c,
2568 _d = _a.castShadow,
2569 castShadow = _d === void 0 ? true : _d,
2570 _e = _a.receiveShadow,
2571 receiveShadow = _e === void 0 ? false : _e; // This guarantees model's root has identity matrix at creation
2572
2573 this._scene = new THREE.Group();
2574 var pivot = new THREE.Object3D();
2575 pivot.name = "Pivot";
2576 pivot.add.apply(pivot, __spread(scenes));
2577
2578 this._scene.add(pivot);
2579
2580 this._animations = animations;
2581 this._fixSkinnedBbox = fixSkinnedBbox;
2582 this._cachedLights = null;
2583 this._cachedMeshes = null;
2584
2585 this._setInitialBbox();
2586
2587 var bboxCenter = this._initialBbox.getCenter(new THREE.Vector3());
2588
2589 pivot.position.copy(bboxCenter.negate());
2590
2591 this._moveInitialBboxToCenter();
2592
2593 this._originalSize = this.size;
2594 this.castShadow = castShadow;
2595 this.receiveShadow = receiveShadow;
2596 }
2597
2598 var __proto = Model.prototype;
2599 Object.defineProperty(__proto, "scene", {
2600 /**
2601 * Scene of the model, see {@link https://threejs.org/docs/#api/en/objects/Group THREE.Group}
2602 * @readonly
2603 */
2604 get: function () {
2605 return this._scene;
2606 },
2607 enumerable: false,
2608 configurable: true
2609 });
2610 Object.defineProperty(__proto, "animations", {
2611 /**
2612 * {@link https://threejs.org/docs/#api/en/animation/AnimationClip THREE.AnimationClip}s inside model
2613 */
2614 get: function () {
2615 return this._animations;
2616 },
2617 enumerable: false,
2618 configurable: true
2619 });
2620 Object.defineProperty(__proto, "lights", {
2621 /***
2622 * {@link https://threejs.org/docs/#api/en/lights/Light THREE.Light}s inside model if there's any.
2623 * @readonly
2624 */
2625 get: function () {
2626 return this._cachedLights ? this._cachedLights : this._getAllLights();
2627 },
2628 enumerable: false,
2629 configurable: true
2630 });
2631 Object.defineProperty(__proto, "meshes", {
2632 /**
2633 * {@link https://threejs.org/docs/#api/en/objects/Mesh THREE.Mesh}es inside model if there's any.
2634 * @readonly
2635 */
2636 get: function () {
2637 return this._cachedMeshes ? this._cachedMeshes : this._getAllMeshes();
2638 },
2639 enumerable: false,
2640 configurable: true
2641 });
2642 Object.defineProperty(__proto, "bbox", {
2643 /**
2644 * Get a copy of model's current bounding box
2645 * @type THREE#Box3
2646 * @see https://threejs.org/docs/#api/en/math/Box3
2647 */
2648 get: function () {
2649 return this._getTransformedBbox();
2650 },
2651 enumerable: false,
2652 configurable: true
2653 });
2654 Object.defineProperty(__proto, "initialBbox", {
2655 /**
2656 * Get a copy of model's initial bounding box without transform
2657 */
2658 get: function () {
2659 return this._initialBbox.clone();
2660 },
2661 enumerable: false,
2662 configurable: true
2663 });
2664 Object.defineProperty(__proto, "size", {
2665 /**
2666 * Model's bounding box size
2667 * Changing this will scale the model.
2668 * @type number
2669 * @example
2670 * import { GLTFLoader } from "@egjs/view3d";
2671 * new GLTFLoader().load(URL_TO_GLTF)
2672 * .then(model => {
2673 * model.size = 100;
2674 * })
2675 */
2676 get: function () {
2677 return this._getTransformedBbox().getSize(new THREE.Vector3()).length();
2678 },
2679 set: function (val) {
2680 var scene = this._scene;
2681 var initialBbox = this._initialBbox; // Modify scale
2682
2683 var bboxSize = initialBbox.getSize(new THREE.Vector3());
2684 var scale = val / bboxSize.length();
2685 scene.scale.setScalar(scale);
2686 scene.updateMatrix();
2687 },
2688 enumerable: false,
2689 configurable: true
2690 });
2691 Object.defineProperty(__proto, "fixSkinnedBbox", {
2692 /**
2693 * Whether to apply inference from skeleton when calculating bounding box
2694 * This can fix some models with skinned mesh when it has wrong bounding box
2695 * @type boolean
2696 */
2697 get: function () {
2698 return this._fixSkinnedBbox;
2699 },
2700 set: function (val) {
2701 this._fixSkinnedBbox = val;
2702 },
2703 enumerable: false,
2704 configurable: true
2705 });
2706 Object.defineProperty(__proto, "originalSize", {
2707 /**
2708 * Return the model's original bbox size before applying any transform
2709 * @type number
2710 */
2711 get: function () {
2712 return this._originalSize;
2713 },
2714 enumerable: false,
2715 configurable: true
2716 });
2717 Object.defineProperty(__proto, "castShadow", {
2718 /**
2719 * Whether the model's meshes gets rendered into shadow map
2720 * @type boolean
2721 * @example
2722 * model.castShadow = true;
2723 */
2724 set: function (val) {
2725 var meshes = this.meshes;
2726 meshes.forEach(function (mesh) {
2727 return mesh.castShadow = val;
2728 });
2729 },
2730 enumerable: false,
2731 configurable: true
2732 });
2733 Object.defineProperty(__proto, "receiveShadow", {
2734 /**
2735 * Whether the model's mesh materials receive shadows
2736 * @type boolean
2737 * @example
2738 * model.receiveShadow = true;
2739 */
2740 set: function (val) {
2741 var meshes = this.meshes;
2742 meshes.forEach(function (mesh) {
2743 return mesh.receiveShadow = val;
2744 });
2745 },
2746 enumerable: false,
2747 configurable: true
2748 });
2749 /**
2750 * Translate the model to center the model's bounding box to world origin (0, 0, 0).
2751 */
2752
2753 __proto.moveToOrigin = function () {
2754 // Translate scene position to origin
2755 var scene = this._scene;
2756
2757 var initialBbox = this._initialBbox.clone();
2758
2759 initialBbox.min.multiply(scene.scale);
2760 initialBbox.max.multiply(scene.scale);
2761 var bboxCenter = initialBbox.getCenter(new THREE.Vector3());
2762 scene.position.copy(bboxCenter.negate());
2763 scene.updateMatrix();
2764 };
2765
2766 __proto._setInitialBbox = function () {
2767 this._scene.updateMatrixWorld();
2768
2769 if (this._fixSkinnedBbox && this._hasSkinnedMesh()) {
2770 this._initialBbox = this._getSkeletonBbox();
2771 } else {
2772 this._initialBbox = new THREE.Box3().setFromObject(this._scene);
2773 }
2774 };
2775
2776 __proto._getSkeletonBbox = function () {
2777 var bbox = new THREE.Box3();
2778 this.meshes.forEach(function (mesh) {
2779 if (!mesh.isSkinnedMesh) {
2780 bbox.expandByObject(mesh);
2781 return;
2782 }
2783
2784 var geometry = mesh.geometry;
2785 var positions = geometry.attributes.position;
2786 var skinIndicies = geometry.attributes.skinIndex;
2787 var skinWeights = geometry.attributes.skinWeight;
2788 var skeleton = mesh.skeleton;
2789 skeleton.update();
2790 var boneMatricies = skeleton.boneMatrices;
2791 var finalMatrix = new THREE.Matrix4();
2792
2793 var _loop_1 = function (posIdx) {
2794 finalMatrix.identity();
2795 var skinned = new THREE.Vector4();
2796 skinned.set(0, 0, 0, 0);
2797 var skinVertex = new THREE.Vector4();
2798 skinVertex.set(positions.getX(posIdx), positions.getY(posIdx), positions.getZ(posIdx), 1).applyMatrix4(mesh.bindMatrix);
2799 var weights = [skinWeights.getX(posIdx), skinWeights.getY(posIdx), skinWeights.getZ(posIdx), skinWeights.getW(posIdx)];
2800 var indicies = [skinIndicies.getX(posIdx), skinIndicies.getY(posIdx), skinIndicies.getZ(posIdx), skinIndicies.getW(posIdx)];
2801 weights.forEach(function (weight, index) {
2802 var boneMatrix = new THREE.Matrix4().fromArray(boneMatricies, indicies[index] * 16);
2803 skinned.add(skinVertex.clone().applyMatrix4(boneMatrix).multiplyScalar(weight));
2804 });
2805 var transformed = new THREE.Vector3().fromArray(skinned.applyMatrix4(mesh.bindMatrixInverse).toArray());
2806 transformed.applyMatrix4(mesh.matrixWorld);
2807 bbox.expandByPoint(transformed);
2808 };
2809
2810 for (var posIdx = 0; posIdx < positions.count; posIdx++) {
2811 _loop_1(posIdx);
2812 }
2813 });
2814 return bbox;
2815 };
2816
2817 __proto._moveInitialBboxToCenter = function () {
2818 var bboxCenter = this._initialBbox.getCenter(new THREE.Vector3());
2819
2820 this._initialBbox.translate(bboxCenter.negate());
2821 };
2822
2823 __proto._getAllLights = function () {
2824 var lights = [];
2825
2826 this._scene.traverse(function (obj) {
2827 if (obj.isLight) {
2828 lights.push(obj);
2829 }
2830 });
2831
2832 this._cachedLights = lights;
2833 return lights;
2834 };
2835 /**
2836 * Get all {@link https://threejs.org/docs/#api/en/objects/Mesh THREE.Mesh}es inside model if there's any.
2837 * @private
2838 * @returns Meshes found at model's scene
2839 */
2840
2841
2842 __proto._getAllMeshes = function () {
2843 var meshes = [];
2844
2845 this._scene.traverse(function (obj) {
2846 if (obj.isMesh) {
2847 meshes.push(obj);
2848 }
2849 });
2850
2851 this._cachedMeshes = meshes;
2852 return meshes;
2853 };
2854
2855 __proto._hasSkinnedMesh = function () {
2856 return this.meshes.some(function (mesh) {
2857 return mesh.isSkinnedMesh;
2858 });
2859 };
2860
2861 __proto._getTransformedBbox = function () {
2862 return this._initialBbox.clone().applyMatrix4(this._scene.matrix);
2863 };
2864
2865 return Model;
2866 }();
2867
2868 /*
2869 * Copyright (c) 2020 NAVER Corp.
2870 * egjs projects are licensed under the MIT license
2871 */
2872
2873 var Core = {
2874 __proto__: null,
2875 ModelAnimator: ModelAnimator,
2876 Model: Model,
2877 Renderer: Renderer,
2878 Scene: Scene,
2879 XRManager: XRManager,
2880 Camera: Camera,
2881 Controller: Controller,
2882 Pose: Pose
2883 };
2884
2885 /*
2886 * Copyright (c) 2020 NAVER Corp.
2887 * egjs projects are licensed under the MIT license
2888 */
2889 /**
2890 * Control that animates model without user input
2891 * @category Controls
2892 */
2893
2894 var AutoControl =
2895 /*#__PURE__*/
2896 function () {
2897 /**
2898 * Create new RotateControl instance
2899 * @param {object} options Options
2900 * @param {HTMLElement | string | null} [options.element=null] Attaching element / selector of the element
2901 * @param {number} [options.delay=2000] Reactivation delay after mouse input in milisecond
2902 * @param {number} [options.delayOnMouseLeave=0] Reactivation delay after mouse leave
2903 * @param {number} [options.speed=1] Y-axis(yaw) rotation speed
2904 * @param {boolean} [options.pauseOnHover=false] Whether to pause rotation on mouse hover
2905 * @param {boolean} [options.canInterrupt=true] Whether user can interrupt the rotation with click/wheel input
2906 * @param {boolean} [options.disableOnInterrupt=false] Whether to disable control on user interrupt
2907 * @tutorial Adding Controls
2908 */
2909 function AutoControl(_a) {
2910 var _this = this;
2911
2912 var _b = _a === void 0 ? {} : _a,
2913 _c = _b.element,
2914 element = _c === void 0 ? NULL_ELEMENT : _c,
2915 _d = _b.delay,
2916 delay = _d === void 0 ? 2000 : _d,
2917 _e = _b.delayOnMouseLeave,
2918 delayOnMouseLeave = _e === void 0 ? 0 : _e,
2919 _f = _b.speed,
2920 speed = _f === void 0 ? 1 : _f,
2921 _g = _b.pauseOnHover,
2922 pauseOnHover = _g === void 0 ? false : _g,
2923 _h = _b.canInterrupt,
2924 canInterrupt = _h === void 0 ? true : _h,
2925 _j = _b.disableOnInterrupt,
2926 disableOnInterrupt = _j === void 0 ? false : _j; // Internal values
2927
2928
2929 this._targetEl = null;
2930 this._enabled = false;
2931 this._interrupted = false;
2932 this._interruptionTimer = -1;
2933 this._hovering = false;
2934
2935 this._onMouseDown = function (evt) {
2936 if (!_this._canInterrupt) return;
2937 if (evt.button !== MOUSE_BUTTON.LEFT && evt.button !== MOUSE_BUTTON.RIGHT) return;
2938 _this._interrupted = true;
2939
2940 _this._clearTimeout();
2941
2942 window.addEventListener(EVENTS.MOUSE_UP, _this._onMouseUp, false);
2943 };
2944
2945 this._onMouseUp = function () {
2946 window.removeEventListener(EVENTS.MOUSE_UP, _this._onMouseUp, false);
2947
2948 _this._setUninterruptedAfterDelay(_this._delay);
2949 };
2950
2951 this._onTouchStart = function () {
2952 if (!_this._canInterrupt) return;
2953 _this._interrupted = true;
2954
2955 _this._clearTimeout();
2956 };
2957
2958 this._onTouchEnd = function () {
2959 _this._setUninterruptedAfterDelay(_this._delay);
2960 };
2961
2962 this._onMouseEnter = function () {
2963 if (!_this._pauseOnHover) return;
2964 _this._interrupted = true;
2965 _this._hovering = true;
2966 };
2967
2968 this._onMouseLeave = function () {
2969 if (!_this._pauseOnHover) return;
2970 _this._hovering = false;
2971
2972 _this._setUninterruptedAfterDelay(_this._delayOnMouseLeave);
2973 };
2974
2975 this._onWheel = function () {
2976 if (!_this._canInterrupt) return;
2977 _this._interrupted = true;
2978
2979 _this._setUninterruptedAfterDelay(_this._delay);
2980 };
2981
2982 var targetEl = getElement(element);
2983
2984 if (targetEl) {
2985 this.setElement(targetEl);
2986 }
2987
2988 this._delay = delay;
2989 this._delayOnMouseLeave = delayOnMouseLeave;
2990 this._speed = speed;
2991 this._pauseOnHover = pauseOnHover;
2992 this._canInterrupt = canInterrupt;
2993 this._disableOnInterrupt = disableOnInterrupt;
2994 }
2995
2996 var __proto = AutoControl.prototype;
2997 Object.defineProperty(__proto, "element", {
2998 /**
2999 * Control's current target element to attach event listeners
3000 * @readonly
3001 */
3002 get: function () {
3003 return this._targetEl;
3004 },
3005 enumerable: false,
3006 configurable: true
3007 });
3008 Object.defineProperty(__proto, "enabled", {
3009 /**
3010 * Whether this control is enabled or not
3011 * @readonly
3012 */
3013 get: function () {
3014 return this._enabled;
3015 },
3016 enumerable: false,
3017 configurable: true
3018 });
3019 Object.defineProperty(__proto, "delay", {
3020 /**
3021 * Reactivation delay after mouse input in milisecond
3022 */
3023 get: function () {
3024 return this._delay;
3025 },
3026 set: function (val) {
3027 this._delay = val;
3028 },
3029 enumerable: false,
3030 configurable: true
3031 });
3032 Object.defineProperty(__proto, "delayOnMouseLeave", {
3033 /**
3034 * Reactivation delay after mouse leave
3035 * This option only works when {@link AutoControl#pauseOnHover pauseOnHover} is activated
3036 */
3037 get: function () {
3038 return this._delayOnMouseLeave;
3039 },
3040 set: function (val) {
3041 this._delayOnMouseLeave = val;
3042 },
3043 enumerable: false,
3044 configurable: true
3045 });
3046 Object.defineProperty(__proto, "speed", {
3047 /**
3048 * Y-axis(yaw) rotation speed
3049 * @default 1
3050 */
3051 get: function () {
3052 return this._speed;
3053 },
3054 set: function (val) {
3055 this._speed = val;
3056 },
3057 enumerable: false,
3058 configurable: true
3059 });
3060 Object.defineProperty(__proto, "pauseOnHover", {
3061 /**
3062 * Whether to pause rotation on mouse hover
3063 * @default false
3064 */
3065 get: function () {
3066 return this._pauseOnHover;
3067 },
3068 set: function (val) {
3069 this._pauseOnHover = val;
3070 },
3071 enumerable: false,
3072 configurable: true
3073 });
3074 Object.defineProperty(__proto, "canInterrupt", {
3075 /**
3076 * Whether user can interrupt the rotation with click/wheel input
3077 * @default true
3078 */
3079 get: function () {
3080 return this._canInterrupt;
3081 },
3082 set: function (val) {
3083 this._canInterrupt = val;
3084 },
3085 enumerable: false,
3086 configurable: true
3087 });
3088 Object.defineProperty(__proto, "disableOnInterrupt", {
3089 /**
3090 * Whether to disable control on user interrupt
3091 * @default false
3092 */
3093 get: function () {
3094 return this._disableOnInterrupt;
3095 },
3096 set: function (val) {
3097 this._disableOnInterrupt = val;
3098 },
3099 enumerable: false,
3100 configurable: true
3101 });
3102 /**
3103 * Destroy the instance and remove all event listeners attached
3104 * This also will reset CSS cursor to intial
3105 * @returns {void} Nothing
3106 */
3107
3108 __proto.destroy = function () {
3109 this.disable();
3110 };
3111 /**
3112 * Update control by given deltaTime
3113 * @param camera Camera to update position
3114 * @param deltaTime Number of milisec to update
3115 * @returns {void} Nothing
3116 */
3117
3118
3119 __proto.update = function (camera, deltaTime) {
3120 if (!this._enabled) return;
3121
3122 if (this._interrupted) {
3123 if (this._disableOnInterrupt) {
3124 this.disable();
3125 }
3126
3127 return;
3128 }
3129
3130 camera.yaw += this._speed * deltaTime / 100;
3131 }; // This is not documetned on purpose as it doesn't do nothing
3132
3133
3134 __proto.resize = function (size) {// DO NOTHING
3135 };
3136 /**
3137 * Enable this input and add event listeners
3138 * @returns {void} Nothing
3139 */
3140
3141
3142 __proto.enable = function () {
3143 if (this._enabled) return;
3144
3145 if (!this._targetEl) {
3146 throw new View3DError(MESSAGES.ADD_CONTROL_FIRST, CODES.ADD_CONTROL_FIRST);
3147 }
3148
3149 var targetEl = this._targetEl;
3150 targetEl.addEventListener(EVENTS.MOUSE_DOWN, this._onMouseDown, false);
3151 targetEl.addEventListener(EVENTS.TOUCH_START, this._onTouchStart, false);
3152 targetEl.addEventListener(EVENTS.TOUCH_END, this._onTouchEnd, false);
3153 targetEl.addEventListener(EVENTS.MOUSE_ENTER, this._onMouseEnter, false);
3154 targetEl.addEventListener(EVENTS.MOUSE_LEAVE, this._onMouseLeave, false);
3155 targetEl.addEventListener(EVENTS.WHEEL, this._onWheel, false);
3156 this._enabled = true;
3157 };
3158 /**
3159 * Disable this input and remove all event handlers
3160 * @returns {void} Nothing
3161 */
3162
3163
3164 __proto.disable = function () {
3165 if (!this._enabled || !this._targetEl) return;
3166 var targetEl = this._targetEl;
3167 targetEl.removeEventListener(EVENTS.MOUSE_DOWN, this._onMouseDown, false);
3168 window.removeEventListener(EVENTS.MOUSE_UP, this._onMouseUp, false);
3169 targetEl.removeEventListener(EVENTS.TOUCH_START, this._onTouchStart, false);
3170 targetEl.removeEventListener(EVENTS.TOUCH_END, this._onTouchEnd, false);
3171 targetEl.removeEventListener(EVENTS.MOUSE_ENTER, this._onMouseEnter, false);
3172 targetEl.removeEventListener(EVENTS.MOUSE_LEAVE, this._onMouseLeave, false);
3173 targetEl.removeEventListener(EVENTS.WHEEL, this._onWheel, false);
3174 this._enabled = false;
3175 this._interrupted = false;
3176 this._hovering = false;
3177
3178 this._clearTimeout();
3179 }; // This does nothing
3180
3181
3182 __proto.sync = function (camera) {// Do nothing
3183 };
3184 /**
3185 * Set target element to attach event listener
3186 * @param element target element
3187 * @returns {void} Nothing
3188 */
3189
3190
3191 __proto.setElement = function (element) {
3192 this._targetEl = element;
3193 };
3194
3195 __proto._setUninterruptedAfterDelay = function (delay) {
3196 var _this = this;
3197
3198 if (this._hovering) return;
3199
3200 this._clearTimeout();
3201
3202 if (delay > 0) {
3203 this._interruptionTimer = window.setTimeout(function () {
3204 _this._interrupted = false;
3205 _this._interruptionTimer = -1;
3206 }, delay);
3207 } else {
3208 this._interrupted = false;
3209 this._interruptionTimer = -1;
3210 }
3211 };
3212
3213 __proto._clearTimeout = function () {
3214 if (this._interruptionTimer >= 0) {
3215 window.clearTimeout(this._interruptionTimer);
3216 this._interruptionTimer = -1;
3217 }
3218 };
3219
3220 return AutoControl;
3221 }();
3222
3223 /*
3224 * Copyright (c) 2020 NAVER Corp.
3225 * egjs projects are licensed under the MIT license
3226 */
3227 var CURSOR = {
3228 GRAB: "grab",
3229 GRABBING: "grabbing"
3230 };
3231
3232 /*
3233 * Copyright (c) 2020 NAVER Corp.
3234 * egjs projects are licensed under the MIT license
3235 */
3236 /**
3237 * Model's rotation control that supports both mouse & touch
3238 * @category Controls
3239 */
3240
3241 var RotateControl =
3242 /*#__PURE__*/
3243 function () {
3244 /**
3245 * Create new RotateControl instance
3246 * @param {object} options Options
3247 * @param {HTMLElement | null} [options.element] Target element.
3248 * @param {number} [options.duration=500] Motion's duration.
3249 * @param {function} [options.easing=(x: number) => 1 - Math.pow(1 - x, 3)] Motion's easing function.
3250 * @param {THREE.Vector2} [options.scale=new THREE.Vector2(1, 1)] Scale factor for panning, x is for horizontal and y is for vertical panning.
3251 * @param {boolean} [options.useGrabCursor=true] Whether to apply CSS style `cursor: grab` on the target element or not.
3252 * @param {boolean} [options.scaleToElement=true] Whether to scale control to fit element size.
3253 * @tutorial Adding Controls
3254 */
3255 function RotateControl(_a) {
3256 var _this = this;
3257
3258 var _b = _a === void 0 ? {} : _a,
3259 _c = _b.element,
3260 element = _c === void 0 ? NULL_ELEMENT : _c,
3261 _d = _b.duration,
3262 duration = _d === void 0 ? ANIMATION_DURATION : _d,
3263 _e = _b.easing,
3264 easing = _e === void 0 ? EASING$1 : _e,
3265 _f = _b.scale,
3266 scale = _f === void 0 ? new THREE.Vector2(1, 1) : _f,
3267 _g = _b.useGrabCursor,
3268 useGrabCursor = _g === void 0 ? true : _g,
3269 _h = _b.scaleToElement,
3270 scaleToElement = _h === void 0 ? true : _h; // Internal values
3271
3272
3273 this._targetEl = null;
3274 this._screenScale = new THREE.Vector2(0, 0);
3275 this._prevPos = new THREE.Vector2(0, 0);
3276 this._enabled = false;
3277
3278 this._onMouseDown = function (evt) {
3279 if (evt.button !== MOUSE_BUTTON.LEFT) return;
3280 var targetEl = _this._targetEl;
3281 evt.preventDefault();
3282 targetEl.focus ? targetEl.focus() : window.focus();
3283
3284 _this._prevPos.set(evt.clientX, evt.clientY);
3285
3286 window.addEventListener(EVENTS.MOUSE_MOVE, _this._onMouseMove, false);
3287 window.addEventListener(EVENTS.MOUSE_UP, _this._onMouseUp, false);
3288
3289 _this._setCursor(CURSOR.GRABBING);
3290 };
3291
3292 this._onMouseMove = function (evt) {
3293 evt.preventDefault();
3294 var prevPos = _this._prevPos;
3295 var rotateDelta = new THREE.Vector2(evt.clientX, evt.clientY).sub(prevPos).multiply(_this._userScale);
3296
3297 if (_this._scaleToElement) {
3298 rotateDelta.multiply(_this._screenScale);
3299 }
3300
3301 _this._xMotion.setEndDelta(rotateDelta.x);
3302
3303 _this._yMotion.setEndDelta(rotateDelta.y);
3304
3305 prevPos.set(evt.clientX, evt.clientY);
3306 };
3307
3308 this._onMouseUp = function () {
3309 _this._prevPos.set(0, 0);
3310
3311 window.removeEventListener(EVENTS.MOUSE_MOVE, _this._onMouseMove, false);
3312 window.removeEventListener(EVENTS.MOUSE_UP, _this._onMouseUp, false);
3313
3314 _this._setCursor(CURSOR.GRAB);
3315 };
3316
3317 this._onTouchStart = function (evt) {
3318 evt.preventDefault();
3319 var touch = evt.touches[0];
3320
3321 _this._prevPos.set(touch.clientX, touch.clientY);
3322 };
3323
3324 this._onTouchMove = function (evt) {
3325 // Only the one finger motion should be considered
3326 if (evt.touches.length > 1) return;
3327
3328 if (evt.cancelable !== false) {
3329 evt.preventDefault();
3330 }
3331
3332 evt.stopPropagation();
3333 var touch = evt.touches[0];
3334 var prevPos = _this._prevPos;
3335 var rotateDelta = new THREE.Vector2(touch.clientX, touch.clientY).sub(prevPos).multiply(_this._userScale);
3336
3337 if (_this._scaleToElement) {
3338 rotateDelta.multiply(_this._screenScale);
3339 }
3340
3341 _this._xMotion.setEndDelta(rotateDelta.x);
3342
3343 _this._yMotion.setEndDelta(rotateDelta.y);
3344
3345 prevPos.set(touch.clientX, touch.clientY);
3346 };
3347
3348 this._onTouchEnd = function (evt) {
3349 var touch = evt.touches[0];
3350
3351 if (touch) {
3352 _this._prevPos.set(touch.clientX, touch.clientY);
3353 } else {
3354 _this._prevPos.set(0, 0);
3355 }
3356 };
3357
3358 var targetEl = getElement(element);
3359
3360 if (targetEl) {
3361 this.setElement(targetEl);
3362 }
3363
3364 this._userScale = scale;
3365 this._useGrabCursor = useGrabCursor;
3366 this._scaleToElement = scaleToElement;
3367 this._xMotion = new Motion({
3368 duration: duration,
3369 range: INFINITE_RANGE,
3370 easing: easing
3371 });
3372 this._yMotion = new Motion({
3373 duration: duration,
3374 range: PITCH_RANGE,
3375 easing: easing
3376 });
3377 }
3378
3379 var __proto = RotateControl.prototype;
3380 Object.defineProperty(__proto, "element", {
3381 /**
3382 * Control's current target element to attach event listeners
3383 * @readonly
3384 */
3385 get: function () {
3386 return this._targetEl;
3387 },
3388 enumerable: false,
3389 configurable: true
3390 });
3391 Object.defineProperty(__proto, "scale", {
3392 /**
3393 * Scale factor for panning, x is for horizontal and y is for vertical panning.
3394 * @type THREE.Vector2
3395 * @see https://threejs.org/docs/#api/en/math/Vector2
3396 * @example
3397 * const rotateControl = new View3D.RotateControl();
3398 * rotateControl.scale.setX(2);
3399 */
3400 get: function () {
3401 return this._userScale;
3402 },
3403 set: function (val) {
3404 this._userScale.copy(val);
3405 },
3406 enumerable: false,
3407 configurable: true
3408 });
3409 Object.defineProperty(__proto, "useGrabCursor", {
3410 /**
3411 * Whether to apply CSS style `cursor: grab` on the target element or not
3412 * @default true
3413 * @example
3414 * const rotateControl = new View3D.RotateControl();
3415 * rotateControl.useGrabCursor = true;
3416 */
3417 get: function () {
3418 return this._useGrabCursor;
3419 },
3420 set: function (val) {
3421 if (!val) {
3422 this._setCursor("");
3423
3424 this._useGrabCursor = false;
3425 } else {
3426 this._useGrabCursor = true;
3427
3428 this._setCursor(CURSOR.GRAB);
3429 }
3430 },
3431 enumerable: false,
3432 configurable: true
3433 });
3434 Object.defineProperty(__proto, "scaleToElement", {
3435 /**
3436 * Whether to scale control to fit element size.
3437 * When this is true and {@link RotateControl#scale scale.x} is 1, panning through element's width will make 3d model's yaw rotate 360°.
3438 * When this is true and {@link RotateControl#scale scale.y} is 1, panning through element's height will make 3d model's pitch rotate 180°.
3439 * @default true
3440 * @example
3441 * import View3D, { RotateControl } from "@egjs/view3d";
3442 * const view3d = new View3D("#view3d-canvas");
3443 * const rotateControl = new RotateControl();
3444 * rotateControl.scaleToElement = true;
3445 * view3d.controller.add(rotateControl);
3446 * view3d.resize();
3447 */
3448 get: function () {
3449 return this._scaleToElement;
3450 },
3451 set: function (val) {
3452 this._scaleToElement = val;
3453 },
3454 enumerable: false,
3455 configurable: true
3456 });
3457 Object.defineProperty(__proto, "enabled", {
3458 /**
3459 * Whether this control is enabled or not
3460 * @readonly
3461 */
3462 get: function () {
3463 return this._enabled;
3464 },
3465 enumerable: false,
3466 configurable: true
3467 });
3468 /**
3469 * Destroy the instance and remove all event listeners attached
3470 * This also will reset CSS cursor to intial
3471 * @returns {void} Nothing
3472 */
3473
3474 __proto.destroy = function () {
3475 this.disable();
3476 };
3477 /**
3478 * Update control by given deltaTime
3479 * @param camera Camera to update position
3480 * @param deltaTime Number of milisec to update
3481 * @returns {void} Nothing
3482 */
3483
3484
3485 __proto.update = function (camera, deltaTime) {
3486 var xMotion = this._xMotion;
3487 var yMotion = this._yMotion;
3488 var delta = new THREE.Vector2(xMotion.update(deltaTime), yMotion.update(deltaTime));
3489 camera.yaw += delta.x;
3490 camera.pitch += delta.y;
3491 };
3492 /**
3493 * Resize control to match target size
3494 * This method is only meaningful when {@link RotateControl#scaleToElement scaleToElement} is enabled
3495 * @param size {@link https://threejs.org/docs/#api/en/math/Vector2 THREE.Vector2} instance of width(x), height(y)
3496 */
3497
3498
3499 __proto.resize = function (size) {
3500 this._screenScale.set(360 / size.x, 180 / size.y);
3501 };
3502 /**
3503 * Enable this input and add event listeners
3504 * @returns {void} Nothing
3505 */
3506
3507
3508 __proto.enable = function () {
3509 if (this._enabled) return;
3510
3511 if (!this._targetEl) {
3512 throw new View3DError(MESSAGES.ADD_CONTROL_FIRST, CODES.ADD_CONTROL_FIRST);
3513 }
3514
3515 var targetEl = this._targetEl;
3516 targetEl.addEventListener(EVENTS.MOUSE_DOWN, this._onMouseDown, false);
3517 targetEl.addEventListener(EVENTS.TOUCH_START, this._onTouchStart, false);
3518 targetEl.addEventListener(EVENTS.TOUCH_MOVE, this._onTouchMove, false);
3519 targetEl.addEventListener(EVENTS.TOUCH_END, this._onTouchEnd, false);
3520 this._enabled = true;
3521
3522 this._setCursor(CURSOR.GRAB);
3523 };
3524 /**
3525 * Disable this input and remove all event handlers
3526 * @returns {void} Nothing
3527 */
3528
3529
3530 __proto.disable = function () {
3531 if (!this._enabled || !this._targetEl) return;
3532 var targetEl = this._targetEl;
3533 targetEl.removeEventListener(EVENTS.MOUSE_DOWN, this._onMouseDown, false);
3534 window.removeEventListener(EVENTS.MOUSE_MOVE, this._onMouseMove, false);
3535 window.removeEventListener(EVENTS.MOUSE_UP, this._onMouseUp, false);
3536 targetEl.removeEventListener(EVENTS.TOUCH_START, this._onTouchStart, false);
3537 targetEl.removeEventListener(EVENTS.TOUCH_MOVE, this._onTouchMove, false);
3538 targetEl.removeEventListener(EVENTS.TOUCH_END, this._onTouchEnd, false);
3539
3540 this._setCursor("");
3541
3542 this._enabled = false;
3543 };
3544 /**
3545 * Synchronize this control's state to given camera position
3546 * @param camera Camera to match state
3547 * @returns {void} Nothing
3548 */
3549
3550
3551 __proto.sync = function (camera) {
3552 this._xMotion.reset(camera.yaw);
3553
3554 this._yMotion.reset(camera.pitch);
3555 };
3556 /**
3557 * Set target element to attach event listener
3558 * @param element target element
3559 * @returns {void} Nothing
3560 */
3561
3562
3563 __proto.setElement = function (element) {
3564 this._targetEl = element;
3565 this.resize(new THREE.Vector2(element.offsetWidth, element.offsetHeight));
3566 };
3567
3568 __proto._setCursor = function (val) {
3569 var targetEl = this._targetEl;
3570 if (!this._useGrabCursor || !targetEl || !this._enabled) return;
3571 targetEl.style.cursor = val;
3572 };
3573
3574 return RotateControl;
3575 }();
3576
3577 /*
3578 * Copyright (c) 2020 NAVER Corp.
3579 * egjs projects are licensed under the MIT license
3580 */
3581 /**
3582 * Model's translation control that supports both mouse & touch
3583 * @category Controls
3584 */
3585
3586 var TranslateControl =
3587 /*#__PURE__*/
3588 function () {
3589 /**
3590 * Create new TranslateControl instance
3591 * @param {object} options Options
3592 * @param {HTMLElement | null} [options.element] Target element.
3593 * @param {function} [options.easing=(x: number) => 1 - Math.pow(1 - x, 3)] Motion's easing function.
3594 * @param {THREE.Vector2} [options.scale=new THREE.Vector2(1, 1)] Scale factor for translation.
3595 * @param {boolean} [options.useGrabCursor=true] Whether to apply CSS style `cursor: grab` on the target element or not.
3596 * @param {boolean} [options.scaleToElement=true] Whether to scale control to fit element size.
3597 * @tutorial Adding Controls
3598 */
3599 function TranslateControl(_a) {
3600 var _this = this;
3601
3602 var _b = _a === void 0 ? {} : _a,
3603 _c = _b.element,
3604 element = _c === void 0 ? NULL_ELEMENT : _c,
3605 _d = _b.easing,
3606 easing = _d === void 0 ? EASING$1 : _d,
3607 _e = _b.scale,
3608 scale = _e === void 0 ? new THREE.Vector2(1, 1) : _e,
3609 _f = _b.useGrabCursor,
3610 useGrabCursor = _f === void 0 ? true : _f,
3611 _g = _b.scaleToElement,
3612 scaleToElement = _g === void 0 ? true : _g; // Internal values
3613
3614
3615 this._targetEl = null;
3616 this._enabled = false; // Sometimes, touchstart for second finger doesn't triggered.
3617 // This flag checks whether that happened
3618
3619 this._touchInitialized = false;
3620 this._prevPos = new THREE.Vector2(0, 0);
3621 this._screenSize = new THREE.Vector2(0, 0);
3622
3623 this._onMouseDown = function (evt) {
3624 if (evt.button !== MOUSE_BUTTON.RIGHT) return;
3625 var targetEl = _this._targetEl;
3626 evt.preventDefault();
3627 targetEl.focus ? targetEl.focus() : window.focus();
3628
3629 _this._prevPos.set(evt.clientX, evt.clientY);
3630
3631 window.addEventListener(EVENTS.MOUSE_MOVE, _this._onMouseMove, false);
3632 window.addEventListener(EVENTS.MOUSE_UP, _this._onMouseUp, false);
3633
3634 _this._setCursor(CURSOR.GRABBING);
3635 };
3636
3637 this._onMouseMove = function (evt) {
3638 evt.preventDefault();
3639 var prevPos = _this._prevPos;
3640 var delta = new THREE.Vector2(evt.clientX, evt.clientY).sub(prevPos).multiply(_this._userScale); // X value is negated to match cursor direction
3641
3642 _this._xMotion.setEndDelta(-delta.x);
3643
3644 _this._yMotion.setEndDelta(delta.y);
3645
3646 prevPos.set(evt.clientX, evt.clientY);
3647 };
3648
3649 this._onMouseUp = function () {
3650 _this._prevPos.set(0, 0);
3651
3652 window.removeEventListener(EVENTS.MOUSE_MOVE, _this._onMouseMove, false);
3653 window.removeEventListener(EVENTS.MOUSE_UP, _this._onMouseUp, false);
3654
3655 _this._setCursor(CURSOR.GRAB);
3656 };
3657
3658 this._onTouchStart = function (evt) {
3659 // Only the two finger motion should be considered
3660 if (evt.touches.length !== 2) return;
3661 evt.preventDefault();
3662
3663 _this._prevPos.copy(_this._getTouchesMiddle(evt.touches));
3664
3665 _this._touchInitialized = true;
3666 };
3667
3668 this._onTouchMove = function (evt) {
3669 // Only the two finger motion should be considered
3670 if (evt.touches.length !== 2) return;
3671
3672 if (evt.cancelable !== false) {
3673 evt.preventDefault();
3674 }
3675
3676 evt.stopPropagation();
3677 var prevPos = _this._prevPos;
3678
3679 var middlePoint = _this._getTouchesMiddle(evt.touches);
3680
3681 if (!_this._touchInitialized) {
3682 prevPos.copy(middlePoint);
3683 _this._touchInitialized = true;
3684 return;
3685 }
3686
3687 var delta = new THREE.Vector2().subVectors(middlePoint, prevPos).multiply(_this._userScale); // X value is negated to match cursor direction
3688
3689 _this._xMotion.setEndDelta(-delta.x);
3690
3691 _this._yMotion.setEndDelta(delta.y);
3692
3693 prevPos.copy(middlePoint);
3694 };
3695
3696 this._onTouchEnd = function (evt) {
3697 // Only the two finger motion should be considered
3698 if (evt.touches.length !== 2) {
3699 _this._touchInitialized = false;
3700 return;
3701 } // Three fingers to two fingers
3702
3703
3704 _this._prevPos.copy(_this._getTouchesMiddle(evt.touches));
3705
3706 _this._touchInitialized = true;
3707 };
3708
3709 this._onContextMenu = function (evt) {
3710 evt.preventDefault();
3711 };
3712
3713 var targetEl = getElement(element);
3714
3715 if (targetEl) {
3716 this.setElement(targetEl);
3717 }
3718
3719 this._xMotion = new Motion({
3720 duration: 0,
3721 range: INFINITE_RANGE,
3722 easing: easing
3723 });
3724 this._yMotion = new Motion({
3725 duration: 0,
3726 range: INFINITE_RANGE,
3727 easing: easing
3728 });
3729 this._userScale = scale;
3730 this._useGrabCursor = useGrabCursor;
3731 this._scaleToElement = scaleToElement;
3732 }
3733
3734 var __proto = TranslateControl.prototype;
3735 Object.defineProperty(__proto, "element", {
3736 /**
3737 * Control's current target element to attach event listeners
3738 * @readonly
3739 */
3740 get: function () {
3741 return this._targetEl;
3742 },
3743 enumerable: false,
3744 configurable: true
3745 });
3746 Object.defineProperty(__proto, "scale", {
3747 /**
3748 * Scale factor for translation
3749 * @type THREE.Vector2
3750 * @see https://threejs.org/docs/#api/en/math/Vector2
3751 * @example
3752 * import { TranslateControl } from "@egjs/view3d";
3753 * const translateControl = new TranslateControl();
3754 * translateControl.scale.set(2, 2);
3755 */
3756 get: function () {
3757 return this._userScale;
3758 },
3759 set: function (val) {
3760 this._userScale.copy(val);
3761 },
3762 enumerable: false,
3763 configurable: true
3764 });
3765 Object.defineProperty(__proto, "useGrabCursor", {
3766 /**
3767 * Whether to apply CSS style `cursor: grab` on the target element or not
3768 * @default true
3769 * @example
3770 * import { TranslateControl } from "@egjs/view3d";
3771 * const translateControl = new TranslateControl();
3772 * translateControl.useGrabCursor = true;
3773 */
3774 get: function () {
3775 return this._useGrabCursor;
3776 },
3777 set: function (val) {
3778 if (!val) {
3779 this._setCursor("");
3780
3781 this._useGrabCursor = false;
3782 } else {
3783 this._useGrabCursor = true;
3784
3785 this._setCursor(CURSOR.GRAB);
3786 }
3787 },
3788 enumerable: false,
3789 configurable: true
3790 });
3791 Object.defineProperty(__proto, "scaleToElement", {
3792 /**
3793 * Scale control to fit element size.
3794 * When this is true, camera's pivot change will correspond same amount you've dragged.
3795 * @default true
3796 * @example
3797 * import View3D, { TranslateControl } from "@egjs/view3d";
3798 * const view3d = new View3D("#view3d-canvas");
3799 * const translateControl = new TranslateControl();
3800 * translateControl.scaleToElement = true;
3801 * view3d.controller.add(translateControl);
3802 * view3d.resize();
3803 */
3804 get: function () {
3805 return this._scaleToElement;
3806 },
3807 set: function (val) {
3808 this._scaleToElement = val;
3809 },
3810 enumerable: false,
3811 configurable: true
3812 });
3813 Object.defineProperty(__proto, "enabled", {
3814 /**
3815 * Whether this control is enabled or not
3816 * @readonly
3817 */
3818 get: function () {
3819 return this._enabled;
3820 },
3821 enumerable: false,
3822 configurable: true
3823 });
3824 /**
3825 * Destroy the instance and remove all event listeners attached
3826 * This also will reset CSS cursor to intial
3827 * @returns {void} Nothing
3828 */
3829
3830 __proto.destroy = function () {
3831 this.disable();
3832 };
3833 /**
3834 * Update control by given deltaTime
3835 * @param deltaTime Number of milisec to update
3836 * @returns {void} Nothing
3837 */
3838
3839
3840 __proto.update = function (camera, deltaTime) {
3841 var screenSize = this._screenSize;
3842 var delta = new THREE.Vector2(this._xMotion.update(deltaTime), this._yMotion.update(deltaTime));
3843 var viewXDir = new THREE.Vector3(1, 0, 0).applyQuaternion(camera.threeCamera.quaternion);
3844 var viewYDir = new THREE.Vector3(0, 1, 0).applyQuaternion(camera.threeCamera.quaternion);
3845
3846 if (this._scaleToElement) {
3847 var screenScale = new THREE.Vector2(camera.renderWidth, camera.renderHeight).divide(screenSize);
3848 delta.multiply(screenScale);
3849 }
3850
3851 camera.pivot.add(viewXDir.multiplyScalar(delta.x));
3852 camera.pivot.add(viewYDir.multiplyScalar(delta.y));
3853 };
3854 /**
3855 * Resize control to match target size
3856 * This method is only meaningful when {@link RotateControl#scaleToElementSize scaleToElementSize} is enabled
3857 * @param size {@link https://threejs.org/docs/#api/en/math/Vector2 THREE.Vector2} instance of width(x), height(y)
3858 */
3859
3860
3861 __proto.resize = function (size) {
3862 var screenSize = this._screenSize;
3863 screenSize.copy(size);
3864 };
3865 /**
3866 * Enable this input and add event listeners
3867 * @returns {void} Nothing
3868 */
3869
3870
3871 __proto.enable = function () {
3872 if (this._enabled) return;
3873
3874 if (!this._targetEl) {
3875 throw new View3DError(MESSAGES.ADD_CONTROL_FIRST, CODES.ADD_CONTROL_FIRST);
3876 }
3877
3878 var targetEl = this._targetEl;
3879 targetEl.addEventListener(EVENTS.MOUSE_DOWN, this._onMouseDown, false);
3880 targetEl.addEventListener(EVENTS.TOUCH_START, this._onTouchStart, false);
3881 targetEl.addEventListener(EVENTS.TOUCH_MOVE, this._onTouchMove, false);
3882 targetEl.addEventListener(EVENTS.TOUCH_END, this._onTouchEnd, false);
3883 targetEl.addEventListener(EVENTS.CONTEXT_MENU, this._onContextMenu, false);
3884 this._enabled = true;
3885
3886 this._setCursor(CURSOR.GRAB);
3887 };
3888 /**
3889 * Disable this input and remove all event handlers
3890 * @returns {void} Nothing
3891 */
3892
3893
3894 __proto.disable = function () {
3895 if (!this._enabled || !this._targetEl) return;
3896 var targetEl = this._targetEl;
3897 targetEl.removeEventListener(EVENTS.MOUSE_DOWN, this._onMouseDown, false);
3898 window.removeEventListener(EVENTS.MOUSE_MOVE, this._onMouseMove, false);
3899 window.removeEventListener(EVENTS.MOUSE_UP, this._onMouseUp, false);
3900 targetEl.removeEventListener(EVENTS.TOUCH_START, this._onTouchStart, false);
3901 targetEl.removeEventListener(EVENTS.TOUCH_MOVE, this._onTouchMove, false);
3902 targetEl.removeEventListener(EVENTS.TOUCH_END, this._onTouchEnd, false);
3903 targetEl.removeEventListener(EVENTS.CONTEXT_MENU, this._onContextMenu, false);
3904
3905 this._setCursor("");
3906
3907 this._enabled = false;
3908 };
3909 /**
3910 * Synchronize this control's state to given camera position
3911 * @param camera Camera to match state
3912 * @returns {void} Nothing
3913 */
3914
3915
3916 __proto.sync = function (camera) {
3917 this._xMotion.reset(0);
3918
3919 this._yMotion.reset(0);
3920 };
3921 /**
3922 * Set target element to attach event listener
3923 * @param element target element
3924 * @returns {void} Nothing
3925 */
3926
3927
3928 __proto.setElement = function (element) {
3929 this._targetEl = element;
3930 this.resize(new THREE.Vector2(element.offsetWidth, element.offsetHeight));
3931 };
3932
3933 __proto._setCursor = function (val) {
3934 var targetEl = this._targetEl;
3935 if (!this._useGrabCursor || !targetEl || !this._enabled) return;
3936 targetEl.style.cursor = val;
3937 };
3938
3939 __proto._getTouchesMiddle = function (touches) {
3940 return new THREE.Vector2(touches[0].clientX + touches[1].clientX, touches[0].clientY + touches[1].clientY).multiplyScalar(0.5);
3941 };
3942
3943 return TranslateControl;
3944 }();
3945
3946 /*
3947 * Copyright (c) 2020 NAVER Corp.
3948 * egjs projects are licensed under the MIT license
3949 */
3950 /**
3951 * Distance controller handling both mouse wheel and pinch zoom
3952 * @category Controls
3953 */
3954
3955 var DistanceControl =
3956 /*#__PURE__*/
3957 function () {
3958 /**
3959 * Create new DistanceControl instance
3960 * @tutorial Adding Controls
3961 * @param {object} options Options
3962 * @param {HTMLElement | string | null} [options.element=null] Attaching element / selector of the element.
3963 * @param {number} [options.duration=500] Motion's duration.
3964 * @param {object} [options.range={min: 0, max: 500}] Motion's range.
3965 * @param {function} [options.easing=(x: number) => 1 - Math.pow(1 - x, 3)] Motion's easing function.
3966 */
3967 function DistanceControl(_a) {
3968 var _this = this;
3969
3970 var _b = _a === void 0 ? {} : _a,
3971 _c = _b.element,
3972 element = _c === void 0 ? NULL_ELEMENT : _c,
3973 _d = _b.duration,
3974 duration = _d === void 0 ? ANIMATION_DURATION : _d,
3975 _e = _b.range,
3976 range = _e === void 0 ? DISTANCE_RANGE : _e,
3977 _f = _b.easing,
3978 easing = _f === void 0 ? EASING$1 : _f; // Options
3979
3980
3981 this._scale = 1; // Internal values
3982
3983 this._targetEl = null;
3984 this._scaleModifier = 0.25;
3985 this._prevTouchDistance = -1;
3986 this._enabled = false;
3987
3988 this._onWheel = function (evt) {
3989 if (evt.deltaY === 0) return;
3990 evt.preventDefault();
3991 evt.stopPropagation();
3992 var animation = _this._motion;
3993 var delta = _this._scale * _this._scaleModifier * evt.deltaY;
3994 animation.setEndDelta(delta);
3995 };
3996
3997 this._onTouchMove = function (evt) {
3998 var touches = evt.touches;
3999 if (touches.length !== 2) return;
4000
4001 if (evt.cancelable !== false) {
4002 evt.preventDefault();
4003 }
4004
4005 evt.stopPropagation();
4006 var animation = _this._motion;
4007 var prevTouchDistance = _this._prevTouchDistance;
4008 var touchPoint1 = new THREE.Vector2(touches[0].pageX, touches[0].pageY);
4009 var touchPoint2 = new THREE.Vector2(touches[1].pageX, touches[1].pageY);
4010 var touchDiff = touchPoint1.sub(touchPoint2);
4011
4012 var touchDistance = touchDiff.length() * _this._scale * _this._scaleModifier;
4013
4014 var delta = -(touchDistance - prevTouchDistance);
4015 _this._prevTouchDistance = touchDistance;
4016 if (prevTouchDistance < 0) return;
4017 animation.setEndDelta(delta);
4018 };
4019
4020 this._onTouchEnd = function () {
4021 _this._prevTouchDistance = -1;
4022 };
4023
4024 var targetEl = getElement(element);
4025
4026 if (targetEl) {
4027 this.setElement(targetEl);
4028 }
4029
4030 this._motion = new Motion({
4031 duration: duration,
4032 range: range,
4033 easing: easing
4034 });
4035 }
4036
4037 var __proto = DistanceControl.prototype;
4038 Object.defineProperty(__proto, "element", {
4039 /**
4040 * Control's current target element to attach event listeners
4041 * @readonly
4042 */
4043 get: function () {
4044 return this._targetEl;
4045 },
4046 enumerable: false,
4047 configurable: true
4048 });
4049 Object.defineProperty(__proto, "scale", {
4050 /**
4051 * Scale factor of the distance
4052 * @type number
4053 * @example
4054 * import { DistanceControl } from "@egjs/view3d";
4055 * const distanceControl = new DistanceControl();
4056 * distanceControl.scale = 2;
4057 */
4058 get: function () {
4059 return this._scale;
4060 },
4061 set: function (val) {
4062 this._scale = val;
4063 },
4064 enumerable: false,
4065 configurable: true
4066 });
4067 Object.defineProperty(__proto, "enabled", {
4068 /**
4069 * Whether this control is enabled or not
4070 * @readonly
4071 */
4072 get: function () {
4073 return this._enabled;
4074 },
4075 enumerable: false,
4076 configurable: true
4077 });
4078 /**
4079 * Destroy the instance and remove all event listeners attached
4080 * @returns {void} Nothing
4081 */
4082
4083 __proto.destroy = function () {
4084 this.disable();
4085 };
4086 /**
4087 * Update control by given deltaTime
4088 * @param camera Camera to update position
4089 * @param deltaTime Number of milisec to update
4090 * @returns {void} Nothing
4091 */
4092
4093
4094 __proto.update = function (camera, deltaTime) {
4095 var motion = this._motion;
4096 camera.distance += motion.update(deltaTime);
4097 }; // This is not documetned on purpose as it doesn't do nothing
4098
4099
4100 __proto.resize = function (size) {// DO NOTHING
4101 };
4102 /**
4103 * Enable this input and add event listeners
4104 * @returns {void} Nothing
4105 */
4106
4107
4108 __proto.enable = function () {
4109 if (this._enabled) return;
4110
4111 if (!this._targetEl) {
4112 throw new View3DError(MESSAGES.ADD_CONTROL_FIRST, CODES.ADD_CONTROL_FIRST);
4113 }
4114
4115 var targetEl = this._targetEl;
4116 targetEl.addEventListener(EVENTS.WHEEL, this._onWheel, false);
4117 targetEl.addEventListener(EVENTS.TOUCH_MOVE, this._onTouchMove, false);
4118 targetEl.addEventListener(EVENTS.TOUCH_END, this._onTouchEnd, false);
4119 this._enabled = true;
4120 };
4121 /**
4122 * Disable this input and remove all event handlers
4123 * @returns {void} Nothing
4124 */
4125
4126
4127 __proto.disable = function () {
4128 if (!this._enabled || !this._targetEl) return;
4129 var targetEl = this._targetEl;
4130 targetEl.removeEventListener(EVENTS.WHEEL, this._onWheel, false);
4131 targetEl.removeEventListener(EVENTS.TOUCH_MOVE, this._onTouchMove, false);
4132 targetEl.removeEventListener(EVENTS.TOUCH_END, this._onTouchEnd, false);
4133 this._enabled = false;
4134 };
4135 /**
4136 * Synchronize this control's state to given camera position
4137 * @param camera Camera to match state
4138 * @returns {void} Nothing
4139 */
4140
4141
4142 __proto.sync = function (camera) {
4143 this._motion.range.min = camera.minDistance;
4144 this._motion.range.max = camera.maxDistance;
4145
4146 this._motion.reset(camera.distance);
4147 };
4148 /**
4149 * Set target element to attach event listener
4150 * @param element target element
4151 * @returns {void} Nothing
4152 */
4153
4154
4155 __proto.setElement = function (element) {
4156 this._targetEl = element;
4157 };
4158
4159 return DistanceControl;
4160 }();
4161
4162 /*
4163 * Copyright (c) 2020 NAVER Corp.
4164 * egjs projects are licensed under the MIT license
4165 */
4166 /**
4167 * Aggregation of {@link RotateControl}, {@link TranslateControl}, and {@link DistanceControl}.
4168 * @category Controls
4169 */
4170
4171 var OrbitControl =
4172 /*#__PURE__*/
4173 function () {
4174 /**
4175 * Create new OrbitControl instance
4176 * @param {object} options Options
4177 * @param {HTMLElement | string | null} [options.element=null] Attaching element / selector of the element
4178 * @param {object} [options.rotate={}] Constructor options of {@link RotateControl}
4179 * @param {object} [options.translate={}] Constructor options of {@link TranslateControl}
4180 * @param {object} [options.distance={}] Constructor options of {@link DistanceControl}
4181 * @tutorial Adding Controls
4182 */
4183 function OrbitControl(_a) {
4184 var _b = _a === void 0 ? {} : _a,
4185 _c = _b.element,
4186 element = _c === void 0 ? NULL_ELEMENT : _c,
4187 _d = _b.rotate,
4188 rotate = _d === void 0 ? {} : _d,
4189 _e = _b.translate,
4190 translate = _e === void 0 ? {} : _e,
4191 _f = _b.distance,
4192 distance = _f === void 0 ? {} : _f;
4193
4194 this._enabled = false;
4195 this._targetEl = getElement(element);
4196 this._rotateControl = new RotateControl(__assign(__assign({}, rotate), {
4197 element: rotate.element || this._targetEl
4198 }));
4199 this._translateControl = new TranslateControl(__assign(__assign({}, translate), {
4200 element: translate.element || this._targetEl
4201 }));
4202 this._distanceControl = new DistanceControl(__assign(__assign({}, distance), {
4203 element: distance.element || this._targetEl
4204 }));
4205 }
4206
4207 var __proto = OrbitControl.prototype;
4208 Object.defineProperty(__proto, "element", {
4209 /**
4210 * Control's current target element to attach event listeners
4211 * @readonly
4212 */
4213 get: function () {
4214 return this._targetEl;
4215 },
4216 enumerable: false,
4217 configurable: true
4218 });
4219 Object.defineProperty(__proto, "enabled", {
4220 /**
4221 * Whether this control is enabled or not
4222 * @readonly
4223 */
4224 get: function () {
4225 return this._enabled;
4226 },
4227 enumerable: false,
4228 configurable: true
4229 });
4230 Object.defineProperty(__proto, "rotate", {
4231 /**
4232 * {@link RotateControl} of this control
4233 */
4234 get: function () {
4235 return this._rotateControl;
4236 },
4237 enumerable: false,
4238 configurable: true
4239 });
4240 Object.defineProperty(__proto, "translate", {
4241 /**
4242 * {@link TranslateControl} of this control
4243 */
4244 get: function () {
4245 return this._translateControl;
4246 },
4247 enumerable: false,
4248 configurable: true
4249 });
4250 Object.defineProperty(__proto, "distance", {
4251 /**
4252 * {@link DistanceControl} of this control
4253 */
4254 get: function () {
4255 return this._distanceControl;
4256 },
4257 enumerable: false,
4258 configurable: true
4259 });
4260 /**
4261 * Destroy the instance and remove all event listeners attached
4262 * This also will reset CSS cursor to intial
4263 * @returns {void} Nothing
4264 */
4265
4266 __proto.destroy = function () {
4267 this._rotateControl.destroy();
4268
4269 this._translateControl.destroy();
4270
4271 this._distanceControl.destroy();
4272 };
4273 /**
4274 * Update control by given deltaTime
4275 * @param camera Camera to update position
4276 * @param deltaTime Number of milisec to update
4277 * @returns {void} Nothing
4278 */
4279
4280
4281 __proto.update = function (camera, deltaTime) {
4282 this._rotateControl.update(camera, deltaTime);
4283
4284 this._translateControl.update(camera, deltaTime);
4285
4286 this._distanceControl.update(camera, deltaTime);
4287 };
4288 /**
4289 * Resize control to match target size
4290 * @param size {@link https://threejs.org/docs/#api/en/math/Vector2 THREE.Vector2} instance of width(x), height(y)
4291 */
4292
4293
4294 __proto.resize = function (size) {
4295 this._rotateControl.resize(size);
4296
4297 this._translateControl.resize(size);
4298
4299 this._distanceControl.resize(size);
4300 };
4301 /**
4302 * Enable this control and add event listeners
4303 * @returns {void} Nothingß
4304 */
4305
4306
4307 __proto.enable = function () {
4308 if (this._enabled) return;
4309
4310 if (!this._targetEl) {
4311 throw new View3DError(MESSAGES.ADD_CONTROL_FIRST, CODES.ADD_CONTROL_FIRST);
4312 }
4313
4314 this._rotateControl.enable();
4315
4316 this._translateControl.enable();
4317
4318 this._distanceControl.enable();
4319
4320 this._enabled = true;
4321 };
4322 /**
4323 * Disable this control and remove all event handlers
4324 * @returns {void} Nothing
4325 */
4326
4327
4328 __proto.disable = function () {
4329 if (!this._enabled || !this._targetEl) return;
4330
4331 this._rotateControl.disable();
4332
4333 this._translateControl.disable();
4334
4335 this._distanceControl.disable();
4336
4337 this._enabled = false;
4338 };
4339 /**
4340 * Synchronize this control's state to given camera position
4341 * @param camera Camera to match state
4342 * @returns {void} Nothing
4343 */
4344
4345
4346 __proto.sync = function (camera) {
4347 this._rotateControl.sync(camera);
4348
4349 this._translateControl.sync(camera);
4350
4351 this._distanceControl.sync(camera);
4352 };
4353 /**
4354 * Set target element to attach event listener
4355 * @param element target element
4356 * @returns {void} Nothing
4357 */
4358
4359
4360 __proto.setElement = function (element) {
4361 this._targetEl = element;
4362
4363 this._rotateControl.setElement(element);
4364
4365 this._translateControl.setElement(element);
4366
4367 this._distanceControl.setElement(element);
4368 };
4369
4370 return OrbitControl;
4371 }();
4372
4373 /*
4374 * Copyright (c) 2020 NAVER Corp.
4375 * egjs projects are licensed under the MIT license
4376 */
4377
4378 var Controls = {
4379 __proto__: null,
4380 AnimationControl: AnimationControl,
4381 AutoControl: AutoControl,
4382 Motion: Motion,
4383 OrbitControl: OrbitControl,
4384 RotateControl: RotateControl,
4385 TranslateControl: TranslateControl,
4386 DistanceControl: DistanceControl
4387 };
4388
4389 /**
4390 * DracoLoader
4391 * @category Loaders
4392 */
4393
4394 var DracoLoader =
4395 /*#__PURE__*/
4396 function () {
4397 function DracoLoader() {}
4398 /**
4399 * Load new DRC model from the given url
4400 * @param url URL to fetch .drc file
4401 * @param options Options for a loaded model
4402 * @returns Promise that resolves {@link Model}
4403 */
4404
4405
4406 var __proto = DracoLoader.prototype;
4407
4408 __proto.load = function (url, options) {
4409 var _this = this;
4410
4411 if (options === void 0) {
4412 options = {};
4413 }
4414
4415 var loader = new DRACOLoader.DRACOLoader();
4416 loader.setCrossOrigin("anonymous");
4417 loader.setDecoderPath(DRACO_DECODER_URL);
4418 loader.manager = new THREE.LoadingManager();
4419 return new Promise(function (resolve, reject) {
4420 loader.load(url, function (geometry) {
4421 var model = _this._parseToModel(geometry, options);
4422
4423 loader.dispose();
4424 resolve(model);
4425 }, undefined, function (err) {
4426 loader.dispose();
4427 reject(err);
4428 });
4429 });
4430 };
4431
4432 __proto._parseToModel = function (geometry, _a) {
4433 var _b = _a === void 0 ? {} : _a,
4434 _c = _b.fixSkinnedBbox,
4435 fixSkinnedBbox = _c === void 0 ? false : _c,
4436 _d = _b.color,
4437 color = _d === void 0 ? 0xffffff : _d,
4438 _e = _b.point,
4439 point = _e === void 0 ? false : _e,
4440 _f = _b.pointOptions,
4441 pointOptions = _f === void 0 ? {} : _f;
4442
4443 geometry.computeVertexNormals();
4444 var material = point ? new THREE.PointsMaterial(__assign({
4445 color: color
4446 }, pointOptions)) : new THREE.MeshStandardMaterial({
4447 color: color
4448 });
4449 var mesh = point ? new THREE.Points(geometry, material) : new THREE.Mesh(geometry, material);
4450 var model = new Model({
4451 scenes: [mesh],
4452 fixSkinnedBbox: fixSkinnedBbox
4453 });
4454 return model;
4455 };
4456
4457 return DracoLoader;
4458 }();
4459
4460 /*
4461 * Copyright (c) 2020 NAVER Corp.
4462 * egjs projects are licensed under the MIT license
4463 */
4464 /**
4465 * THREE.DirectionalLight wrapper that will automatically update its shadow size to model
4466 * Shadow is enabled by default, use {@link AutoDirectionalLight#disableShadow disableShadow} to disable it
4467 * @category Environment
4468 */
4469
4470 var AutoDirectionalLight =
4471 /*#__PURE__*/
4472 function () {
4473 /**
4474 * Create new instance of AutoDirectionalLight
4475 * @param [color="#ffffff"] Color of the light
4476 * @param [intensity=1] Intensity of the light
4477 * @param {object} [options={}] Additional options
4478 * @param {THREE.Vector3} [options.direction=new THREE.Vector3(-1, -1, -1)] Direction of the light
4479 */
4480 function AutoDirectionalLight(color, intensity, _a) {
4481 if (color === void 0) {
4482 color = "#ffffff";
4483 }
4484
4485 if (intensity === void 0) {
4486 intensity = 1;
4487 }
4488
4489 var _b = (_a === void 0 ? {} : _a).direction,
4490 direction = _b === void 0 ? new THREE.Vector3(-1, -1, -1) : _b;
4491 this._light = new THREE.DirectionalLight(color, intensity); // Set the default position ratio of the directional light
4492
4493 var light = this._light;
4494 light.castShadow = true; // Is enabled by default
4495
4496 light.shadow.mapSize.width = 2048;
4497 light.shadow.mapSize.height = 2048;
4498 light.matrixAutoUpdate = false;
4499 this._direction = direction.clone().normalize();
4500 }
4501
4502 var __proto = AutoDirectionalLight.prototype;
4503 Object.defineProperty(__proto, "objects", {
4504 /**
4505 * Array of lights that used in this preset
4506 * @see https://threejs.org/docs/#api/en/lights/Light
4507 */
4508 get: function () {
4509 return [this._light, this._light.target];
4510 },
4511 enumerable: false,
4512 configurable: true
4513 });
4514 Object.defineProperty(__proto, "light", {
4515 /**
4516 * The actual THREE.DirectionalLight
4517 * @type THREE#DirectionalLight
4518 * @see https://threejs.org/docs/#api/en/lights/DirectionalLight
4519 */
4520 get: function () {
4521 return this._light;
4522 },
4523 enumerable: false,
4524 configurable: true
4525 });
4526 Object.defineProperty(__proto, "position", {
4527 /**
4528 * Position of the light
4529 * @type THREE#Vector3
4530 * @see https://threejs.org/docs/#api/en/math/Vector3
4531 */
4532 get: function () {
4533 return this._light.position;
4534 },
4535 enumerable: false,
4536 configurable: true
4537 });
4538 Object.defineProperty(__proto, "direction", {
4539 get: function () {
4540 return this._direction;
4541 },
4542 enumerable: false,
4543 configurable: true
4544 });
4545 /**
4546 * Make light cast a shadow
4547 */
4548
4549 __proto.enableShadow = function () {
4550 this._light.castShadow = true;
4551 };
4552 /**
4553 * Make light don't cast a shadow
4554 */
4555
4556
4557 __proto.disableShadow = function () {
4558 this._light.castShadow = false;
4559 };
4560 /**
4561 * Modify light's position & shadow camera size from model's bounding box
4562 * @param model Model to fit size
4563 * @param scale Scale factor for shadow camera size
4564 */
4565
4566
4567 __proto.fit = function (model, _a) {
4568 var _b = (_a === void 0 ? {} : _a).scale,
4569 scale = _b === void 0 ? 1.5 : _b;
4570 var bbox = model.bbox;
4571 var light = this._light;
4572 var direction = this._direction;
4573 var boxSize = bbox.getSize(new THREE.Vector3()).length();
4574 var boxCenter = bbox.getCenter(new THREE.Vector3()); // Position fitting
4575
4576 var newPos = new THREE.Vector3().addVectors(boxCenter, direction.clone().negate().multiplyScalar(boxSize * 0.5));
4577 light.position.copy(newPos);
4578 light.target.position.copy(boxCenter);
4579 light.updateMatrix(); // Shadowcam fitting
4580
4581 var shadowCam = light.shadow.camera;
4582 shadowCam.near = 0;
4583 shadowCam.far = 2 * boxSize;
4584 shadowCam.position.copy(newPos);
4585 shadowCam.lookAt(boxCenter);
4586 shadowCam.left = -1;
4587 shadowCam.right = 1;
4588 shadowCam.top = 1;
4589 shadowCam.bottom = -1;
4590 shadowCam.updateMatrixWorld();
4591 shadowCam.updateProjectionMatrix();
4592 var bboxPoints = getBoxPoints(bbox);
4593 var projectedPoints = bboxPoints.map(function (position) {
4594 return position.project(shadowCam);
4595 });
4596 var screenBbox = new THREE.Box3().setFromPoints(projectedPoints);
4597 shadowCam.left *= -scale * screenBbox.min.x;
4598 shadowCam.right *= scale * screenBbox.max.x;
4599 shadowCam.top *= scale * screenBbox.max.y;
4600 shadowCam.bottom *= -scale * screenBbox.min.y;
4601 shadowCam.updateProjectionMatrix();
4602 };
4603
4604 return AutoDirectionalLight;
4605 }();
4606
4607 /*
4608 * Copyright (c) 2020 NAVER Corp.
4609 * egjs projects are licensed under the MIT license
4610 */
4611 /**
4612 * Helper class to easily add shadow plane under your 3D model
4613 * @category Environment
4614 * @example
4615 * import View3D, { ShadowPlane } from "@egjs/view3d";
4616 *
4617 * const view3d = new View3D("#view3d-canvas");
4618 * const shadowPlane = new ShadowPlane();
4619 * view3d.scene.addEnv(shadowPlane);
4620 */
4621
4622 var ShadowPlane =
4623 /*#__PURE__*/
4624 function () {
4625 /**
4626 * Create new shadow plane
4627 * @param {object} options Options
4628 * @param {number} [options.size=10000] Size of the shadow plane
4629 * @param {number} [options.opacity=0.3] Opacity of the shadow
4630 */
4631 function ShadowPlane(_a) {
4632 var _b = _a === void 0 ? {} : _a,
4633 _c = _b.size,
4634 size = _c === void 0 ? 10000 : _c,
4635 _d = _b.opacity,
4636 opacity = _d === void 0 ? 0.3 : _d;
4637
4638 this.geometry = new THREE.PlaneGeometry(size, size, 100, 100);
4639 this.material = new THREE.ShadowMaterial({
4640 opacity: opacity
4641 });
4642 this.mesh = new THREE.Mesh(this.geometry, this.material);
4643 var mesh = this.mesh;
4644 mesh.rotateX(-Math.PI / 2);
4645 mesh.receiveShadow = true;
4646 }
4647
4648 var __proto = ShadowPlane.prototype;
4649 Object.defineProperty(__proto, "objects", {
4650 get: function () {
4651 return [this.mesh];
4652 },
4653 enumerable: false,
4654 configurable: true
4655 });
4656 Object.defineProperty(__proto, "opacity", {
4657 /**
4658 * Shadow opacity, value can be between 0(invisible) and 1(solid)
4659 * @type number
4660 */
4661 get: function () {
4662 return this.material.opacity;
4663 },
4664 set: function (val) {
4665 this.material.opacity = val;
4666 },
4667 enumerable: false,
4668 configurable: true
4669 });
4670 /**
4671 * Fit shadow plane's size & position to given model
4672 * @param model Model to fit
4673 */
4674
4675 __proto.fit = function (model, _a) {
4676 var _b = _a === void 0 ? {} : _a,
4677 floorPosition = _b.floorPosition,
4678 _c = _b.floorRotation,
4679 floorRotation = _c === void 0 ? new THREE.Quaternion(0, 0, 0, 1) : _c;
4680
4681 var modelPosition = model.scene.position;
4682 var localYAxis = new THREE.Vector3(0, 1, 0).applyQuaternion(floorRotation); // Apply position
4683
4684 if (floorPosition) {
4685 // Apply a tiny offset to prevent z-fighting with original model
4686 this.mesh.position.copy(floorPosition.clone().add(localYAxis.clone().multiplyScalar(0.001)));
4687 } else {
4688 var modelBbox = model.bbox;
4689 var modelBboxYOffset = modelBbox.getCenter(new THREE.Vector3()).y - modelBbox.min.y;
4690 var modelFloor = new THREE.Vector3().addVectors(modelPosition, // Apply a tiny offset to prevent z-fighting with original model
4691 localYAxis.multiplyScalar(-modelBboxYOffset + 0.0001));
4692 this.mesh.position.copy(modelFloor);
4693 } // Apply rotation
4694
4695
4696 var rotX90 = new THREE.Quaternion().setFromEuler(new THREE.Euler(-Math.PI / 2, 0, 0));
4697 var shadowRotation = new THREE.Quaternion().multiplyQuaternions(floorRotation, rotX90);
4698 this.mesh.quaternion.copy(shadowRotation);
4699 this.mesh.updateMatrix();
4700 };
4701
4702 return ShadowPlane;
4703 }();
4704
4705 /*
4706 * Copyright (c) 2020 NAVER Corp.
4707 * egjs projects are licensed under the MIT license
4708 */
4709
4710 var Environments = {
4711 __proto__: null,
4712 AutoDirectionalLight: AutoDirectionalLight,
4713 ShadowPlane: ShadowPlane
4714 };
4715
4716 /*
4717 * Copyright (c) 2020 NAVER Corp.
4718 * egjs projects are licensed under the MIT license
4719 */
4720 /**
4721 * GLTFLoader
4722 * @category Loaders
4723 */
4724
4725 var GLTFLoader =
4726 /*#__PURE__*/
4727 function () {
4728 /**
4729 * Create a new instance of GLTFLoader
4730 */
4731 function GLTFLoader() {
4732 this._loader = new GLTFLoader$1.GLTFLoader();
4733 this._dracoLoader = new DRACOLoader.DRACOLoader();
4734 var loader = this._loader;
4735 loader.setCrossOrigin("anonymous");
4736 var dracoLoader = this._dracoLoader;
4737 dracoLoader.setDecoderPath(DRACO_DECODER_URL);
4738 loader.setDRACOLoader(dracoLoader);
4739 }
4740
4741 var __proto = GLTFLoader.prototype;
4742 Object.defineProperty(__proto, "loader", {
4743 get: function () {
4744 return this._loader;
4745 },
4746 enumerable: false,
4747 configurable: true
4748 });
4749 Object.defineProperty(__proto, "dracoLoader", {
4750 get: function () {
4751 return this._dracoLoader;
4752 },
4753 enumerable: false,
4754 configurable: true
4755 });
4756 /**
4757 * Load new GLTF model from the given url
4758 * @param url URL to fetch glTF/glb file
4759 * @param options Options for a loaded model
4760 * @returns Promise that resolves {@link Model}
4761 */
4762
4763 __proto.load = function (url, options) {
4764 var _this = this;
4765
4766 if (options === void 0) {
4767 options = {};
4768 }
4769
4770 var loader = this._loader;
4771 loader.manager = new THREE.LoadingManager();
4772 return new Promise(function (resolve, reject) {
4773 loader.load(url, function (gltf) {
4774 var model = _this._parseToModel(gltf, options);
4775
4776 resolve(model);
4777 }, undefined, function (err) {
4778 reject(err);
4779 });
4780 });
4781 };
4782 /**
4783 * Load preset generated from View3D editor.
4784 * @param viewer Instance of the {@link View3D}.
4785 * @param url Preset url
4786 * @param {object} options Options
4787 * @param {string} [options.path] Base path for additional files.
4788 * @param {function} [options.onLoad] Callback which called after each model LOD is loaded.
4789 * @returns {Model} Model instance with highest LOD
4790 */
4791
4792
4793 __proto.loadPreset = function (viewer, url, options) {
4794 var _this = this;
4795
4796 if (options === void 0) {
4797 options = {};
4798 }
4799
4800 var loader = this._loader;
4801 var fileLoader = new THREE.FileLoader();
4802 return fileLoader.loadAsync(url).then(function (jsonRaw) {
4803 return new Promise(function (resolve, reject) {
4804 var json = JSON.parse(jsonRaw);
4805 var baseURL = THREE.LoaderUtils.extractUrlBase(url); // Reset
4806
4807 viewer.scene.reset();
4808 viewer.camera.reset();
4809 viewer.animator.reset();
4810 var modelOptions = json.model;
4811 var cameraOptions = json.camera;
4812 var environmentOptions = json.env;
4813 viewer.camera.setDefaultPose({
4814 yaw: cameraOptions.yaw,
4815 pitch: cameraOptions.pitch
4816 });
4817 viewer.camera.minDistance = cameraOptions.distanceRange[0];
4818 viewer.camera.maxDistance = cameraOptions.distanceRange[1];
4819
4820 if (environmentOptions.background) {
4821 viewer.scene.setBackground(new THREE.Color(environmentOptions.background));
4822 }
4823
4824 var shadowPlane = new ShadowPlane();
4825 shadowPlane.opacity = environmentOptions.shadow.opacity;
4826 viewer.scene.addEnv(shadowPlane);
4827 var ambientOptions = environmentOptions.ambient;
4828 var ambient = new THREE.AmbientLight(new THREE.Color(ambientOptions.color), ambientOptions.intensity);
4829 viewer.scene.addEnv(ambient);
4830 var lightOptions = [environmentOptions.light1, environmentOptions.light2, environmentOptions.light3];
4831 lightOptions.forEach(function (lightOption) {
4832 var lightDirection = new THREE.Vector3(lightOption.x, lightOption.y, lightOption.z).negate();
4833 var directional = new AutoDirectionalLight(new THREE.Color(lightOption.color), lightOption.intensity, {
4834 direction: lightDirection
4835 });
4836 directional.light.castShadow = lightOption.castShadow;
4837 directional.light.updateMatrixWorld();
4838 viewer.scene.addEnv(directional);
4839 });
4840 var isFirstLoad = true;
4841 var loadFlags = json.LOD.map(function () {
4842 return false;
4843 });
4844 json.LOD.forEach(function (fileName, lodIndex) {
4845 var glbURL = _this._resolveURL("" + baseURL + fileName, options.path || "");
4846
4847 loader.load(glbURL, function (gltf) {
4848 loadFlags[lodIndex] = true;
4849 var higherLODLoaded = loadFlags.slice(lodIndex + 1).some(function (loaded) {
4850 return loaded;
4851 });
4852 if (higherLODLoaded) return;
4853
4854 var model = _this._parseToModel(gltf);
4855
4856 viewer.display(model, {
4857 size: modelOptions.size,
4858 resetView: isFirstLoad
4859 });
4860 isFirstLoad = false;
4861 model.castShadow = modelOptions.castShadow;
4862 model.receiveShadow = modelOptions.receiveShadow;
4863
4864 if (options.onLoad) {
4865 options.onLoad(model, lodIndex);
4866 }
4867
4868 if (lodIndex === json.LOD.length - 1) {
4869 resolve(model);
4870 }
4871 }, undefined, function (err) {
4872 reject(err);
4873 });
4874 });
4875 });
4876 });
4877 };
4878 /**
4879 * Load new GLTF model from the given files
4880 * @param files Files that has glTF/glb and all its associated resources like textures and .bin data files
4881 * @param options Options for a loaded model
4882 * @returns Promise that resolves {@link Model}
4883 */
4884
4885
4886 __proto.loadFromFiles = function (files, options) {
4887 var _this = this;
4888
4889 if (options === void 0) {
4890 options = {};
4891 }
4892
4893 var objectURLs = [];
4894
4895 var revokeURLs = function () {
4896 objectURLs.forEach(function (url) {
4897 URL.revokeObjectURL(url);
4898 });
4899 };
4900
4901 return new Promise(function (resolve, reject) {
4902 if (files.length <= 0) {
4903 reject(new Error("No files found"));
4904 return;
4905 }
4906
4907 var gltfFile = files.find(function (file) {
4908 return /\.(gltf|glb)$/i.test(file.name);
4909 });
4910
4911 if (!gltfFile) {
4912 reject(new Error("No glTF file found"));
4913 return;
4914 }
4915
4916 var filesMap = new Map();
4917 files.forEach(function (file) {
4918 filesMap.set(file.name, file);
4919 });
4920 var gltfURL = URL.createObjectURL(gltfFile);
4921 objectURLs.push(gltfURL);
4922 var manager = new THREE.LoadingManager();
4923 manager.setURLModifier(function (fileURL) {
4924 var fileNameResult = /[^\/|\\]+$/.exec(fileURL);
4925 var fileName = fileNameResult && fileNameResult[0] || "";
4926
4927 if (filesMap.has(fileName)) {
4928 var blob = filesMap.get(fileName);
4929 var blobURL = URL.createObjectURL(blob);
4930 objectURLs.push(blobURL);
4931 return blobURL;
4932 }
4933
4934 return fileURL;
4935 });
4936 var loader = _this._loader;
4937 loader.manager = manager;
4938 loader.load(gltfURL, function (gltf) {
4939 var model = _this._parseToModel(gltf, options);
4940
4941 resolve(model);
4942 revokeURLs();
4943 }, undefined, function (err) {
4944 reject(err);
4945 revokeURLs();
4946 });
4947 });
4948 };
4949 /**
4950 * Parse from array buffer
4951 * @param data glTF asset to parse, as an ArrayBuffer or JSON string.
4952 * @param path The base path from which to find subsequent glTF resources such as textures and .bin data files.
4953 * @param options Options for a loaded model
4954 * @returns Promise that resolves {@link Model}
4955 */
4956
4957
4958 __proto.parse = function (data, path, options) {
4959 var _this = this;
4960
4961 if (options === void 0) {
4962 options = {};
4963 }
4964
4965 var loader = this._loader;
4966 loader.manager = new THREE.LoadingManager();
4967 return new Promise(function (resolve, reject) {
4968 loader.parse(data, path, function (gltf) {
4969 var model = _this._parseToModel(gltf, options);
4970
4971 resolve(model);
4972 }, function (err) {
4973 reject(err);
4974 });
4975 });
4976 };
4977
4978 __proto._parseToModel = function (gltf, _a) {
4979 var _b = (_a === void 0 ? {} : _a).fixSkinnedBbox,
4980 fixSkinnedBbox = _b === void 0 ? false : _b;
4981 var model = new Model({
4982 scenes: gltf.scenes,
4983 animations: gltf.animations,
4984 fixSkinnedBbox: fixSkinnedBbox
4985 });
4986 model.meshes.forEach(function (mesh) {
4987 var materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
4988 materials.forEach(function (mat) {
4989 if (mat.map) {
4990 mat.map.encoding = THREE.sRGBEncoding;
4991 }
4992 });
4993 });
4994 return model;
4995 }; // Grabbed from three.js/GLTFLoader
4996 // Original code: https://github.com/mrdoob/three.js/blob/master/examples/jsm/loaders/GLTFLoader.js#L1221
4997 // License: MIT
4998
4999
5000 __proto._resolveURL = function (url, path) {
5001 // Invalid URL
5002 if (typeof url !== "string" || url === "") return ""; // Host Relative URL
5003
5004 if (/^https?:\/\//i.test(path) && /^\//.test(url)) {
5005 path = path.replace(/(^https?:\/\/[^\/]+).*/i, "$1");
5006 } // Absolute URL http://,https://,//
5007
5008
5009 if (/^(https?:)?\/\//i.test(url)) return url; // Data URI
5010
5011 if (/^data:.*,.*$/i.test(url)) return url; // Blob URL
5012
5013 if (/^blob:.*$/i.test(url)) return url; // Relative URL
5014
5015 return path + url;
5016 };
5017
5018 return GLTFLoader;
5019 }();
5020
5021 /*
5022 * Copyright (c) 2020 NAVER Corp.
5023 * egjs projects are licensed under the MIT license
5024 */
5025 /**
5026 * Texture loader
5027 * @category Loaders
5028 */
5029
5030 var TextureLoader =
5031 /*#__PURE__*/
5032 function () {
5033 /**
5034 * Create new TextureLoader instance
5035 * @param renderer {@link Renderer} instance of View3D
5036 */
5037 function TextureLoader(renderer) {
5038 this._renderer = renderer;
5039 }
5040 /**
5041 * Create new {@link https://threejs.org/docs/index.html#api/en/textures/Texture Texture} with given url
5042 * Texture's {@link https://threejs.org/docs/index.html#api/en/textures/Texture.flipY flipY} property is `true` by Three.js's policy, so be careful when using it as a map texture.
5043 * @param url url to fetch image
5044 */
5045
5046
5047 var __proto = TextureLoader.prototype;
5048
5049 __proto.load = function (url) {
5050 return new Promise(function (resolve, reject) {
5051 var loader = new THREE.TextureLoader();
5052 loader.load(url, resolve, undefined, reject);
5053 });
5054 };
5055 /**
5056 * Create new {@link https://threejs.org/docs/#api/en/renderers/WebGLCubeRenderTarget WebGLCubeRenderTarget} with given equirectangular image url
5057 * Be sure that equirectangular image has height of power of 2, as it will be resized if it isn't
5058 * @param url url to fetch equirectangular image
5059 * @returns WebGLCubeRenderTarget created
5060 */
5061
5062
5063 __proto.loadEquirectagularTexture = function (url) {
5064 var _this = this;
5065
5066 return new Promise(function (resolve, reject) {
5067 var loader = new THREE.TextureLoader();
5068 loader.load(url, function (skyboxTexture) {
5069 resolve(_this._equirectToCubemap(skyboxTexture));
5070 }, undefined, reject);
5071 });
5072 };
5073 /**
5074 * Create new {@link https://threejs.org/docs/#api/en/textures/CubeTexture CubeTexture} with given cubemap image urls
5075 * Image order should be: px, nx, py, ny, pz, nz
5076 * @param urls cubemap image urls
5077 * @returns CubeTexture created
5078 */
5079
5080
5081 __proto.loadCubeTexture = function (urls) {
5082 return new Promise(function (resolve, reject) {
5083 var loader = new THREE.CubeTextureLoader();
5084 loader.load(urls, resolve, undefined, reject);
5085 });
5086 };
5087 /**
5088 * Create new texture with given HDR(RGBE) image url
5089 * @param url image url
5090 * @param isEquirectangular Whether to read this image as a equirectangular texture
5091 */
5092
5093
5094 __proto.loadHDRTexture = function (url, isEquirectangular) {
5095 var _this = this;
5096
5097 if (isEquirectangular === void 0) {
5098 isEquirectangular = true;
5099 }
5100
5101 return new Promise(function (resolve, reject) {
5102 var loader = new RGBELoader.RGBELoader();
5103 loader.load(url, function (texture) {
5104 if (isEquirectangular) {
5105 resolve(_this._equirectToCubemap(texture));
5106 } else {
5107 resolve(texture);
5108 }
5109 }, undefined, reject);
5110 });
5111 };
5112
5113 __proto._equirectToCubemap = function (texture) {
5114 return new THREE.WebGLCubeRenderTarget(texture.image.height).fromEquirectangularTexture(this._renderer.threeRenderer, texture);
5115 };
5116
5117 return TextureLoader;
5118 }();
5119
5120 /*
5121 * Copyright (c) 2020 NAVER Corp.
5122 * egjs projects are licensed under the MIT license
5123 */
5124
5125 var Loaders = {
5126 __proto__: null,
5127 GLTFLoader: GLTFLoader,
5128 DracoLoader: DracoLoader,
5129 TextureLoader: TextureLoader
5130 };
5131
5132 /*
5133 * Copyright (c) 2020 NAVER Corp.
5134 * egjs projects are licensed under the MIT license
5135 */
5136 var QUICKLOOK_SUPPORTED = function () {
5137 var anchorEl = document.createElement("a");
5138 return anchorEl.relList && anchorEl.relList.supports && anchorEl.relList.supports("ar");
5139 }();
5140 var WEBXR_SUPPORTED = navigator.xr && navigator.xr.isSessionSupported;
5141 var HIT_TEST_SUPPORTED = window.XRSession && window.XRSession.prototype.requestHitTestSource;
5142 var DOM_OVERLAY_SUPPORTED = window.XRDOMOverlayState != null;
5143 var SESSION = {
5144 AR: "immersive-ar",
5145 VR: "immersive-ar"
5146 };
5147 var REFERENCE_SPACE = {
5148 LOCAL: "local",
5149 LOCAL_FLOOR: "local-floor",
5150 VIEWER: "viewer"
5151 };
5152 var EVENTS$1 = {
5153 SELECT_START: "selectstart",
5154 SELECT: "select",
5155 SELECT_END: "selectend"
5156 };
5157 var INPUT_PROFILE = {
5158 TOUCH: "generic-touchscreen"
5159 };
5160 var FEATURES = {
5161 HIT_TEST: {
5162 requiredFeatures: ["hit-test"]
5163 },
5164 DOM_OVERLAY: function (root) {
5165 return {
5166 optionalFeatures: ["dom-overlay"],
5167 domOverlay: {
5168 root: root
5169 }
5170 };
5171 }
5172 }; // For type definition
5173
5174 var EMPTY_FEATURES = {};
5175 var SCENE_VIEWER = {
5176 INTENT_AR_CORE: function (params, fallback) {
5177 return "intent://arvr.google.com/scene-viewer/1.1?" + params + "#Intent;scheme=https;package=com.google.ar.core;action=android.intent.action.VIEW;" + (fallback ? "S.browser_fallback_url=" + fallback + ";" : "") + "end;";
5178 },
5179 INTENT_SEARCHBOX: function (params, fallback) {
5180 return "intent://arvr.google.com/scene-viewer/1.1?" + params + "#Intent;scheme=https;package=com.google.android.googlequicksearchbox;action=android.intent.action.VIEW;" + (fallback ? "S.browser_fallback_url=" + fallback + ";" : "") + "end;";
5181 },
5182 FALLBACK_DEFAULT: function (params) {
5183 return "https://arvr.google.com/scene-viewer?" + params;
5184 }
5185 };
5186
5187 /*
5188 * Copyright (c) 2020 NAVER Corp.
5189 * egjs projects are licensed under the MIT license
5190 */
5191 /**
5192 * Manager for WebXR dom-overlay feature
5193 * @category XR
5194 */
5195
5196 var DOMOverlay =
5197 /*#__PURE__*/
5198 function () {
5199 /**
5200 * Create new DOMOverlay instance
5201 * @param {object} [options] Options
5202 * @param {HTMLElement} [options.root] Overlay root element
5203 * @param {HTMLElement | null} [options.loadingEl] Model loading indicator element which will be invisible after placing model on the floor.
5204 */
5205 function DOMOverlay(options) {
5206 this._root = options.root;
5207 this._loadingEl = options.loadingEl;
5208 }
5209
5210 var __proto = DOMOverlay.prototype;
5211 Object.defineProperty(__proto, "root", {
5212 /**
5213 * Overlay root element
5214 */
5215 get: function () {
5216 return this._root;
5217 },
5218 enumerable: false,
5219 configurable: true
5220 });
5221 Object.defineProperty(__proto, "loadingElement", {
5222 /**
5223 * Loading indicator element, if there's any
5224 */
5225 get: function () {
5226 return this._loadingEl;
5227 },
5228 enumerable: false,
5229 configurable: true
5230 });
5231 Object.defineProperty(__proto, "features", {
5232 /**
5233 * {@link https://developer.mozilla.org/en-US/docs/Web/API/XRSessionInit XRSessionInit} object for dom-overlay feature
5234 */
5235 get: function () {
5236 return FEATURES.DOM_OVERLAY(this._root);
5237 },
5238 enumerable: false,
5239 configurable: true
5240 });
5241 /**
5242 * Return whether dom-overlay feature is available
5243 */
5244
5245 __proto.isAvailable = function () {
5246 return DOM_OVERLAY_SUPPORTED;
5247 };
5248 /**
5249 * Show loading indicator, if there's any
5250 */
5251
5252
5253 __proto.showLoading = function () {
5254 if (!this._loadingEl) return;
5255 this._loadingEl.style.visibility = "visible";
5256 };
5257 /**
5258 * Hide loading indicator, if there's any
5259 */
5260
5261
5262 __proto.hideLoading = function () {
5263 if (!this._loadingEl) return;
5264 this._loadingEl.style.visibility = "hidden";
5265 };
5266
5267 return DOMOverlay;
5268 }();
5269
5270 /*
5271 * Copyright (c) 2020 NAVER Corp.
5272 * egjs projects are licensed under the MIT license
5273 */
5274 /**
5275 * WebXR based abstract AR session class
5276 * @category XR
5277 * @fires WebARSession#start
5278 * @fires WebARSession#end
5279 * @fires WebARSession#canPlace
5280 * @fires WebARSession#modelPlaced
5281 */
5282
5283 var WebARSession =
5284 /*#__PURE__*/
5285 function (_super) {
5286 __extends(WebARSession, _super);
5287 /**
5288 * Emitted when session is started.
5289 * @event start
5290 * @category XR
5291 * @memberof WebARSession
5292 * @type void
5293 */
5294
5295 /**
5296 * Emitted when session is ended.
5297 * @event end
5298 * @category XR
5299 * @memberof WebARSession
5300 * @type void
5301 */
5302
5303 /**
5304 * Emitted when model can be placed on the space.
5305 * @event canPlace
5306 * @category XR
5307 * @memberof WebARSession
5308 * @type void
5309 */
5310
5311 /**
5312 * Emitted when model is placed.
5313 * @event modelPlaced
5314 * @category XR
5315 * @memberof WebARSession
5316 * @type void
5317 */
5318
5319 /**
5320 * Create new instance of WebARSession
5321 * @param {object} [options={}] Options
5322 * @param {object} [options.features={}] You can set additional features(see {@link https://developer.mozilla.org/en-US/docs/Web/API/XRSessionInit XRSessionInit}) with this option.
5323 * @param {number} [options.maxModelSize=Infinity] If model's size is too big to show on AR, you can restrict it's size with this option. Model with size bigger than this value will clamped to this value.
5324 * @param {HTMLElement|string|null} [options.overlayRoot=null] If this value is set, dom-overlay feature will be automatically added for this session. And this value will be used as dom-overlay's root element. You can set either HTMLElement or query selector for that element.
5325 * @param {HTMLElement|string|null} [options.loadingEl=null] This will be used for loading indicator element, which will automatically invisible after placing 3D model by setting `visibility: hidden`. This element must be placed under `overlayRoot`. You can set either HTMLElement or query selector for that element.
5326 * @param {boolean} [options.forceOverlay=false] Whether to apply `dom-overlay` feature as required. If set to false, `dom-overlay` will be optional feature.
5327 */
5328
5329
5330 function WebARSession(_a) {
5331 var _b = _a === void 0 ? {} : _a,
5332 _c = _b.features,
5333 userFeatures = _c === void 0 ? EMPTY_FEATURES : _c,
5334 // https://developer.mozilla.org/en-US/docs/Web/API/XRSessionInit
5335 _d = _b.maxModelSize,
5336 // https://developer.mozilla.org/en-US/docs/Web/API/XRSessionInit
5337 maxModelSize = _d === void 0 ? Infinity : _d,
5338 _e = _b.overlayRoot,
5339 overlayRoot = _e === void 0 ? NULL_ELEMENT : _e,
5340 _f = _b.loadingEl,
5341 loadingEl = _f === void 0 ? NULL_ELEMENT : _f,
5342 _g = _b.forceOverlay,
5343 forceOverlay = _g === void 0 ? false : _g;
5344
5345 var _this = _super.call(this) || this;
5346 /**
5347 * Whether it's webxr-based session or not
5348 * @type true
5349 */
5350
5351
5352 _this.isWebXRSession = true;
5353 _this._session = null;
5354 _this._domOverlay = null;
5355 var overlayEl = getElement(overlayRoot);
5356 var features = [];
5357
5358 if (overlayEl) {
5359 _this._domOverlay = new DOMOverlay({
5360 root: overlayEl,
5361 loadingEl: getElement(loadingEl, overlayEl)
5362 });
5363 features.push(_this._domOverlay.features);
5364 }
5365
5366 _this._features = merge.apply(void 0, __spread([{}], features, [userFeatures]));
5367 _this._maxModelSize = maxModelSize;
5368 _this._forceOverlay = forceOverlay;
5369 return _this;
5370 }
5371
5372 var __proto = WebARSession.prototype;
5373 Object.defineProperty(__proto, "session", {
5374 /**
5375 * {@link https://developer.mozilla.org/en-US/docs/Web/API/XRSession XRSession} of this session
5376 * This value is only available after calling enter
5377 */
5378 get: function () {
5379 return this._session;
5380 },
5381 enumerable: false,
5382 configurable: true
5383 });
5384 Object.defineProperty(__proto, "features", {
5385 /**
5386 * {@link https://developer.mozilla.org/en-US/docs/Web/API/XRSessionInit XRSessionInit} object for this session.
5387 */
5388 get: function () {
5389 return this._features;
5390 },
5391 enumerable: false,
5392 configurable: true
5393 });
5394 /**
5395 * Return availability of this session
5396 * @returns {Promise} A Promise that resolves availability of this session(boolean).
5397 */
5398
5399 __proto.isAvailable = function () {
5400 var domOverlay = this._domOverlay;
5401 if (!WEBXR_SUPPORTED || !HIT_TEST_SUPPORTED) return Promise.resolve(false);
5402
5403 if (this._forceOverlay) {
5404 if (domOverlay && !domOverlay.isAvailable()) return Promise.resolve(false);
5405 }
5406
5407 return navigator.xr.isSessionSupported(SESSION.AR);
5408 };
5409 /**
5410 * Enter session
5411 * @param view3d Instance of the View3D
5412 * @returns {Promise}
5413 */
5414
5415
5416 __proto.enter = function (view3d) {
5417 var _this = this; // Model not loaded yet
5418
5419
5420 if (!view3d.model) return Promise.reject("3D Model is not loaded");
5421 var model = view3d.model;
5422 return navigator.xr.requestSession(SESSION.AR, this._features).then(function (session) {
5423 var renderer = view3d.renderer;
5424 var threeRenderer = renderer.threeRenderer;
5425 var xrContext = {
5426 view3d: view3d,
5427 model: model,
5428 session: session
5429 }; // Cache original values
5430
5431 var originalMatrix = model.scene.matrix.clone();
5432 var originalModelSize = model.size;
5433 var originalBackground = view3d.scene.root.background;
5434 var arModelSize = Math.min(model.originalSize, _this._maxModelSize);
5435 model.size = arModelSize;
5436 model.moveToOrigin();
5437 view3d.scene.setBackground(null); // Cache original model rotation
5438
5439 threeRenderer.xr.setReferenceSpaceType(REFERENCE_SPACE.LOCAL);
5440 threeRenderer.xr.setSession(session);
5441 threeRenderer.setPixelRatio(1);
5442
5443 _this.onStart(xrContext);
5444
5445 session.addEventListener("end", function () {
5446 _this.onEnd(xrContext); // Restore original values
5447
5448
5449 model.scene.matrix.copy(originalMatrix);
5450 model.scene.matrix.decompose(model.scene.position, model.scene.quaternion, model.scene.scale);
5451 model.size = originalModelSize;
5452 model.moveToOrigin();
5453 view3d.scene.update(model);
5454 view3d.scene.setBackground(originalBackground); // Restore renderer values
5455
5456 threeRenderer.xr.setSession(null);
5457 threeRenderer.setPixelRatio(window.devicePixelRatio); // Restore render loop
5458
5459 renderer.stopAnimationLoop();
5460 renderer.setAnimationLoop(view3d.renderLoop);
5461 }, {
5462 once: true
5463 }); // Set XR session render loop
5464
5465 renderer.stopAnimationLoop();
5466 renderer.setAnimationLoop(function (delta, frame) {
5467 var xrCam = threeRenderer.xr.getCamera(new THREE.PerspectiveCamera());
5468 var referenceSpace = threeRenderer.xr.getReferenceSpace();
5469 var glLayer = session.renderState.baseLayer;
5470 var size = {
5471 width: glLayer.framebufferWidth,
5472 height: glLayer.framebufferHeight
5473 };
5474
5475 var renderContext = __assign(__assign({}, xrContext), {
5476 delta: delta,
5477 frame: frame,
5478 referenceSpace: referenceSpace,
5479 xrCam: xrCam,
5480 size: size
5481 });
5482
5483 _this._beforeRender(renderContext);
5484
5485 view3d.renderLoop(delta);
5486 });
5487 });
5488 };
5489 /**
5490 * Exit this session
5491 * @param view3d Instance of the View3D
5492 */
5493
5494
5495 __proto.exit = function (view3d) {
5496 var session = view3d.renderer.threeRenderer.xr.getSession();
5497 session.end();
5498 };
5499
5500 __proto.onStart = function (ctx) {
5501 var _a;
5502
5503 this._session = ctx.session;
5504 (_a = this._domOverlay) === null || _a === void 0 ? void 0 : _a.showLoading();
5505 this.emit("start");
5506 };
5507
5508 __proto.onEnd = function (ctx) {
5509 var _a;
5510
5511 this._session = null;
5512 (_a = this._domOverlay) === null || _a === void 0 ? void 0 : _a.hideLoading();
5513 this.emit("end");
5514 };
5515
5516 return WebARSession;
5517 }(EventEmitter);
5518
5519 /*
5520 * Copyright (c) 2020 NAVER Corp.
5521 * egjs projects are licensed under the MIT license
5522 */
5523 /**
5524 * Manager for WebXR hit-test feature
5525 * @category XR
5526 */
5527
5528 var HitTest =
5529 /*#__PURE__*/
5530 function () {
5531 function HitTest() {
5532 this._source = null;
5533 }
5534
5535 var __proto = HitTest.prototype;
5536 Object.defineProperty(__proto, "ready", {
5537 /**
5538 * Return whether hit-test is ready
5539 */
5540 get: function () {
5541 return this._source != null;
5542 },
5543 enumerable: false,
5544 configurable: true
5545 });
5546 Object.defineProperty(__proto, "features", {
5547 /**
5548 * {@link https://developer.mozilla.org/en-US/docs/Web/API/XRSessionInit XRSessionInit} object for hit-test feature
5549 */
5550 get: function () {
5551 return FEATURES.HIT_TEST;
5552 },
5553 enumerable: false,
5554 configurable: true
5555 });
5556 /**
5557 * Destroy instance
5558 */
5559
5560 __proto.destroy = function () {
5561 if (this._source) {
5562 this._source.cancel();
5563
5564 this._source = null;
5565 }
5566 };
5567 /**
5568 * Initialize hit-test feature
5569 * @param {XRSession} session XRSession instance
5570 */
5571
5572
5573 __proto.init = function (session) {
5574 var _this = this;
5575
5576 session.requestReferenceSpace(REFERENCE_SPACE.VIEWER).then(function (referenceSpace) {
5577 session.requestHitTestSource({
5578 space: referenceSpace
5579 }).then(function (source) {
5580 _this._source = source;
5581 });
5582 });
5583 };
5584 /**
5585 * Return whether hit-test feature is available
5586 */
5587
5588
5589 __proto.isAvailable = function () {
5590 return HIT_TEST_SUPPORTED;
5591 };
5592 /**
5593 * Get hit-test results
5594 * @param {XRFrame} frame XRFrame instance
5595 */
5596
5597
5598 __proto.getResults = function (frame) {
5599 return frame.getHitTestResults(this._source);
5600 };
5601
5602 return HitTest;
5603 }();
5604
5605 /*
5606 * Copyright (c) 2020 NAVER Corp.
5607 * egjs projects are licensed under the MIT license
5608 */
5609 /**
5610 * Fires for every animation frame when animation is active.
5611 * @type object
5612 * @property {object} event Event object.
5613 * @property {number} [event.progress] Current animation progress value.
5614 * Value is ranged from 0(start) to 1(end).
5615 * @property {number} [event.easedProgress] Eased progress value.
5616 * @event Animation#progress
5617 */
5618
5619 /**
5620 * Fires for every animation loop except for the last loop
5621 * This will be triggered only when repeat > 0
5622 * @type object
5623 * @property {object} event Event object.
5624 * @property {number} [event.progress] Current animation progress value.
5625 * Value is ranged from 0(start) to 1(end).
5626 * @property {number} [event.easedProgress] Eased progress value.
5627 * @property {number} [event.loopIndex] Index of the current loop.
5628 * @event Animation#loop
5629 */
5630
5631 /**
5632 * Fires when animation ends.
5633 * @type void
5634 * @event Animation#finish
5635 */
5636
5637 /**
5638 * Self-running animation
5639 * @category Core
5640 */
5641
5642 var Animation =
5643 /*#__PURE__*/
5644 function (_super) {
5645 __extends(Animation, _super);
5646 /**
5647 * Create new instance of the Animation
5648 * @param {object} [options={}] Options
5649 */
5650
5651
5652 function Animation(_a) {
5653 var _b = _a === void 0 ? {} : _a,
5654 _c = _b.context,
5655 context = _c === void 0 ? window : _c,
5656 _d = _b.repeat,
5657 repeat = _d === void 0 ? 0 : _d,
5658 _e = _b.duration,
5659 duration = _e === void 0 ? ANIMATION_DURATION : _e,
5660 _f = _b.easing,
5661 easing = _f === void 0 ? EASE_OUT_CUBIC : _f;
5662
5663 var _this = _super.call(this) || this;
5664
5665 _this._loop = function () {
5666 var delta = _this._getDeltaTime();
5667
5668 var duration = _this._duration;
5669 _this._time += delta;
5670 var loopIncrease = Math.floor(_this._time / duration);
5671 _this._time = circulate(_this._time, 0, duration);
5672 var progress = _this._time / duration;
5673 var progressEvent = {
5674 progress: progress,
5675 easedProgress: _this._easing(progress)
5676 };
5677
5678 _this.emit("progress", progressEvent);
5679
5680 for (var loopIdx = 0; loopIdx < loopIncrease; loopIdx++) {
5681 _this._loopCount++;
5682
5683 if (_this._loopCount > _this._repeat) {
5684 _this.emit("finish");
5685
5686 _this.stop();
5687
5688 return;
5689 } else {
5690 _this.emit("loop", __assign(__assign({}, progressEvent), {
5691 loopIndex: _this._loopCount
5692 }));
5693 }
5694 }
5695
5696 _this._rafId = _this._ctx.requestAnimationFrame(_this._loop);
5697 }; // Options
5698
5699
5700 _this._repeat = repeat;
5701 _this._duration = duration;
5702 _this._easing = easing; // Internal States
5703
5704 _this._ctx = context;
5705 _this._rafId = -1;
5706 _this._time = 0;
5707 _this._clock = 0;
5708 _this._loopCount = 0;
5709 return _this;
5710 }
5711
5712 var __proto = Animation.prototype;
5713
5714 __proto.start = function () {
5715 if (this._rafId >= 0) return; // This guarantees "progress" event with progress = 0 on first start
5716
5717 this._updateClock();
5718
5719 this._loop();
5720 };
5721
5722 __proto.stop = function () {
5723 if (this._rafId < 0) return;
5724 this._time = 0;
5725 this._loopCount = 0;
5726
5727 this._stopLoop();
5728 };
5729
5730 __proto.pause = function () {
5731 if (this._rafId < 0) return;
5732
5733 this._stopLoop();
5734 };
5735
5736 __proto._stopLoop = function () {
5737 this._ctx.cancelAnimationFrame(this._rafId);
5738
5739 this._rafId = -1;
5740 };
5741
5742 __proto._getDeltaTime = function () {
5743 var lastTime = this._clock;
5744
5745 this._updateClock();
5746
5747 return this._clock - lastTime;
5748 };
5749
5750 __proto._updateClock = function () {
5751 this._clock = Date.now();
5752 };
5753
5754 return Animation;
5755 }(EventEmitter);
5756
5757 /*
5758 * Copyright (c) 2020 NAVER Corp.
5759 * egjs projects are licensed under the MIT license
5760 */
5761 /**
5762 * Rotation indicator for ARHoverSession
5763 * @category Controls-AR
5764 */
5765
5766 var RotationIndicator =
5767 /*#__PURE__*/
5768 function () {
5769 /**
5770 * Create new RotationIndicator
5771 * @param {RotationIndicatorOption} [options={}] Options
5772 */
5773 function RotationIndicator(_a) {
5774 var _b = _a === void 0 ? {} : _a,
5775 _c = _b.ringColor,
5776 ringColor = _c === void 0 ? 0xffffff : _c,
5777 _d = _b.axisColor,
5778 axisColor = _d === void 0 ? 0xffffff : _d;
5779
5780 var ringGeometry = new THREE.RingGeometry(0.99, 1, 150, 1, 0, Math.PI * 2);
5781 var ringMaterial = new THREE.MeshBasicMaterial({
5782 color: ringColor,
5783 side: THREE.DoubleSide
5784 });
5785 this._ring = new THREE.Mesh(ringGeometry, ringMaterial);
5786 var axisVertices = [new THREE.Vector3(0, 0, -1000), new THREE.Vector3(0, 0, +1000)];
5787 var axisGeometry = new THREE.BufferGeometry().setFromPoints(axisVertices);
5788 var axisMaterial = new THREE.LineBasicMaterial({
5789 color: axisColor
5790 });
5791 this._axis = new THREE.Line(axisGeometry, axisMaterial);
5792 this._obj = new THREE.Group();
5793
5794 this._obj.add(this._ring);
5795
5796 this._obj.add(this._axis);
5797
5798 this.hide();
5799 }
5800
5801 var __proto = RotationIndicator.prototype;
5802 Object.defineProperty(__proto, "object", {
5803 /**
5804 * {@link https://threejs.org/docs/index.html#api/en/objects/Group THREE.Group} object that contains ring & axis.
5805 */
5806 get: function () {
5807 return this._obj;
5808 },
5809 enumerable: false,
5810 configurable: true
5811 });
5812 /**
5813 * Show indicator
5814 */
5815
5816 __proto.show = function () {
5817 this._obj.visible = true;
5818 };
5819 /**
5820 * Hide indicator
5821 */
5822
5823
5824 __proto.hide = function () {
5825 this._obj.visible = false;
5826 };
5827 /**
5828 * Change the position of the indicator
5829 * @param position New position
5830 */
5831
5832
5833 __proto.updatePosition = function (position) {
5834 this._obj.position.copy(position);
5835 };
5836 /**
5837 * Update scale of the ring
5838 * @param scale New scale
5839 */
5840
5841
5842 __proto.updateScale = function (scale) {
5843 this._ring.scale.setScalar(scale);
5844 };
5845 /**
5846 * Update indicator's rotation
5847 * @param rotation Quaternion value set as new rotation.
5848 */
5849
5850
5851 __proto.updateRotation = function (rotation) {
5852 this._obj.quaternion.copy(rotation);
5853 };
5854
5855 return RotationIndicator;
5856 }();
5857
5858 /*
5859 * Copyright (c) 2020 NAVER Corp.
5860 * egjs projects are licensed under the MIT license
5861 */
5862 /**
5863 * One finger swirl control on single axis
5864 * @category Controls-AR
5865 */
5866
5867 var ARSwirlControl =
5868 /*#__PURE__*/
5869 function () {
5870 /**
5871 * Create new ARSwirlControl
5872 * @param {ARSwirlControlOption} [options={}] Options
5873 */
5874 function ARSwirlControl(_a) {
5875 var _b = _a === void 0 ? {} : _a,
5876 _c = _b.scale,
5877 scale = _c === void 0 ? 1 : _c,
5878 _d = _b.showIndicator,
5879 showIndicator = _d === void 0 ? true : _d;
5880 /**
5881 * Current rotation value
5882 */
5883
5884
5885 this.rotation = new THREE.Quaternion(); // Internal States
5886
5887 this._axis = new THREE.Vector3(0, 1, 0);
5888 this._enabled = true;
5889 this._active = false;
5890 this._prevPos = new THREE.Vector2();
5891 this._fromQuat = new THREE.Quaternion();
5892 this._toQuat = new THREE.Quaternion();
5893 this._motion = new Motion({
5894 range: INFINITE_RANGE
5895 });
5896 this._userScale = scale;
5897
5898 if (showIndicator) {
5899 this._rotationIndicator = new RotationIndicator();
5900 }
5901 }
5902
5903 var __proto = ARSwirlControl.prototype;
5904 Object.defineProperty(__proto, "enabled", {
5905 /**
5906 * Whether this control is enabled or not.
5907 * @readonly
5908 */
5909 get: function () {
5910 return this._enabled;
5911 },
5912 enumerable: false,
5913 configurable: true
5914 });
5915 Object.defineProperty(__proto, "scale", {
5916 /**
5917 * Scale(speed) factor of this control.
5918 */
5919 get: function () {
5920 return this._userScale;
5921 },
5922 set: function (val) {
5923 this._userScale = val;
5924 },
5925 enumerable: false,
5926 configurable: true
5927 });
5928
5929 __proto.init = function (_a) {
5930 var view3d = _a.view3d;
5931 var initialRotation = view3d.model.scene.quaternion;
5932 this.updateRotation(initialRotation);
5933
5934 if (this._rotationIndicator) {
5935 view3d.scene.add(this._rotationIndicator.object);
5936 }
5937 };
5938
5939 __proto.destroy = function (_a) {
5940 var view3d = _a.view3d;
5941
5942 if (this._rotationIndicator) {
5943 view3d.scene.remove(this._rotationIndicator.object);
5944 }
5945 };
5946
5947 __proto.updateRotation = function (rotation) {
5948 this.rotation.copy(rotation);
5949
5950 this._fromQuat.copy(rotation);
5951
5952 this._toQuat.copy(rotation);
5953 };
5954 /**
5955 * Enable this control
5956 */
5957
5958
5959 __proto.enable = function () {
5960 this._enabled = true;
5961 };
5962 /**
5963 * Disable this control
5964 */
5965
5966
5967 __proto.disable = function () {
5968 this._enabled = false;
5969 };
5970
5971 __proto.activate = function (_a, gesture) {
5972 var view3d = _a.view3d;
5973 if (!this._enabled) return;
5974 this._active = true;
5975 var model = view3d.model;
5976 var rotationIndicator = this._rotationIndicator;
5977
5978 if (rotationIndicator) {
5979 rotationIndicator.show();
5980 rotationIndicator.updatePosition(model.bbox.getCenter(new THREE.Vector3()));
5981 rotationIndicator.updateScale(model.size / 2);
5982 rotationIndicator.updateRotation(model.scene.quaternion);
5983 }
5984 };
5985
5986 __proto.deactivate = function () {
5987 this._active = false;
5988
5989 if (this._rotationIndicator) {
5990 this._rotationIndicator.hide();
5991 }
5992 };
5993
5994 __proto.updateAxis = function (axis) {
5995 this._axis.copy(axis);
5996 };
5997
5998 __proto.setInitialPos = function (coords) {
5999 this._prevPos.copy(coords[0]);
6000 };
6001
6002 __proto.process = function (_a, _b) {
6003 var view3d = _a.view3d,
6004 xrCam = _a.xrCam;
6005 var coords = _b.coords;
6006 if (!this._active || coords.length !== 1) return;
6007 var prevPos = this._prevPos;
6008 var motion = this._motion;
6009 var model = view3d.model;
6010 var coord = coords[0];
6011 var modelPos = model.scene.position.clone();
6012 var ndcModelPos = new THREE.Vector2().fromArray(modelPos.project(xrCam).toArray()); // Get the rotation angle with the model's NDC coordinates as the center.
6013
6014 var rotationAngle = getRotationAngle(ndcModelPos, prevPos, coord) * this._userScale;
6015
6016 var rotation = new THREE.Quaternion().setFromAxisAngle(this._axis, rotationAngle);
6017
6018 var interpolated = this._getInterpolatedQuaternion();
6019
6020 this._fromQuat.copy(interpolated);
6021
6022 this._toQuat.premultiply(rotation);
6023
6024 motion.reset(0);
6025 motion.setEndDelta(1);
6026 prevPos.copy(coord);
6027 };
6028
6029 __proto.update = function (_a, deltaTime) {
6030 var model = _a.model;
6031 if (!this._active) return;
6032 var motion = this._motion;
6033 motion.update(deltaTime);
6034
6035 var interpolated = this._getInterpolatedQuaternion();
6036
6037 this.rotation.copy(interpolated);
6038 model.scene.quaternion.copy(interpolated);
6039 };
6040
6041 __proto._getInterpolatedQuaternion = function () {
6042 var motion = this._motion;
6043 var toEuler = this._toQuat;
6044 var fromEuler = this._fromQuat;
6045 var progress = motion.val;
6046 return new THREE.Quaternion().copy(fromEuler).slerp(toEuler, progress);
6047 };
6048
6049 return ARSwirlControl;
6050 }();
6051
6052 /*
6053 * Copyright (c) 2020 NAVER Corp.
6054 * egjs projects are licensed under the MIT license
6055 */
6056 var STATE;
6057
6058 (function (STATE) {
6059 STATE[STATE["WAITING"] = 0] = "WAITING";
6060 STATE[STATE["TRANSLATING"] = 1] = "TRANSLATING";
6061 STATE[STATE["BOUNCING"] = 2] = "BOUNCING";
6062 })(STATE || (STATE = {}));
6063 /**
6064 * Model's translation(position) control for {@link ARFloorControl}
6065 * @category Controls-AR
6066 */
6067
6068
6069 var ARFloorTranslateControl =
6070 /*#__PURE__*/
6071 function () {
6072 /**
6073 * Create new instance of ARTranslateControl
6074 * @param {ARFloorTranslateControlOption} [options={}] Options
6075 */
6076 function ARFloorTranslateControl(_a) {
6077 var _b = _a === void 0 ? {} : _a,
6078 _c = _b.hoverAmplitude,
6079 hoverAmplitude = _c === void 0 ? 0.01 : _c,
6080 _d = _b.hoverHeight,
6081 hoverHeight = _d === void 0 ? 0.1 : _d,
6082 _e = _b.hoverPeriod,
6083 hoverPeriod = _e === void 0 ? 1000 : _e,
6084 _f = _b.hoverEasing,
6085 hoverEasing = _f === void 0 ? SINE_WAVE : _f,
6086 _g = _b.bounceDuration,
6087 bounceDuration = _g === void 0 ? 1000 : _g,
6088 _h = _b.bounceEasing,
6089 bounceEasing = _h === void 0 ? EASE_OUT_BOUNCE : _h; // Internal states
6090
6091
6092 this._modelPosition = new THREE.Vector3();
6093 this._hoverPosition = new THREE.Vector3();
6094 this._floorPosition = new THREE.Vector3();
6095 this._dragPlane = new THREE.Plane();
6096 this._enabled = true;
6097 this._state = STATE.WAITING;
6098 this._initialPos = new THREE.Vector2();
6099 this._hoverAmplitude = hoverAmplitude;
6100 this._hoverHeight = hoverHeight;
6101 this._hoverMotion = new Motion({
6102 loop: true,
6103 duration: hoverPeriod,
6104 easing: hoverEasing
6105 });
6106 this._bounceMotion = new Motion({
6107 duration: bounceDuration,
6108 easing: bounceEasing,
6109 range: INFINITE_RANGE
6110 });
6111 }
6112
6113 var __proto = ARFloorTranslateControl.prototype;
6114 Object.defineProperty(__proto, "enabled", {
6115 /**
6116 * Whether this control is enabled or not
6117 * @readonly
6118 */
6119 get: function () {
6120 return this._enabled;
6121 },
6122 enumerable: false,
6123 configurable: true
6124 });
6125 Object.defineProperty(__proto, "modelPosition", {
6126 /**
6127 * Position including hover/bounce animation offset from the floor.
6128 * @readonly
6129 */
6130 get: function () {
6131 return this._modelPosition.clone();
6132 },
6133 enumerable: false,
6134 configurable: true
6135 });
6136 Object.defineProperty(__proto, "floorPosition", {
6137 /**
6138 * Last detected floor position
6139 * @readonly
6140 */
6141 get: function () {
6142 return this._floorPosition.clone();
6143 },
6144 enumerable: false,
6145 configurable: true
6146 });
6147 Object.defineProperty(__proto, "hoverAmplitude", {
6148 /**
6149 * How much model will hover up and down, in meter.
6150 */
6151 get: function () {
6152 return this._hoverAmplitude;
6153 },
6154 set: function (val) {
6155 this._hoverAmplitude = val;
6156 },
6157 enumerable: false,
6158 configurable: true
6159 });
6160 Object.defineProperty(__proto, "hoverHeight", {
6161 /**
6162 * How much model will float from the floor, in meter.
6163 */
6164 get: function () {
6165 return this._hoverHeight;
6166 },
6167 set: function (val) {
6168 this._hoverHeight = val;
6169 },
6170 enumerable: false,
6171 configurable: true
6172 });
6173
6174 __proto.initFloorPosition = function (position) {
6175 this._modelPosition.copy(position);
6176
6177 this._floorPosition.copy(position);
6178
6179 this._hoverPosition.copy(position);
6180
6181 this._hoverPosition.setY(position.y + this._hoverHeight);
6182 }; // tslint:disable-next-line no-empty
6183
6184
6185 __proto.init = function (ctx) {}; // tslint:disable-next-line no-empty
6186
6187
6188 __proto.destroy = function (ctx) {};
6189 /**
6190 * Enable this control
6191 */
6192
6193
6194 __proto.enable = function () {
6195 this._enabled = true;
6196 };
6197 /**
6198 * Disable this control
6199 */
6200
6201
6202 __proto.disable = function () {
6203 this._enabled = false;
6204 this.deactivate();
6205 };
6206
6207 __proto.activate = function (_a, gesture) {
6208 var model = _a.model;
6209 if (!this._enabled) return;
6210 var modelBbox = model.bbox;
6211 var modelBboxYOffset = modelBbox.getCenter(new THREE.Vector3()).y - modelBbox.min.y;
6212
6213 this._dragPlane.set(new THREE.Vector3(0, 1, 0), -(this._floorPosition.y + this._hoverHeight + modelBboxYOffset));
6214
6215 this._hoverMotion.reset(0);
6216
6217 this._hoverMotion.setEndDelta(1);
6218
6219 this._state = STATE.TRANSLATING;
6220 };
6221
6222 __proto.deactivate = function () {
6223 if (!this._enabled || this._state === STATE.WAITING) {
6224 this._state = STATE.WAITING;
6225 return;
6226 }
6227
6228 this._state = STATE.BOUNCING;
6229 var floorPosition = this._floorPosition;
6230 var modelPosition = this._modelPosition;
6231 var hoverPosition = this._hoverPosition;
6232 var bounceMotion = this._bounceMotion;
6233 var hoveringAmount = modelPosition.y - floorPosition.y;
6234 bounceMotion.reset(modelPosition.y);
6235 bounceMotion.setEndDelta(-hoveringAmount); // Restore hover pos
6236
6237 hoverPosition.copy(floorPosition);
6238 hoverPosition.setY(floorPosition.y + this._hoverHeight);
6239 };
6240
6241 __proto.setInitialPos = function (coords) {
6242 this._initialPos.copy(coords[0]);
6243 };
6244
6245 __proto.process = function (_a, _b) {
6246 var view3d = _a.view3d,
6247 model = _a.model,
6248 frame = _a.frame,
6249 referenceSpace = _a.referenceSpace,
6250 xrCam = _a.xrCam;
6251 var hitResults = _b.hitResults;
6252 var state = this._state;
6253 var notActive = state === STATE.WAITING || state === STATE.BOUNCING;
6254 if (!hitResults || hitResults.length !== 1 || notActive) return;
6255 var hitResult = hitResults[0];
6256
6257 var prevFloorPosition = this._floorPosition.clone();
6258
6259 var floorPosition = this._floorPosition;
6260 var hoverPosition = this._hoverPosition;
6261 var hoverHeight = this._hoverHeight;
6262 var dragPlane = this._dragPlane;
6263 var modelBbox = model.bbox;
6264 var modelBboxYOffset = modelBbox.getCenter(new THREE.Vector3()).y - modelBbox.min.y;
6265 var hitPose = hitResult.results[0] && hitResult.results[0].getPose(referenceSpace);
6266 var isFloorHit = hitPose && hitPose.transform.matrix[5] >= 0.75;
6267 var camPos = new THREE.Vector3().setFromMatrixPosition(xrCam.matrixWorld);
6268
6269 if (!hitPose || !isFloorHit) {
6270 // Use previous drag plane if no hit plane is found
6271 var targetRayPose = frame.getPose(hitResult.inputSource.targetRaySpace, view3d.renderer.threeRenderer.xr.getReferenceSpace());
6272 var fingerDir = new THREE.Vector3().copy(targetRayPose.transform.position).sub(camPos).normalize();
6273 var fingerRay = new THREE.Ray(camPos, fingerDir);
6274 var intersection = fingerRay.intersectPlane(dragPlane, new THREE.Vector3());
6275
6276 if (intersection) {
6277 floorPosition.copy(intersection);
6278 floorPosition.setY(prevFloorPosition.y);
6279 hoverPosition.copy(intersection);
6280 hoverPosition.setY(intersection.y - modelBboxYOffset);
6281 }
6282
6283 return;
6284 }
6285
6286 var hitMatrix = new THREE.Matrix4().fromArray(hitPose.transform.matrix);
6287 var hitPosition = new THREE.Vector3().setFromMatrixPosition(hitMatrix); // Set new floor level when it's increased at least 10cm
6288
6289 var currentDragPlaneHeight = -dragPlane.constant;
6290 var hitDragPlaneHeight = hitPosition.y + hoverHeight + modelBboxYOffset;
6291
6292 if (hitDragPlaneHeight - currentDragPlaneHeight > 0.1) {
6293 dragPlane.constant = -hitDragPlaneHeight;
6294 }
6295
6296 var camToHitDir = new THREE.Vector3().subVectors(hitPosition, camPos).normalize();
6297 var camToHitRay = new THREE.Ray(camPos, camToHitDir);
6298 var hitOnDragPlane = camToHitRay.intersectPlane(dragPlane, new THREE.Vector3());
6299 if (!hitOnDragPlane) return;
6300 floorPosition.copy(hitOnDragPlane);
6301 floorPosition.setY(hitPosition.y);
6302 hoverPosition.copy(hitOnDragPlane);
6303 hoverPosition.setY(hitOnDragPlane.y - modelBboxYOffset);
6304 };
6305
6306 __proto.update = function (_a, delta) {
6307 var model = _a.model;
6308 var state = this._state;
6309 var modelPosition = this._modelPosition;
6310 var hoverPosition = this._hoverPosition;
6311 if (state === STATE.WAITING) return;
6312
6313 if (state !== STATE.BOUNCING) {
6314 // Hover
6315 var hoverMotion = this._hoverMotion;
6316 hoverMotion.update(delta); // Change only x, y component of position
6317
6318 var hoverOffset = hoverMotion.val * this._hoverAmplitude;
6319 modelPosition.copy(hoverPosition);
6320 modelPosition.setY(hoverPosition.y + hoverOffset);
6321 } else {
6322 // Bounce
6323 var bounceMotion = this._bounceMotion;
6324 bounceMotion.update(delta);
6325 modelPosition.setY(bounceMotion.val);
6326
6327 if (bounceMotion.progress >= 1) {
6328 this._state = STATE.WAITING;
6329 }
6330 }
6331
6332 var modelBbox = model.bbox;
6333 var modelYOffset = modelBbox.getCenter(new THREE.Vector3()).y - modelBbox.min.y; // modelPosition = where model.bbox.min.y should be
6334
6335 model.scene.position.copy(modelPosition.clone().setY(modelPosition.y + modelYOffset));
6336 };
6337
6338 return ARFloorTranslateControl;
6339 }();
6340
6341 /*
6342 * Copyright (c) 2020 NAVER Corp.
6343 * egjs projects are licensed under the MIT license
6344 */
6345 /**
6346 * UI element displaying model's scale percentage info when user chaning model's scale.
6347 * @category Controls-AR
6348 */
6349
6350 var ScaleUI =
6351 /*#__PURE__*/
6352 function () {
6353 /**
6354 * Create new instance of ScaleUI
6355 * @param {ScaleUIOption} [options={}] Options
6356 */
6357 function ScaleUI(_a) {
6358 var _b = _a === void 0 ? {} : _a,
6359 _c = _b.width,
6360 width = _c === void 0 ? 0.1 : _c,
6361 _d = _b.padding,
6362 padding = _d === void 0 ? 20 : _d,
6363 _e = _b.offset,
6364 offset = _e === void 0 ? 0.05 : _e,
6365 _f = _b.font,
6366 font = _f === void 0 ? "64px sans-serif" : _f,
6367 _g = _b.color,
6368 color = _g === void 0 ? "white" : _g;
6369
6370 var canvas = document.createElement("canvas");
6371 var ctx = canvas.getContext("2d");
6372 ctx.font = font; // Maximum canvas width should be equal to this
6373
6374 var maxText = ctx.measureText("100%"); // Following APIs won't work on IE, but it's WebXR so I think it's okay
6375
6376 var maxWidth = maxText.actualBoundingBoxLeft + maxText.actualBoundingBoxRight;
6377 var maxHeight = maxText.actualBoundingBoxAscent + maxText.actualBoundingBoxDescent;
6378 var widthPowerOfTwo = toPowerOfTwo(maxWidth);
6379 canvas.width = widthPowerOfTwo;
6380 canvas.height = widthPowerOfTwo; // This considers increased amount by making width to power of two
6381
6382 var planeWidth = width * (widthPowerOfTwo / maxWidth);
6383 this._ctx = ctx;
6384 this._canvas = canvas;
6385 this._height = planeWidth * maxHeight / maxWidth; // Text height inside plane
6386
6387 this._texture = new THREE.CanvasTexture(canvas); // Plane is square
6388
6389 var uiGeometry = new THREE.PlaneGeometry(planeWidth, planeWidth);
6390 var mesh = new THREE.Mesh(uiGeometry, new THREE.MeshBasicMaterial({
6391 map: this._texture,
6392 transparent: true
6393 }));
6394 mesh.matrixAutoUpdate = false;
6395 this._mesh = mesh;
6396 this._font = font;
6397 this._color = color;
6398 this._padding = padding;
6399 this._offset = offset;
6400 }
6401
6402 var __proto = ScaleUI.prototype;
6403 Object.defineProperty(__proto, "mesh", {
6404 /**
6405 * Scale UI's plane mesh
6406 * @readonly
6407 */
6408 get: function () {
6409 return this._mesh;
6410 },
6411 enumerable: false,
6412 configurable: true
6413 });
6414 Object.defineProperty(__proto, "height", {
6415 /**
6416 * Scale UI's height value
6417 * @readonly
6418 */
6419 get: function () {
6420 return this._height;
6421 },
6422 enumerable: false,
6423 configurable: true
6424 });
6425 Object.defineProperty(__proto, "visible", {
6426 /**
6427 * Whether UI is visible or not.
6428 * @readonly
6429 */
6430 get: function () {
6431 return this._mesh.visible;
6432 },
6433 enumerable: false,
6434 configurable: true
6435 });
6436
6437 __proto.updatePosition = function (position, focus) {
6438 // Update mesh
6439 var mesh = this._mesh;
6440 mesh.lookAt(focus);
6441 mesh.position.copy(position);
6442 mesh.position.setY(position.y + this._height / 2 + this._offset);
6443 mesh.updateMatrix();
6444 };
6445
6446 __proto.updateScale = function (scale) {
6447 var ctx = this._ctx;
6448 var canvas = this._canvas;
6449 var padding = this._padding;
6450 var scalePercentage = (scale * 100).toFixed(0);
6451 ctx.clearRect(0, 0, canvas.width, canvas.height);
6452 var centerX = canvas.width / 2;
6453 var centerY = canvas.height / 2; // Draw round rect
6454
6455 var textSize = ctx.measureText(scalePercentage + "%");
6456 var halfWidth = (textSize.actualBoundingBoxLeft + textSize.actualBoundingBoxRight) / 2;
6457 var halfHeight = (textSize.actualBoundingBoxAscent + textSize.actualBoundingBoxDescent) / 2;
6458 ctx.beginPath();
6459 ctx.moveTo(centerX - halfWidth, centerY - halfHeight - padding);
6460 ctx.lineTo(centerX + halfWidth, centerY - halfHeight - padding);
6461 ctx.quadraticCurveTo(centerX + halfWidth + padding, centerY - halfHeight - padding, centerX + halfWidth + padding, centerY - halfHeight);
6462 ctx.lineTo(centerX + halfWidth + padding, centerY + halfHeight);
6463 ctx.quadraticCurveTo(centerX + halfWidth + padding, centerY + halfHeight + padding, centerX + halfWidth, centerY + halfHeight + padding);
6464 ctx.lineTo(centerX - halfWidth, centerY + halfHeight + padding);
6465 ctx.quadraticCurveTo(centerX - halfWidth - padding, centerY + halfHeight + padding, centerX - halfWidth - padding, centerY + halfHeight);
6466 ctx.lineTo(centerX - halfWidth - padding, centerY - halfHeight);
6467 ctx.quadraticCurveTo(centerX - halfWidth - padding, centerY - halfHeight - padding, centerX - halfWidth, centerY - halfHeight - padding);
6468 ctx.closePath();
6469 ctx.lineWidth = 5;
6470 ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
6471 ctx.fill();
6472 ctx.stroke(); // Draw text
6473
6474 ctx.font = this._font;
6475 ctx.textAlign = "center";
6476 ctx.textBaseline = "middle";
6477 ctx.strokeStyle = this._color;
6478 ctx.fillStyle = this._color;
6479 ctx.fillText(scalePercentage + "%", centerX, centerY);
6480 this._texture.needsUpdate = true;
6481 };
6482 /**
6483 * Show UI
6484 */
6485
6486
6487 __proto.show = function () {
6488 this._mesh.visible = true;
6489 };
6490 /**
6491 * Hide UI
6492 */
6493
6494
6495 __proto.hide = function () {
6496 this._mesh.visible = false;
6497 };
6498
6499 return ScaleUI;
6500 }();
6501
6502 /*
6503 * Copyright (c) 2020 NAVER Corp.
6504 * egjs projects are licensed under the MIT license
6505 */
6506 /**
6507 * Model's scale controller which works on AR(WebXR) mode.
6508 * @category Controls-AR
6509 */
6510
6511 var ARScaleControl =
6512 /*#__PURE__*/
6513 function () {
6514 /**
6515 * Create new instance of ARScaleControl
6516 * @param {ARScaleControlOption} [options={}] Options
6517 */
6518 function ARScaleControl(_a) {
6519 var _b = _a === void 0 ? {} : _a,
6520 _c = _b.min,
6521 min = _c === void 0 ? 0.05 : _c,
6522 _d = _b.max,
6523 max = _d === void 0 ? 2 : _d;
6524
6525 this._enabled = true;
6526 this._active = false;
6527 this._prevCoordDistance = -1;
6528 this._scaleMultiplier = 1;
6529 this._initialScale = new THREE.Vector3();
6530 this._ui = new ScaleUI();
6531 this._motion = new Motion({
6532 duration: 0,
6533 range: {
6534 min: min,
6535 max: max
6536 }
6537 });
6538
6539 this._motion.reset(1); // default scale is 1(100%)
6540
6541
6542 this._ui = new ScaleUI();
6543 }
6544
6545 var __proto = ARScaleControl.prototype;
6546 Object.defineProperty(__proto, "enabled", {
6547 /**
6548 * Whether this control is enabled or not
6549 * @readonly
6550 */
6551 get: function () {
6552 return this._enabled;
6553 },
6554 enumerable: false,
6555 configurable: true
6556 });
6557 Object.defineProperty(__proto, "scale", {
6558 get: function () {
6559 return this._initialScale.clone().multiplyScalar(this._scaleMultiplier);
6560 },
6561 enumerable: false,
6562 configurable: true
6563 });
6564 Object.defineProperty(__proto, "scaleMultiplier", {
6565 get: function () {
6566 return this._scaleMultiplier;
6567 },
6568 enumerable: false,
6569 configurable: true
6570 });
6571 Object.defineProperty(__proto, "range", {
6572 /**
6573 * Range of the scale
6574 * @readonly
6575 */
6576 get: function () {
6577 return this._motion.range;
6578 },
6579 enumerable: false,
6580 configurable: true
6581 });
6582
6583 __proto.init = function (_a) {
6584 var view3d = _a.view3d;
6585
6586 this._initialScale.copy(view3d.model.scene.scale);
6587
6588 view3d.scene.add(this._ui.mesh);
6589 };
6590
6591 __proto.destroy = function (_a) {
6592 var view3d = _a.view3d;
6593 view3d.scene.remove(this._ui.mesh);
6594 };
6595
6596 __proto.setInitialPos = function (coords) {
6597 this._prevCoordDistance = new THREE.Vector2().subVectors(coords[0], coords[1]).length();
6598 };
6599 /**
6600 * Enable this control
6601 */
6602
6603
6604 __proto.enable = function () {
6605 this._enabled = true;
6606 };
6607 /**
6608 * Disable this control
6609 */
6610
6611
6612 __proto.disable = function () {
6613 this._enabled = false;
6614 this.deactivate();
6615 };
6616
6617 __proto.activate = function (ctx, gesture) {
6618 this._active = true;
6619
6620 this._ui.show();
6621
6622 this._updateUIPosition(ctx);
6623 };
6624
6625 __proto.deactivate = function () {
6626 this._active = false;
6627
6628 this._ui.hide();
6629
6630 this._prevCoordDistance = -1;
6631 };
6632 /**
6633 * Update scale range
6634 * @param min Minimum scale
6635 * @param max Maximum scale
6636 */
6637
6638
6639 __proto.setRange = function (min, max) {
6640 this._motion.range = {
6641 min: min,
6642 max: max
6643 };
6644 };
6645
6646 __proto.process = function (ctx, _a) {
6647 var coords = _a.coords;
6648 if (coords.length !== 2 || !this._enabled || !this._active) return;
6649 var motion = this._motion;
6650 var distance = new THREE.Vector2().subVectors(coords[0], coords[1]).length();
6651 var delta = distance - this._prevCoordDistance;
6652 motion.setEndDelta(delta);
6653 this._prevCoordDistance = distance;
6654
6655 this._updateUIPosition(ctx);
6656 };
6657
6658 __proto.update = function (_a, deltaTime) {
6659 var model = _a.model;
6660 if (!this._enabled || !this._active) return;
6661 var motion = this._motion;
6662 motion.update(deltaTime);
6663 this._scaleMultiplier = motion.val;
6664
6665 this._ui.updateScale(this._scaleMultiplier);
6666
6667 model.scene.scale.copy(this.scale);
6668 };
6669
6670 __proto._updateUIPosition = function (_a) {
6671 var view3d = _a.view3d,
6672 xrCam = _a.xrCam; // Update UI
6673
6674 var model = view3d.model;
6675 var camPos = new THREE.Vector3().setFromMatrixPosition(xrCam.matrixWorld);
6676 var uiPos = model.scene.position.clone().setY(model.bbox.max.y);
6677
6678 this._ui.updatePosition(uiPos, camPos);
6679 };
6680
6681 return ARScaleControl;
6682 }();
6683
6684 /*
6685 * Copyright (c) 2020 NAVER Corp.
6686 * egjs projects are licensed under the MIT license
6687 */
6688 /**
6689 * Ring type indicator for showing where the model's at.
6690 * @category Controls-AR
6691 */
6692
6693 var FloorIndicator =
6694 /*#__PURE__*/
6695 function () {
6696 /**
6697 * Create new instance of FloorIndicator
6698 * @param {FloorIndicatorOption} [options={}] Options
6699 */
6700 function FloorIndicator(_a) {
6701 var _b = _a === void 0 ? {} : _a,
6702 _c = _b.ringOpacity,
6703 ringOpacity = _c === void 0 ? 0.3 : _c,
6704 _d = _b.dirIndicatorOpacity,
6705 dirIndicatorOpacity = _d === void 0 ? 1 : _d,
6706 _e = _b.fadeoutDuration,
6707 fadeoutDuration = _e === void 0 ? 1000 : _e;
6708
6709 var deg10 = Math.PI / 18;
6710 var dimmedRingGeomtry = new THREE.RingGeometry(0.975, 1, 150, 1, -6 * deg10, 30 * deg10);
6711 var reticle = new THREE.CircleGeometry(0.1, 30, 0, Math.PI * 2);
6712 dimmedRingGeomtry.merge(reticle);
6713 var highlightedRingGeometry = new THREE.RingGeometry(0.96, 1.015, 30, 1, 25 * deg10, 4 * deg10); // Create little triangle in ring
6714
6715 var ringVertices = highlightedRingGeometry.vertices;
6716 var trianglePart = ringVertices.slice(Math.floor(11 * ringVertices.length / 16), Math.floor(13 * ringVertices.length / 16));
6717 var firstY = trianglePart[0].y;
6718 var midIndex = Math.floor(trianglePart.length / 2);
6719 trianglePart.forEach(function (vec, vecIdx) {
6720 var offsetAmount = 0.025 * (midIndex - Math.abs(vecIdx - midIndex));
6721 vec.setY(firstY - offsetAmount);
6722 });
6723 var indicatorMat = new THREE.Matrix4().makeRotationX(-Math.PI / 2);
6724 var mergedGeometry = new THREE.Geometry();
6725 mergedGeometry.merge(dimmedRingGeomtry, indicatorMat, 0);
6726 mergedGeometry.merge(highlightedRingGeometry, indicatorMat, 1);
6727 var dimmedMaterial = new THREE.MeshBasicMaterial({
6728 transparent: true,
6729 opacity: ringOpacity,
6730 color: 0xffffff
6731 });
6732 var highlightMaterial = new THREE.MeshBasicMaterial({
6733 transparent: true,
6734 opacity: dirIndicatorOpacity,
6735 color: 0xffffff
6736 });
6737 var materials = [dimmedMaterial, highlightMaterial];
6738 this._mesh = new THREE.Mesh(mergedGeometry, materials);
6739 this._mesh.matrixAutoUpdate = false;
6740 this._animator = new Motion({
6741 duration: fadeoutDuration
6742 });
6743 this._opacityRange = {
6744 min: ringOpacity,
6745 max: dirIndicatorOpacity
6746 };
6747 }
6748
6749 var __proto = FloorIndicator.prototype;
6750 Object.defineProperty(__proto, "mesh", {
6751 /**
6752 * Ring mesh
6753 */
6754 get: function () {
6755 return this._mesh;
6756 },
6757 enumerable: false,
6758 configurable: true
6759 });
6760
6761 __proto.update = function (_a) {
6762 var delta = _a.delta,
6763 scale = _a.scale,
6764 position = _a.position,
6765 rotation = _a.rotation;
6766 var mesh = this._mesh;
6767 var animator = this._animator;
6768 if (!this._mesh.visible) return;
6769 animator.update(delta);
6770 var materials = this._mesh.material;
6771 var minOpacityMat = materials[0];
6772 var maxOpacityMat = materials[1];
6773 var opacityRange = this._opacityRange;
6774 minOpacityMat.opacity = animator.val * opacityRange.min;
6775 maxOpacityMat.opacity = animator.val * opacityRange.max;
6776
6777 if (animator.val <= 0) {
6778 mesh.visible = false;
6779 } // Update mesh
6780
6781
6782 mesh.scale.setScalar(scale);
6783 mesh.position.copy(position);
6784 mesh.quaternion.copy(rotation);
6785 mesh.updateMatrix();
6786 };
6787
6788 __proto.show = function () {
6789 this._mesh.visible = true;
6790
6791 this._animator.reset(1);
6792 };
6793
6794 __proto.fadeout = function () {
6795 this._animator.setEndDelta(-1);
6796 };
6797
6798 return FloorIndicator;
6799 }();
6800
6801 /*
6802 * Copyright (c) 2020 NAVER Corp.
6803 * egjs projects are licensed under the MIT license
6804 */
6805 var GESTURE;
6806
6807 (function (GESTURE) {
6808 GESTURE[GESTURE["NONE"] = 0] = "NONE";
6809 GESTURE[GESTURE["ONE_FINGER_HORIZONTAL"] = 1] = "ONE_FINGER_HORIZONTAL";
6810 GESTURE[GESTURE["ONE_FINGER_VERTICAL"] = 2] = "ONE_FINGER_VERTICAL";
6811 GESTURE[GESTURE["ONE_FINGER"] = 3] = "ONE_FINGER";
6812 GESTURE[GESTURE["TWO_FINGER_HORIZONTAL"] = 4] = "TWO_FINGER_HORIZONTAL";
6813 GESTURE[GESTURE["TWO_FINGER_VERTICAL"] = 8] = "TWO_FINGER_VERTICAL";
6814 GESTURE[GESTURE["TWO_FINGER"] = 12] = "TWO_FINGER";
6815 GESTURE[GESTURE["PINCH"] = 16] = "PINCH";
6816 })(GESTURE || (GESTURE = {}));
6817
6818 /*
6819 * Copyright (c) 2020 NAVER Corp.
6820 * egjs projects are licensed under the MIT license
6821 */
6822 var STATE$1;
6823
6824 (function (STATE) {
6825 STATE[STATE["WAITING"] = 0] = "WAITING";
6826 STATE[STATE["IN_DEADZONE"] = 1] = "IN_DEADZONE";
6827 STATE[STATE["OUT_OF_DEADZONE"] = 2] = "OUT_OF_DEADZONE";
6828 })(STATE$1 || (STATE$1 = {}));
6829 /**
6830 * Deadzone checker for deadzone-based controls
6831 * @category Controls-AR
6832 */
6833
6834
6835 var DeadzoneChecker =
6836 /*#__PURE__*/
6837 function () {
6838 /**
6839 * Create new DeadzoneChecker
6840 * @param {DeadzoneCheckerOption} [options={}] Options
6841 */
6842 function DeadzoneChecker(_a) {
6843 var _b = (_a === void 0 ? {} : _a).size,
6844 size = _b === void 0 ? 0.1 : _b; // Internal States
6845
6846 this._state = STATE$1.WAITING;
6847 this._detectedGesture = GESTURE.NONE;
6848 this._testingGestures = GESTURE.NONE;
6849 this._lastFingerCount = 0;
6850 this._aspect = 1; // Store two prev positions, as it should be maintained separately
6851
6852 this._prevOneFingerPos = new THREE.Vector2();
6853 this._prevTwoFingerPos = new THREE.Vector2();
6854 this._initialTwoFingerDistance = 0;
6855 this._prevOneFingerPosInitialized = false;
6856 this._prevTwoFingerPosInitialized = false;
6857 this._size = size;
6858 }
6859
6860 var __proto = DeadzoneChecker.prototype;
6861 Object.defineProperty(__proto, "size", {
6862 /**
6863 * Size of the deadzone.
6864 * @type number
6865 */
6866 get: function () {
6867 return this._size;
6868 },
6869 set: function (val) {
6870 this._size = val;
6871 },
6872 enumerable: false,
6873 configurable: true
6874 });
6875 Object.defineProperty(__proto, "inDeadzone", {
6876 get: function () {
6877 return this._state === STATE$1.IN_DEADZONE;
6878 },
6879 enumerable: false,
6880 configurable: true
6881 });
6882 /**
6883 * Set screen aspect(height / width)
6884 * @param aspect Screen aspect value
6885 */
6886
6887 __proto.setAspect = function (aspect) {
6888 this._aspect = aspect;
6889 };
6890
6891 __proto.setFirstInput = function (inputs) {
6892 var fingerCount = inputs.length;
6893
6894 if (fingerCount === 1 && !this._prevOneFingerPosInitialized) {
6895 this._prevOneFingerPos.copy(inputs[0]);
6896
6897 this._prevOneFingerPosInitialized = true;
6898 } else if (fingerCount === 2 && !this._prevTwoFingerPosInitialized) {
6899 this._prevTwoFingerPos.copy(new THREE.Vector2().addVectors(inputs[0], inputs[1]).multiplyScalar(0.5));
6900
6901 this._initialTwoFingerDistance = new THREE.Vector2().subVectors(inputs[0], inputs[1]).length();
6902 this._prevTwoFingerPosInitialized = true;
6903 }
6904
6905 this._lastFingerCount = fingerCount;
6906 this._state = STATE$1.IN_DEADZONE;
6907 };
6908
6909 __proto.addTestingGestures = function () {
6910 var gestures = [];
6911
6912 for (var _i = 0; _i < arguments.length; _i++) {
6913 gestures[_i] = arguments[_i];
6914 }
6915
6916 this._testingGestures = this._testingGestures | gestures.reduce(function (gesture, accumulated) {
6917 return gesture | accumulated;
6918 }, GESTURE.NONE);
6919 };
6920
6921 __proto.cleanup = function () {
6922 this._testingGestures = GESTURE.NONE;
6923 this._lastFingerCount = 0;
6924 this._prevOneFingerPosInitialized = false;
6925 this._prevTwoFingerPosInitialized = false;
6926 this._initialTwoFingerDistance = 0;
6927 this._detectedGesture = GESTURE.NONE;
6928 this._state = STATE$1.WAITING;
6929 };
6930
6931 __proto.applyScreenAspect = function (inputs) {
6932 var aspect = this._aspect;
6933 inputs.forEach(function (input) {
6934 if (aspect > 1) {
6935 input.setY(input.y * aspect);
6936 } else {
6937 input.setX(input.x / aspect);
6938 }
6939 });
6940 };
6941
6942 __proto.check = function (inputs) {
6943 var state = this._state;
6944 var deadzone = this._size;
6945 var testingGestures = this._testingGestures;
6946 var lastFingerCount = this._lastFingerCount;
6947 var fingerCount = inputs.length;
6948
6949 if (state === STATE$1.OUT_OF_DEADZONE) {
6950 return this._detectedGesture;
6951 }
6952
6953 this._lastFingerCount = fingerCount;
6954 this.applyScreenAspect(inputs);
6955
6956 if (fingerCount !== lastFingerCount) {
6957 this.setFirstInput(inputs);
6958 return GESTURE.NONE;
6959 }
6960
6961 if (fingerCount === 1) {
6962 var input = inputs[0];
6963
6964 var prevPos = this._prevOneFingerPos.clone();
6965
6966 var diff = new THREE.Vector2().subVectors(input, prevPos);
6967
6968 if (diff.length() > deadzone) {
6969 if (Math.abs(diff.x) > Math.abs(diff.y)) {
6970 if (GESTURE.ONE_FINGER_HORIZONTAL & testingGestures) {
6971 this._detectedGesture = GESTURE.ONE_FINGER_HORIZONTAL;
6972 }
6973 } else {
6974 if (GESTURE.ONE_FINGER_VERTICAL & testingGestures) {
6975 this._detectedGesture = GESTURE.ONE_FINGER_VERTICAL;
6976 }
6977 }
6978 }
6979 } else if (fingerCount === 2) {
6980 var middle = new THREE.Vector2().addVectors(inputs[1], inputs[0]).multiplyScalar(0.5);
6981
6982 var prevPos = this._prevTwoFingerPos.clone();
6983
6984 var diff = new THREE.Vector2().subVectors(middle, prevPos);
6985
6986 if (diff.length() > deadzone) {
6987 if (Math.abs(diff.x) > Math.abs(diff.y)) {
6988 if (GESTURE.TWO_FINGER_HORIZONTAL & testingGestures) {
6989 this._detectedGesture = GESTURE.TWO_FINGER_HORIZONTAL;
6990 }
6991 } else {
6992 if (GESTURE.TWO_FINGER_VERTICAL & testingGestures) {
6993 this._detectedGesture = GESTURE.TWO_FINGER_VERTICAL;
6994 }
6995 }
6996 }
6997
6998 var distance = new THREE.Vector2().subVectors(inputs[1], inputs[0]).length();
6999
7000 if (Math.abs(distance - this._initialTwoFingerDistance) > deadzone) {
7001 if (GESTURE.PINCH & testingGestures) {
7002 this._detectedGesture = GESTURE.PINCH;
7003 }
7004 }
7005 }
7006
7007 if (this._detectedGesture !== GESTURE.NONE) {
7008 this._state = STATE$1.OUT_OF_DEADZONE;
7009 }
7010
7011 return this._detectedGesture;
7012 };
7013
7014 return DeadzoneChecker;
7015 }();
7016
7017 /*
7018 * Copyright (c) 2020 NAVER Corp.
7019 * egjs projects are licensed under the MIT license
7020 */
7021 /**
7022 * AR control for {@link FloorARSession}
7023 * @category Controls-AR
7024 */
7025
7026 var ARFloorControl =
7027 /*#__PURE__*/
7028 function () {
7029 /**
7030 * Create new instance of ARFloorControl
7031 * @param {ARFloorControlOption} options Options
7032 */
7033 function ARFloorControl(options) {
7034 var _this = this;
7035
7036 if (options === void 0) {
7037 options = {};
7038 }
7039
7040 this._enabled = true;
7041 this._initialized = false;
7042 this._modelHit = false;
7043 this._hitTestSource = null;
7044
7045 this.onSelectStart = function (ctx) {
7046 var view3d = ctx.view3d,
7047 frame = ctx.frame,
7048 xrCam = ctx.xrCam,
7049 referenceSpace = ctx.referenceSpace;
7050 var hitTestSource = _this._hitTestSource;
7051 if (!hitTestSource || !_this._enabled) return;
7052 var deadzoneChecker = _this._deadzoneChecker;
7053 var rotateControl = _this._rotateControl;
7054 var translateControl = _this._translateControl;
7055 var scaleControl = _this._scaleControl; // Update deadzone testing gestures
7056
7057 if (rotateControl.enabled) {
7058 deadzoneChecker.addTestingGestures(GESTURE.ONE_FINGER);
7059 }
7060
7061 if (translateControl.enabled) {
7062 deadzoneChecker.addTestingGestures(GESTURE.ONE_FINGER);
7063 }
7064
7065 if (scaleControl.enabled) {
7066 deadzoneChecker.addTestingGestures(GESTURE.PINCH);
7067 }
7068
7069 var hitResults = frame.getHitTestResultsForTransientInput(hitTestSource);
7070
7071 var coords = _this._hitResultToVector(hitResults);
7072
7073 deadzoneChecker.applyScreenAspect(coords);
7074 deadzoneChecker.setFirstInput(coords);
7075
7076 if (coords.length === 1) {
7077 // Check finger is on the model
7078 var modelBbox = view3d.model.bbox;
7079 var targetRayPose = frame.getPose(hitResults[0].inputSource.targetRaySpace, referenceSpace);
7080 var camPos = new THREE.Vector3().setFromMatrixPosition(xrCam.matrixWorld);
7081 var fingerDir = new THREE.Vector3().copy(targetRayPose.transform.position).sub(camPos).normalize();
7082 var fingerRay = new THREE.Ray(camPos, fingerDir);
7083 var intersection = fingerRay.intersectBox(modelBbox, new THREE.Vector3());
7084
7085 if (intersection) {
7086 // Touch point intersected with model
7087 _this._modelHit = true;
7088 }
7089 }
7090
7091 _this._floorIndicator.show();
7092 };
7093
7094 this.onSelectEnd = function () {
7095 _this.deactivate();
7096
7097 _this._floorIndicator.fadeout();
7098 };
7099
7100 this._rotateControl = new ARSwirlControl(__assign({
7101 showIndicator: false
7102 }, options.rotate));
7103 this._translateControl = new ARFloorTranslateControl(options.translate);
7104 this._scaleControl = new ARScaleControl(options.scale);
7105 this._floorIndicator = new FloorIndicator(options.floorIndicator);
7106 this._deadzoneChecker = new DeadzoneChecker(options.deadzone);
7107 }
7108
7109 var __proto = ARFloorControl.prototype;
7110 Object.defineProperty(__proto, "enabled", {
7111 /**
7112 * Return whether this control is enabled or not
7113 */
7114 get: function () {
7115 return this._enabled;
7116 },
7117 enumerable: false,
7118 configurable: true
7119 });
7120 Object.defineProperty(__proto, "rotate", {
7121 /**
7122 * {@link ARSwirlControl} in this control
7123 */
7124 get: function () {
7125 return this._rotateControl;
7126 },
7127 enumerable: false,
7128 configurable: true
7129 });
7130 Object.defineProperty(__proto, "translate", {
7131 /**
7132 * {@link ARFloorTranslateControl} in this control
7133 */
7134 get: function () {
7135 return this._translateControl;
7136 },
7137 enumerable: false,
7138 configurable: true
7139 });
7140 Object.defineProperty(__proto, "scale", {
7141 /**
7142 * {@link ARScaleControl} in this control
7143 */
7144 get: function () {
7145 return this._scaleControl;
7146 },
7147 enumerable: false,
7148 configurable: true
7149 });
7150 Object.defineProperty(__proto, "controls", {
7151 get: function () {
7152 return [this._rotateControl, this._translateControl, this._scaleControl];
7153 },
7154 enumerable: false,
7155 configurable: true
7156 });
7157
7158 __proto.init = function (ctx, initialFloorPos) {
7159 var _this = this;
7160
7161 var session = ctx.session,
7162 view3d = ctx.view3d,
7163 size = ctx.size;
7164 this.controls.forEach(function (control) {
7165 return control.init(ctx);
7166 });
7167
7168 this._translateControl.initFloorPosition(initialFloorPos);
7169
7170 this._deadzoneChecker.setAspect(size.height / size.width);
7171
7172 view3d.scene.add(this._floorIndicator.mesh);
7173 this._initialized = true;
7174 session.requestHitTestSourceForTransientInput({
7175 profile: INPUT_PROFILE.TOUCH
7176 }).then(function (transientHitTestSource) {
7177 _this._hitTestSource = transientHitTestSource;
7178 });
7179 };
7180 /**
7181 * Destroy this control and deactivate it
7182 * @param view3d Instance of the {@link View3D}
7183 */
7184
7185
7186 __proto.destroy = function (ctx) {
7187 if (!this._initialized) return;
7188
7189 if (this._hitTestSource) {
7190 this._hitTestSource.cancel();
7191
7192 this._hitTestSource = null;
7193 }
7194
7195 ctx.view3d.scene.remove(this._floorIndicator.mesh);
7196 this.deactivate();
7197 this.controls.forEach(function (control) {
7198 return control.destroy(ctx);
7199 });
7200 this._initialized = false;
7201 };
7202
7203 __proto.deactivate = function () {
7204 this._modelHit = false;
7205
7206 this._deadzoneChecker.cleanup();
7207
7208 this.controls.forEach(function (control) {
7209 return control.deactivate();
7210 });
7211 };
7212 /**
7213 * Enable this control
7214 */
7215
7216
7217 __proto.enable = function () {
7218 this._enabled = true;
7219 };
7220 /**
7221 * Disable this control
7222 */
7223
7224
7225 __proto.disable = function () {
7226 this._enabled = false;
7227 this.deactivate();
7228 };
7229
7230 __proto.update = function (ctx) {
7231 var view3d = ctx.view3d,
7232 session = ctx.session,
7233 frame = ctx.frame;
7234 var hitTestSource = this._hitTestSource;
7235 if (!hitTestSource || !view3d.model) return;
7236 var deadzoneChecker = this._deadzoneChecker;
7237 var inputSources = session.inputSources;
7238 var hitResults = frame.getHitTestResultsForTransientInput(hitTestSource);
7239
7240 var coords = this._hitResultToVector(hitResults);
7241
7242 var xrInputs = {
7243 coords: coords,
7244 inputSources: inputSources,
7245 hitResults: hitResults
7246 };
7247
7248 if (deadzoneChecker.inDeadzone) {
7249 this._checkDeadzone(ctx, xrInputs);
7250 } else {
7251 this._processInput(ctx, xrInputs);
7252 }
7253
7254 this._updateControls(ctx);
7255 };
7256
7257 __proto._checkDeadzone = function (ctx, _a) {
7258 var coords = _a.coords;
7259
7260 var gesture = this._deadzoneChecker.check(coords.map(function (coord) {
7261 return coord.clone();
7262 }));
7263
7264 var rotateControl = this._rotateControl;
7265 var translateControl = this._translateControl;
7266 var scaleControl = this._scaleControl;
7267 if (gesture === GESTURE.NONE) return;
7268
7269 switch (gesture) {
7270 case GESTURE.ONE_FINGER_HORIZONTAL:
7271 case GESTURE.ONE_FINGER_VERTICAL:
7272 if (this._modelHit) {
7273 translateControl.activate(ctx, gesture);
7274 translateControl.setInitialPos(coords);
7275 } else {
7276 rotateControl.activate(ctx, gesture);
7277 rotateControl.setInitialPos(coords);
7278 }
7279
7280 break;
7281
7282 case GESTURE.PINCH:
7283 scaleControl.activate(ctx, gesture);
7284 scaleControl.setInitialPos(coords);
7285 break;
7286 }
7287 };
7288
7289 __proto._processInput = function (ctx, inputs) {
7290 this.controls.forEach(function (control) {
7291 return control.process(ctx, inputs);
7292 });
7293 };
7294
7295 __proto._updateControls = function (ctx) {
7296 var view3d = ctx.view3d,
7297 model = ctx.model,
7298 delta = ctx.delta;
7299 var deltaMilisec = delta * 1000;
7300 this.controls.forEach(function (control) {
7301 return control.update(ctx, deltaMilisec);
7302 });
7303 model.scene.updateMatrix();
7304 var modelRotation = this._rotateControl.rotation;
7305 var floorPosition = this._translateControl.floorPosition;
7306 view3d.scene.update(model, {
7307 floorPosition: floorPosition
7308 }); // Get a scaled bbox, which only has scale applied on it.
7309
7310 var scaleControl = this._scaleControl;
7311 var scaledBbox = model.initialBbox;
7312 scaledBbox.min.multiply(scaleControl.scale);
7313 scaledBbox.max.multiply(scaleControl.scale);
7314 var floorIndicator = this._floorIndicator;
7315 var boundingSphere = scaledBbox.getBoundingSphere(new THREE.Sphere());
7316 floorIndicator.update({
7317 delta: deltaMilisec,
7318 scale: boundingSphere.radius,
7319 position: floorPosition,
7320 rotation: modelRotation
7321 });
7322 };
7323
7324 __proto._hitResultToVector = function (hitResults) {
7325 return hitResults.map(function (input) {
7326 return new THREE.Vector2().set(input.inputSource.gamepad.axes[0], -input.inputSource.gamepad.axes[1]);
7327 });
7328 };
7329
7330 return ARFloorControl;
7331 }();
7332
7333 /*
7334 * Copyright (c) 2020 NAVER Corp.
7335 * egjs projects are licensed under the MIT license
7336 */
7337 /**
7338 * WebXR based AR session which puts model on the detected floor.
7339 * @category XR
7340 * @fires WebARSession#start
7341 * @fires WebARSession#end
7342 * @fires WebARSession#canPlace
7343 * @fires WebARSession#modelPlaced
7344 */
7345
7346 var FloorARSession =
7347 /*#__PURE__*/
7348 function (_super) {
7349 __extends(FloorARSession, _super);
7350 /**
7351 * Create new instance of FloorARSession
7352 * @param {FloorARSessionOption} options Options
7353 */
7354
7355
7356 function FloorARSession(options) {
7357 if (options === void 0) {
7358 options = {};
7359 }
7360
7361 var _this = _super.call(this, options) || this;
7362
7363 _this.onStart = function (ctx) {
7364 var view3d = ctx.view3d,
7365 session = ctx.session;
7366
7367 _super.prototype.onStart.call(_this, ctx);
7368
7369 _this._control = new ARFloorControl(_this._options);
7370 view3d.scene.hide();
7371
7372 _this._hitTest.init(session);
7373 };
7374
7375 _this.onEnd = function (ctx) {
7376 var view3d = ctx.view3d,
7377 session = ctx.session;
7378
7379 _super.prototype.onEnd.call(_this, ctx);
7380
7381 _this._renderContext = null;
7382 _this._modelPlaced = false;
7383 session.removeEventListener(EVENTS$1.SELECT_START, _this._onSelectStart);
7384 session.removeEventListener(EVENTS$1.SELECT_END, _this._onSelectEnd);
7385
7386 _this._hitTest.destroy();
7387
7388 _this._control.destroy(ctx);
7389
7390 _this._control = null;
7391 view3d.scene.show();
7392 };
7393
7394 _this._beforeRender = function (ctx) {
7395 _this._renderContext = ctx;
7396
7397 if (!_this._modelPlaced) {
7398 _this._initModelPosition(ctx);
7399 } else {
7400 _this._control.update(ctx);
7401 }
7402 };
7403
7404 _this._onSelectStart = function (e) {
7405 _this._control.onSelectStart(__assign(__assign({}, _this._renderContext), {
7406 frame: e.frame
7407 }));
7408 };
7409
7410 _this._onSelectEnd = function () {
7411 _this._control.onSelectEnd();
7412 };
7413
7414 _this._control = null;
7415 _this._renderContext = null;
7416 _this._modelPlaced = false;
7417 _this._hitTest = new HitTest();
7418 _this._features = merge(_this._features, _this._hitTest.features);
7419 _this._options = options;
7420 return _this;
7421 }
7422
7423 var __proto = FloorARSession.prototype;
7424 Object.defineProperty(__proto, "control", {
7425 /**
7426 * {@link ARControl} instance of this session
7427 * @type ARFloorControl | null
7428 */
7429 get: function () {
7430 return this._control;
7431 },
7432 enumerable: false,
7433 configurable: true
7434 });
7435
7436 __proto._initModelPosition = function (ctx) {
7437 var _a;
7438
7439 var view3d = ctx.view3d,
7440 frame = ctx.frame,
7441 session = ctx.session;
7442 var model = view3d.model;
7443 var hitTest = this._hitTest; // Make sure the model is loaded
7444
7445 if (!hitTest.ready || !model) return;
7446 var control = this._control;
7447 var referenceSpace = view3d.renderer.threeRenderer.xr.getReferenceSpace();
7448 var hitTestResults = hitTest.getResults(frame);
7449 if (hitTestResults.length <= 0) return;
7450 var hit = hitTestResults[0];
7451 var hitMatrix = new THREE.Matrix4().fromArray(hit.getPose(referenceSpace).transform.matrix); // If transformed coords space's y axis is not facing up, don't use it.
7452
7453 if (hitMatrix.elements[5] < 0.75) return;
7454 var modelRoot = model.scene;
7455 var hitPosition = new THREE.Vector3().setFromMatrixPosition(hitMatrix); // Reset rotation & update position
7456
7457 modelRoot.quaternion.set(0, 0, 0, 1);
7458 modelRoot.position.copy(hitPosition);
7459 modelRoot.position.setY(modelRoot.position.y - model.bbox.min.y);
7460 modelRoot.updateMatrix();
7461 view3d.scene.update(model);
7462 view3d.scene.show();
7463 this.emit("canPlace"); // Don't need it
7464
7465 hitTest.destroy();
7466 session.addEventListener(EVENTS$1.SELECT_START, this._onSelectStart);
7467 session.addEventListener(EVENTS$1.SELECT_END, this._onSelectEnd);
7468 (_a = this._domOverlay) === null || _a === void 0 ? void 0 : _a.hideLoading();
7469 this._modelPlaced = true;
7470 this.emit("modelPlaced"); // Show scale up animation
7471
7472 var originalModelScale = modelRoot.scale.clone();
7473 var scaleUpAnimation = new Animation({
7474 context: session
7475 });
7476 scaleUpAnimation.on("progress", function (evt) {
7477 var newScale = originalModelScale.clone().multiplyScalar(evt.easedProgress);
7478 modelRoot.scale.copy(newScale);
7479 });
7480 scaleUpAnimation.on("finish", function () {
7481 modelRoot.scale.copy(originalModelScale);
7482 control.init(ctx, hitPosition);
7483 });
7484 scaleUpAnimation.start();
7485 };
7486
7487 return FloorARSession;
7488 }(WebARSession);
7489
7490 /*
7491 * Copyright (c) 2020 NAVER Corp.
7492 * egjs projects are licensed under the MIT license
7493 */
7494 /**
7495 * Arrow indicator for AR model translatioon.
7496 * @category Controls-AR
7497 */
7498
7499 var ArrowIndicator =
7500 /*#__PURE__*/
7501 function () {
7502 /**
7503 * Create new ArrowIndicator
7504 * @param {ArrowIndicatorOption} [options={}] Options
7505 */
7506 function ArrowIndicator(_a) {
7507 var _this = this;
7508
7509 var _b = (_a === void 0 ? {} : _a).color,
7510 color = _b === void 0 ? 0xffffff : _b;
7511 var bodyGeometry = new THREE.CylinderBufferGeometry(0.1, 0.1, 1);
7512 var coneGeometry = new THREE.CylinderBufferGeometry(0, 0.5, 1, 30, 1);
7513 bodyGeometry.translate(0, 0.5, 0);
7514 coneGeometry.translate(0, 1.5, 0);
7515 var body = new THREE.Mesh(bodyGeometry, new THREE.MeshBasicMaterial({
7516 color: color
7517 }));
7518 var cone = new THREE.Mesh(coneGeometry, new THREE.MeshBasicMaterial({
7519 color: color
7520 }));
7521 var arrow = new THREE.Group();
7522 arrow.add(body);
7523 arrow.add(cone);
7524 this._arrows = [arrow];
7525 this._obj = new THREE.Group();
7526
7527 this._obj.add(arrow);
7528
7529 range(3).forEach(function (idx) {
7530 var copied = arrow.clone(true);
7531 copied.rotateZ(Math.PI / 2 * (idx + 1));
7532
7533 _this._obj.add(copied);
7534
7535 _this._arrows.push(copied);
7536 });
7537 this.hide();
7538 }
7539
7540 var __proto = ArrowIndicator.prototype;
7541 Object.defineProperty(__proto, "object", {
7542 /**
7543 * {@link https://threejs.org/docs/index.html#api/en/objects/Group THREE.Group} object that contains arrows.
7544 */
7545 get: function () {
7546 return this._obj;
7547 },
7548 enumerable: false,
7549 configurable: true
7550 });
7551 /**
7552 * Show indicator
7553 */
7554
7555 __proto.show = function () {
7556 this._obj.visible = true;
7557 };
7558 /**
7559 * Hide indicator
7560 */
7561
7562
7563 __proto.hide = function () {
7564 this._obj.visible = false;
7565 };
7566 /**
7567 * Change the center of the arrows to a given position
7568 * @param position Position to set as center of the arrows
7569 */
7570
7571
7572 __proto.updatePosition = function (position) {
7573 this._obj.position.copy(position);
7574 };
7575 /**
7576 * Update the arrow's offset from the center
7577 * @param offset Offset vector.
7578 */
7579
7580
7581 __proto.updateOffset = function (offset) {
7582 this._arrows.forEach(function (arrow, idx) {
7583 var facingDirection = new THREE.Vector3(0, 1, 0).applyQuaternion(arrow.quaternion);
7584 var facingOffset = facingDirection.multiply(offset);
7585 arrow.position.copy(facingOffset);
7586 });
7587 };
7588 /**
7589 * Update arrow's scale
7590 * @param scale Scale vector
7591 */
7592
7593
7594 __proto.updateScale = function (scale) {
7595 this._arrows.forEach(function (arrow) {
7596 return arrow.scale.setScalar(scale);
7597 });
7598 };
7599 /**
7600 * Update arrow's rotation.
7601 * @param rotation Quaternion value to rotate arrows.
7602 */
7603
7604
7605 __proto.updateRotation = function (rotation) {
7606 this._obj.quaternion.copy(rotation);
7607 };
7608
7609 return ArrowIndicator;
7610 }();
7611
7612 /*
7613 * Copyright (c) 2020 NAVER Corp.
7614 * egjs projects are licensed under the MIT license
7615 */
7616 /**
7617 * Model's translation(position) control for {@link ARWallControl}
7618 * @category Controls-AR
7619 */
7620
7621 var ARWallTranslateControl =
7622 /*#__PURE__*/
7623 function () {
7624 /**
7625 * Create new instance of ARTranslateControl
7626 * @param {ARWallTranslateControlOption} [options={}] Options
7627 */
7628 function ARWallTranslateControl(options) {
7629 if (options === void 0) {
7630 options = {};
7631 }
7632
7633 this.position = new THREE.Vector3();
7634 this.wallPosition = new THREE.Vector3();
7635 this.hitRotation = new THREE.Quaternion(); // Global Y guaranteed rotation matrix
7636
7637 this.wallRotation = new THREE.Quaternion(); // Options
7638 // Internal states
7639
7640 this._dragPlane = new THREE.Plane();
7641 this._enabled = true;
7642 this._active = false;
7643 this._initialPos = new THREE.Vector2();
7644 this._arrowIndicator = new ArrowIndicator(options.arrow);
7645 }
7646
7647 var __proto = ARWallTranslateControl.prototype;
7648 Object.defineProperty(__proto, "enabled", {
7649 /**
7650 * Whether this control is enabled or not
7651 * @readonly
7652 */
7653 get: function () {
7654 return this._enabled;
7655 },
7656 enumerable: false,
7657 configurable: true
7658 });
7659
7660 __proto.initWallTransform = function (_a) {
7661 var hitPosition = _a.hitPosition,
7662 hitRotation = _a.hitRotation,
7663 modelPosition = _a.modelPosition,
7664 wallRotation = _a.wallRotation;
7665 this.position.copy(modelPosition);
7666 this.hitRotation.copy(hitRotation);
7667 this.wallPosition.copy(hitPosition);
7668 this.wallRotation.copy(wallRotation);
7669 var wallNormal = new THREE.Vector3(0, 1, 0).applyQuaternion(wallRotation);
7670
7671 this._dragPlane.set(wallNormal, -wallNormal.dot(modelPosition));
7672 };
7673
7674 __proto.init = function (_a) {
7675 var view3d = _a.view3d;
7676 view3d.scene.add(this._arrowIndicator.object);
7677 };
7678
7679 __proto.destroy = function (_a) {
7680 var view3d = _a.view3d;
7681 view3d.scene.remove(this._arrowIndicator.object);
7682 };
7683 /**
7684 * Enable this control
7685 */
7686
7687
7688 __proto.enable = function () {
7689 this._enabled = true;
7690 };
7691 /**
7692 * Disable this control
7693 */
7694
7695
7696 __proto.disable = function () {
7697 this._enabled = false;
7698 this.deactivate();
7699 };
7700
7701 __proto.activate = function (_a, gesture) {
7702 var model = _a.model;
7703 if (!this._enabled) return;
7704 this._active = true; // Update arrows
7705
7706 var arrowIndicator = this._arrowIndicator;
7707 var modelBbox = model.initialBbox;
7708 modelBbox.min.multiply(model.scene.scale);
7709 modelBbox.max.multiply(model.scene.scale);
7710 modelBbox.translate(model.scene.position);
7711 arrowIndicator.show();
7712 arrowIndicator.updatePosition(modelBbox.getCenter(new THREE.Vector3()));
7713 arrowIndicator.updateScale(model.size / 16);
7714 var arrowPlaneRotation = model.scene.quaternion.clone();
7715 arrowIndicator.updateRotation(arrowPlaneRotation);
7716 arrowIndicator.updateOffset(new THREE.Vector3().subVectors(modelBbox.max, modelBbox.min).multiplyScalar(0.5));
7717 };
7718
7719 __proto.deactivate = function () {
7720 this._active = false;
7721
7722 this._arrowIndicator.hide();
7723 };
7724
7725 __proto.setInitialPos = function (coords) {
7726 this._initialPos.copy(coords[0]);
7727 };
7728
7729 __proto.process = function (_a, _b) {
7730 var view3d = _a.view3d,
7731 model = _a.model,
7732 frame = _a.frame,
7733 referenceSpace = _a.referenceSpace,
7734 xrCam = _a.xrCam;
7735 var hitResults = _b.hitResults;
7736 if (!hitResults || hitResults.length !== 1 || !this._active) return;
7737 var dragPlane = this._dragPlane;
7738 var modelRoot = model.scene;
7739 var modelZOffset = -model.initialBbox.min.z * modelRoot.scale.z;
7740 var camPos = new THREE.Vector3().setFromMatrixPosition(xrCam.matrixWorld);
7741 var hitResult = hitResults[0];
7742 var hitPose = hitResult.results[0] && hitResult.results[0].getPose(referenceSpace);
7743 var isWallHit = hitPose && hitPose.transform.matrix[5] < 0.25;
7744
7745 if (!hitPose || !isWallHit) {
7746 // Use previous drag plane if no hit plane is found
7747 var targetRayPose = frame.getPose(hitResult.inputSource.targetRaySpace, view3d.renderer.threeRenderer.xr.getReferenceSpace());
7748 var fingerDir = new THREE.Vector3().copy(targetRayPose.transform.position).sub(camPos).normalize();
7749 var fingerRay = new THREE.Ray(camPos, fingerDir);
7750 var intersection = fingerRay.intersectPlane(dragPlane, new THREE.Vector3());
7751
7752 if (intersection) {
7753 this.wallPosition.copy(intersection.clone().sub(dragPlane.normal.clone().multiplyScalar(modelZOffset)));
7754 this.position.copy(intersection);
7755 }
7756
7757 return;
7758 }
7759
7760 var hitMatrix = new THREE.Matrix4().fromArray(hitPose.transform.matrix);
7761 var hitOrientation = new THREE.Quaternion().copy(hitPose.transform.orientation);
7762 var hitPosition = new THREE.Vector3().setFromMatrixPosition(hitMatrix);
7763 var worldYAxis = new THREE.Vector3(0, 1, 0);
7764 /*
7765 * ^ wallU
7766 * |
7767 * ⨀---> wallV
7768 * wallNormal
7769 */
7770
7771 var wallNormal = new THREE.Vector3(0, 1, 0).applyQuaternion(hitOrientation).normalize();
7772 var wallU = new THREE.Vector3().crossVectors(worldYAxis, wallNormal);
7773 var wallV = wallNormal.clone().applyAxisAngle(wallU, -Math.PI / 2); // Reconstruct wall matrix with prev Y(normal) direction as Z axis
7774
7775 var wallMatrix = new THREE.Matrix4().makeBasis(wallU, wallV, wallNormal);
7776 var modelPosition = hitPosition.clone().add(wallNormal.clone().multiplyScalar(modelZOffset)); // Update position
7777
7778 this.position.copy(modelPosition);
7779 this.wallPosition.copy(hitPosition); // Update rotation if it differs more than 10deg
7780
7781 var prevWallNormal = new THREE.Vector3(0, 1, 0).applyQuaternion(this.hitRotation).normalize();
7782
7783 if (Math.acos(Math.abs(prevWallNormal.dot(wallNormal))) >= Math.PI / 18) {
7784 var prevWallRotation = this.wallRotation.clone();
7785 var wallRotation = new THREE.Quaternion().setFromRotationMatrix(wallMatrix);
7786 var rotationDiff = prevWallRotation.inverse().premultiply(wallRotation);
7787 modelRoot.quaternion.premultiply(rotationDiff);
7788 this.wallRotation.copy(wallRotation);
7789 this.hitRotation.copy(hitOrientation);
7790
7791 this._arrowIndicator.updateRotation(modelRoot.quaternion); // Update drag plane
7792
7793
7794 dragPlane.set(wallNormal, -modelPosition.dot(wallNormal));
7795 }
7796 };
7797
7798 __proto.update = function (_a, delta) {
7799 var model = _a.model;
7800 model.scene.position.copy(this.position);
7801
7802 this._arrowIndicator.updatePosition(this.position);
7803
7804 model.scene.updateMatrix();
7805 };
7806
7807 return ARWallTranslateControl;
7808 }();
7809
7810 /*
7811 * Copyright (c) 2020 NAVER Corp.
7812 * egjs projects are licensed under the MIT license
7813 */
7814 /**
7815 * AR control for {@link WallARSession}.
7816 * @category Controls-AR
7817 */
7818
7819 var ARWallControl =
7820 /*#__PURE__*/
7821 function () {
7822 /**
7823 * Create new instance of ARControl
7824 * @param {ARWallControlOption} options Options
7825 */
7826 function ARWallControl(options) {
7827 var _this = this;
7828
7829 if (options === void 0) {
7830 options = {};
7831 }
7832
7833 this._enabled = true;
7834 this._initialized = false;
7835 this._modelHit = false;
7836 this._hitTestSource = null;
7837
7838 this.onSelectStart = function (ctx) {
7839 var view3d = ctx.view3d,
7840 session = ctx.session,
7841 frame = ctx.frame,
7842 referenceSpace = ctx.referenceSpace,
7843 xrCam = ctx.xrCam;
7844 var hitTestSource = _this._hitTestSource;
7845 if (!hitTestSource || !_this._enabled) return;
7846 var deadzoneChecker = _this._deadzoneChecker;
7847 var rotateControl = _this._rotateControl;
7848 var translateControl = _this._translateControl;
7849 var scaleControl = _this._scaleControl; // Update deadzone testing gestures
7850
7851 if (rotateControl.enabled) {
7852 deadzoneChecker.addTestingGestures(GESTURE.ONE_FINGER);
7853 }
7854
7855 if (translateControl.enabled) {
7856 deadzoneChecker.addTestingGestures(GESTURE.ONE_FINGER);
7857 }
7858
7859 if (scaleControl.enabled) {
7860 deadzoneChecker.addTestingGestures(GESTURE.PINCH);
7861 }
7862
7863 var hitResults = frame.getHitTestResultsForTransientInput(hitTestSource);
7864
7865 var coords = _this._hitResultToVector(hitResults);
7866
7867 deadzoneChecker.applyScreenAspect(coords);
7868 deadzoneChecker.setFirstInput(coords);
7869
7870 if (coords.length === 1) {
7871 // Check finger is on the model
7872 var modelBbox = view3d.model.bbox;
7873 var targetRayPose = frame.getPose(session.inputSources[0].targetRaySpace, referenceSpace);
7874 var camPos = new THREE.Vector3().setFromMatrixPosition(xrCam.matrixWorld);
7875 var fingerDir = new THREE.Vector3().copy(targetRayPose.transform.position).sub(camPos).normalize();
7876 var fingerRay = new THREE.Ray(camPos, fingerDir);
7877 var intersection = fingerRay.intersectBox(modelBbox, new THREE.Vector3());
7878
7879 if (intersection) {
7880 // Touch point intersected with model
7881 _this._modelHit = true;
7882 }
7883 }
7884
7885 _this._floorIndicator.show();
7886 };
7887
7888 this.onSelectEnd = function () {
7889 _this.deactivate();
7890
7891 _this._floorIndicator.fadeout();
7892 }; // TODO: bind options
7893
7894
7895 this._rotateControl = new ARSwirlControl(__assign(__assign({}, options.rotate), {
7896 showIndicator: false
7897 }));
7898 this._translateControl = new ARWallTranslateControl(options.translate);
7899 this._scaleControl = new ARScaleControl(options.scale);
7900 this._floorIndicator = new FloorIndicator(options.floorIndicator);
7901 this._deadzoneChecker = new DeadzoneChecker(options.deadzone);
7902 }
7903
7904 var __proto = ARWallControl.prototype;
7905 Object.defineProperty(__proto, "enabled", {
7906 /**
7907 * Return whether this control is enabled or not
7908 */
7909 get: function () {
7910 return this._enabled;
7911 },
7912 enumerable: false,
7913 configurable: true
7914 });
7915 Object.defineProperty(__proto, "rotate", {
7916 /**
7917 * {@link ARSwirlControlOptions} in this control
7918 */
7919 get: function () {
7920 return this._rotateControl;
7921 },
7922 enumerable: false,
7923 configurable: true
7924 });
7925 Object.defineProperty(__proto, "translate", {
7926 /**
7927 * {@link ARTranslateControl} in this control
7928 */
7929 get: function () {
7930 return this._translateControl;
7931 },
7932 enumerable: false,
7933 configurable: true
7934 });
7935 Object.defineProperty(__proto, "scale", {
7936 /**
7937 * {@link ARScaleControl} in this control
7938 */
7939 get: function () {
7940 return this._scaleControl;
7941 },
7942 enumerable: false,
7943 configurable: true
7944 });
7945 Object.defineProperty(__proto, "controls", {
7946 get: function () {
7947 return [this._rotateControl, this._translateControl, this._scaleControl];
7948 },
7949 enumerable: false,
7950 configurable: true
7951 });
7952
7953 __proto.init = function (ctx, initialTransform) {
7954 var _this = this;
7955
7956 var session = ctx.session,
7957 view3d = ctx.view3d,
7958 size = ctx.size;
7959 this.controls.forEach(function (control) {
7960 return control.init(ctx);
7961 });
7962
7963 this._translateControl.initWallTransform(initialTransform);
7964
7965 this._deadzoneChecker.setAspect(size.height / size.width);
7966
7967 view3d.scene.add(this._floorIndicator.mesh);
7968 this._initialized = true;
7969 session.requestHitTestSourceForTransientInput({
7970 profile: INPUT_PROFILE.TOUCH
7971 }).then(function (transientHitTestSource) {
7972 _this._hitTestSource = transientHitTestSource;
7973 });
7974 };
7975 /**
7976 * Destroy this control and deactivate it
7977 * @param view3d Instance of the {@link View3D}
7978 */
7979
7980
7981 __proto.destroy = function (ctx) {
7982 if (!this._initialized) return;
7983
7984 if (this._hitTestSource) {
7985 this._hitTestSource.cancel();
7986
7987 this._hitTestSource = null;
7988 }
7989
7990 ctx.view3d.scene.remove(this._floorIndicator.mesh);
7991 this.deactivate();
7992 this.controls.forEach(function (control) {
7993 return control.destroy(ctx);
7994 });
7995 this._initialized = false;
7996 };
7997
7998 __proto.deactivate = function () {
7999 this._modelHit = false;
8000
8001 this._deadzoneChecker.cleanup();
8002
8003 this.controls.forEach(function (control) {
8004 return control.deactivate();
8005 });
8006 };
8007 /**
8008 * Enable this control
8009 */
8010
8011
8012 __proto.enable = function () {
8013 this._enabled = true;
8014 };
8015 /**
8016 * Disable this control
8017 */
8018
8019
8020 __proto.disable = function () {
8021 this._enabled = false;
8022 this.deactivate();
8023 };
8024
8025 __proto.update = function (ctx) {
8026 var view3d = ctx.view3d,
8027 session = ctx.session,
8028 frame = ctx.frame;
8029 var hitTestSource = this._hitTestSource;
8030 if (!hitTestSource || !view3d.model) return;
8031 var deadzoneChecker = this._deadzoneChecker;
8032 var inputSources = session.inputSources;
8033 var hitResults = frame.getHitTestResultsForTransientInput(hitTestSource);
8034
8035 var coords = this._hitResultToVector(hitResults);
8036
8037 var xrInputs = {
8038 coords: coords,
8039 inputSources: inputSources,
8040 hitResults: hitResults
8041 };
8042
8043 if (deadzoneChecker.inDeadzone) {
8044 this._checkDeadzone(ctx, xrInputs);
8045 } else {
8046 this._processInput(ctx, xrInputs);
8047 }
8048
8049 this._updateControls(ctx);
8050 };
8051
8052 __proto._checkDeadzone = function (ctx, _a) {
8053 var coords = _a.coords;
8054 var model = ctx.model;
8055
8056 var gesture = this._deadzoneChecker.check(coords.map(function (coord) {
8057 return coord.clone();
8058 }));
8059
8060 var rotateControl = this._rotateControl;
8061 var translateControl = this._translateControl;
8062 var scaleControl = this._scaleControl;
8063 if (gesture === GESTURE.NONE) return;
8064
8065 switch (gesture) {
8066 case GESTURE.ONE_FINGER_HORIZONTAL:
8067 case GESTURE.ONE_FINGER_VERTICAL:
8068 if (this._modelHit) {
8069 translateControl.activate(ctx, gesture);
8070 translateControl.setInitialPos(coords);
8071 } else {
8072 rotateControl.activate(ctx, gesture);
8073 rotateControl.updateAxis(new THREE.Vector3(0, 1, 0).applyQuaternion(translateControl.hitRotation));
8074 rotateControl.updateRotation(model.scene.quaternion);
8075 rotateControl.setInitialPos(coords);
8076 }
8077
8078 break;
8079
8080 case GESTURE.PINCH:
8081 scaleControl.activate(ctx, gesture);
8082 scaleControl.setInitialPos(coords);
8083 break;
8084 }
8085 };
8086
8087 __proto._processInput = function (ctx, inputs) {
8088 this.controls.forEach(function (control) {
8089 return control.process(ctx, inputs);
8090 });
8091 };
8092
8093 __proto._updateControls = function (ctx) {
8094 var view3d = ctx.view3d,
8095 model = ctx.model,
8096 delta = ctx.delta;
8097 var deltaMilisec = delta * 1000;
8098 this.controls.forEach(function (control) {
8099 return control.update(ctx, deltaMilisec);
8100 });
8101 model.scene.updateMatrix();
8102 var translateControl = this._translateControl;
8103 var floorPosition = translateControl.wallPosition;
8104 view3d.scene.update(model, {
8105 floorPosition: floorPosition,
8106 floorRotation: translateControl.hitRotation
8107 }); // Get a scaled bbox, which only has scale applied on it.
8108
8109 var scaleControl = this._scaleControl;
8110 var scaledBbox = model.initialBbox;
8111 scaledBbox.min.multiply(scaleControl.scale);
8112 scaledBbox.max.multiply(scaleControl.scale);
8113 var floorIndicator = this._floorIndicator;
8114 var boundingSphere = scaledBbox.getBoundingSphere(new THREE.Sphere());
8115 var rotX90 = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI / 2, 0, 0));
8116 var floorRotation = model.scene.quaternion.clone().multiply(rotX90);
8117 floorIndicator.update({
8118 delta: deltaMilisec,
8119 scale: boundingSphere.radius,
8120 position: floorPosition,
8121 rotation: floorRotation
8122 });
8123 };
8124
8125 __proto._hitResultToVector = function (hitResults) {
8126 return hitResults.map(function (input) {
8127 return new THREE.Vector2().set(input.inputSource.gamepad.axes[0], -input.inputSource.gamepad.axes[1]);
8128 });
8129 };
8130
8131 return ARWallControl;
8132 }();
8133
8134 /*
8135 * Copyright (c) 2020 NAVER Corp.
8136 * egjs projects are licensed under the MIT license
8137 */
8138 /**
8139 * AR session which places model on the wall
8140 * @category XR
8141 * @fires WebARSession#start
8142 * @fires WebARSession#end
8143 * @fires WebARSession#canPlace
8144 * @fires WebARSession#modelPlaced
8145 */
8146
8147 var WallARSession =
8148 /*#__PURE__*/
8149 function (_super) {
8150 __extends(WallARSession, _super);
8151 /**
8152 * Create new instance of WallARSession
8153 * @param {WallARSessionOption} [options={}] Options
8154 */
8155
8156
8157 function WallARSession(options) {
8158 if (options === void 0) {
8159 options = {};
8160 }
8161
8162 var _this = _super.call(this, options) || this;
8163
8164 _this.onStart = function (ctx) {
8165 var view3d = ctx.view3d,
8166 session = ctx.session;
8167
8168 _super.prototype.onStart.call(_this, ctx);
8169
8170 _this._control = new ARWallControl(_this._options);
8171 view3d.scene.hide();
8172
8173 _this._hitTest.init(session);
8174 };
8175
8176 _this.onEnd = function (ctx) {
8177 var view3d = ctx.view3d,
8178 session = ctx.session;
8179
8180 _super.prototype.onEnd.call(_this, ctx);
8181
8182 _this._renderContext = null;
8183 _this._modelPlaced = false;
8184 session.removeEventListener(EVENTS$1.SELECT_START, _this._onSelectStart);
8185 session.removeEventListener(EVENTS$1.SELECT_END, _this._onSelectEnd);
8186
8187 _this._hitTest.destroy();
8188
8189 _this._control.destroy(ctx);
8190
8191 _this._control = null;
8192 view3d.scene.show();
8193 };
8194
8195 _this._beforeRender = function (ctx) {
8196 _this._renderContext = ctx;
8197
8198 if (!_this._modelPlaced) {
8199 _this._initModelPosition(ctx);
8200 } else {
8201 _this._control.update(ctx);
8202 }
8203 };
8204
8205 _this._onSelectStart = function (e) {
8206 _this._control.onSelectStart(__assign(__assign({}, _this._renderContext), {
8207 frame: e.frame
8208 }));
8209 };
8210
8211 _this._onSelectEnd = function () {
8212 _this._control.onSelectEnd();
8213 };
8214
8215 _this._control = null;
8216 _this._renderContext = null;
8217 _this._modelPlaced = false;
8218 _this._hitTest = new HitTest();
8219 _this._features = merge(_this._features, _this._hitTest.features);
8220 _this._options = options;
8221 return _this;
8222 }
8223
8224 var __proto = WallARSession.prototype;
8225 Object.defineProperty(__proto, "control", {
8226 /**
8227 * {@link ARWallControl} instance of this session
8228 * @type ARWallControl | null
8229 */
8230 get: function () {
8231 return this._control;
8232 },
8233 enumerable: false,
8234 configurable: true
8235 });
8236
8237 __proto._initModelPosition = function (ctx) {
8238 var _a;
8239
8240 var view3d = ctx.view3d,
8241 frame = ctx.frame,
8242 session = ctx.session;
8243 var model = view3d.model;
8244 var hitTest = this._hitTest; // Make sure the model is loaded
8245
8246 if (!hitTest.ready || !model) return;
8247 var control = this._control;
8248 var referenceSpace = view3d.renderer.threeRenderer.xr.getReferenceSpace();
8249 var hitTestResults = hitTest.getResults(frame);
8250 if (hitTestResults.length <= 0) return;
8251 var hit = hitTestResults[0];
8252 var hitPose = hit.getPose(referenceSpace);
8253 var hitMatrix = new THREE.Matrix4().fromArray(hitPose.transform.matrix); // If transformed coord space's y axis is facing up or down, don't use it.
8254
8255 if (hitMatrix.elements[5] >= 0.25 || hitMatrix.elements[5] <= -0.25) return;
8256 var modelRoot = model.scene;
8257 var hitRotation = new THREE.Quaternion().copy(hitPose.transform.orientation);
8258 var hitPosition = new THREE.Vector3().setFromMatrixPosition(hitMatrix);
8259 var modelZOffset = -model.initialBbox.min.z * modelRoot.scale.z;
8260 var modelPosition = hitPosition.clone().setZ(hitPosition.z + modelZOffset);
8261 var worldYAxis = new THREE.Vector3(0, 1, 0);
8262 /*
8263 * ^ wallU
8264 * |
8265 * ⨀---> wallV
8266 * wallNormal
8267 */
8268
8269 var wallNormal = new THREE.Vector3(0, 1, 0).applyQuaternion(hitRotation).normalize();
8270 var wallU = new THREE.Vector3().crossVectors(worldYAxis, wallNormal);
8271 var wallV = wallNormal.clone().applyAxisAngle(wallU, -Math.PI / 2); // Reconstruct wall matrix with prev Y(normal) direction as Z axis
8272
8273 var wallMatrix = new THREE.Matrix4().makeBasis(wallU, wallV, wallNormal);
8274 var wallRotation = new THREE.Quaternion().setFromRotationMatrix(wallMatrix);
8275 var modelRotation = model.scene.quaternion.clone().premultiply(wallRotation); // Update rotation & position
8276
8277 modelRoot.quaternion.copy(modelRotation);
8278 modelRoot.position.copy(modelPosition);
8279 modelRoot.updateMatrix();
8280 view3d.scene.update(model);
8281 view3d.scene.show(); // Don't need it
8282
8283 hitTest.destroy();
8284 session.addEventListener(EVENTS$1.SELECT_START, this._onSelectStart);
8285 session.addEventListener(EVENTS$1.SELECT_END, this._onSelectEnd);
8286 (_a = this._domOverlay) === null || _a === void 0 ? void 0 : _a.hideLoading();
8287 this._modelPlaced = true; // Show scale up animation
8288
8289 var originalModelScale = model.scene.scale.clone();
8290 var scaleUpAnimation = new Animation({
8291 context: session
8292 });
8293 scaleUpAnimation.on("progress", function (evt) {
8294 var newScale = originalModelScale.clone().multiplyScalar(evt.easedProgress);
8295 model.scene.scale.copy(newScale);
8296 });
8297 scaleUpAnimation.on("finish", function () {
8298 model.scene.scale.copy(originalModelScale);
8299 control.init(ctx, {
8300 hitPosition: hitPosition,
8301 hitRotation: hitRotation,
8302 wallRotation: wallRotation,
8303 modelPosition: modelPosition
8304 });
8305 });
8306 scaleUpAnimation.start();
8307 };
8308
8309 return WallARSession;
8310 }(WebARSession);
8311
8312 /*
8313 * Copyright (c) 2020 NAVER Corp.
8314 * egjs projects are licensed under the MIT license
8315 */
8316 var STATE$2;
8317
8318 (function (STATE) {
8319 STATE[STATE["WAITING"] = 0] = "WAITING";
8320 STATE[STATE["ROTATE_HORIZONTAL"] = 1] = "ROTATE_HORIZONTAL";
8321 STATE[STATE["ROTATE_VERTICAL"] = 2] = "ROTATE_VERTICAL";
8322 })(STATE$2 || (STATE$2 = {}));
8323 /**
8324 * Two finger swipe control
8325 * @category Controls-AR
8326 */
8327
8328
8329 var ARSwipeControl =
8330 /*#__PURE__*/
8331 function () {
8332 /**
8333 * Create new ARSwipeControl
8334 * @param {ARSwipeControlOption} [options={}] Options
8335 */
8336 function ARSwipeControl(_a) {
8337 var _b = (_a === void 0 ? {} : _a).scale,
8338 scale = _b === void 0 ? 1 : _b;
8339 /**
8340 * Current rotation value
8341 */
8342
8343 this.rotation = new THREE.Quaternion(); // Internal States
8344
8345 this._state = STATE$2.WAITING;
8346 this._enabled = true;
8347 this._active = false;
8348 this._prevPos = new THREE.Vector2();
8349 this._fromQuat = new THREE.Quaternion();
8350 this._toQuat = new THREE.Quaternion();
8351 this._horizontalAxis = new THREE.Vector3();
8352 this._verticalAxis = new THREE.Vector3();
8353 this._motion = new Motion({
8354 range: INFINITE_RANGE
8355 });
8356 this._rotationIndicator = new RotationIndicator();
8357 this._userScale = scale;
8358 }
8359
8360 var __proto = ARSwipeControl.prototype;
8361 Object.defineProperty(__proto, "enabled", {
8362 /**
8363 * Whether this control is enabled or not.
8364 * @readonly
8365 */
8366 get: function () {
8367 return this._enabled;
8368 },
8369 enumerable: false,
8370 configurable: true
8371 });
8372 Object.defineProperty(__proto, "scale", {
8373 /**
8374 * Scale(speed) factor of this control.
8375 */
8376 get: function () {
8377 return this._userScale;
8378 },
8379 set: function (val) {
8380 this._userScale = val;
8381 },
8382 enumerable: false,
8383 configurable: true
8384 });
8385 Object.defineProperty(__proto, "horizontalAxis", {
8386 get: function () {
8387 return this._horizontalAxis;
8388 },
8389 enumerable: false,
8390 configurable: true
8391 });
8392 Object.defineProperty(__proto, "verticalAxis", {
8393 get: function () {
8394 return this._verticalAxis;
8395 },
8396 enumerable: false,
8397 configurable: true
8398 });
8399
8400 __proto.init = function (_a) {
8401 var view3d = _a.view3d;
8402 var initialRotation = view3d.model.scene.quaternion;
8403 this.updateRotation(initialRotation);
8404 view3d.scene.add(this._rotationIndicator.object);
8405 };
8406
8407 __proto.destroy = function (_a) {
8408 var view3d = _a.view3d;
8409 view3d.scene.remove(this._rotationIndicator.object);
8410 };
8411
8412 __proto.updateRotation = function (rotation) {
8413 this.rotation.copy(rotation);
8414
8415 this._fromQuat.copy(rotation);
8416
8417 this._toQuat.copy(rotation);
8418 };
8419 /**
8420 * Enable this control
8421 */
8422
8423
8424 __proto.enable = function () {
8425 this._enabled = true;
8426 };
8427 /**
8428 * Disable this control
8429 */
8430
8431
8432 __proto.disable = function () {
8433 this._enabled = false;
8434 };
8435
8436 __proto.updateAxis = function (horizontal, vertical) {
8437 this._horizontalAxis.copy(horizontal);
8438
8439 this._verticalAxis.copy(vertical);
8440 };
8441
8442 __proto.activate = function (_a, gesture) {
8443 var view3d = _a.view3d;
8444 if (!this._enabled) return;
8445 var model = view3d.model;
8446 var rotationIndicator = this._rotationIndicator;
8447 this._active = true;
8448 rotationIndicator.show();
8449 rotationIndicator.updatePosition(model.bbox.getCenter(new THREE.Vector3()));
8450 rotationIndicator.updateScale(model.size / 2);
8451
8452 if (gesture === GESTURE.TWO_FINGER_HORIZONTAL) {
8453 rotationIndicator.updateRotation(model.scene.quaternion.clone().multiply(new THREE.Quaternion().setFromEuler(new THREE.Euler(-Math.PI / 2, 0, 0))));
8454 this._state = STATE$2.ROTATE_HORIZONTAL;
8455 } else if (gesture === GESTURE.TWO_FINGER_VERTICAL) {
8456 rotationIndicator.updateRotation(model.scene.quaternion.clone().multiply(new THREE.Quaternion().setFromEuler(new THREE.Euler(0, Math.PI / 2, 0))));
8457 this._state = STATE$2.ROTATE_VERTICAL;
8458 }
8459 };
8460
8461 __proto.deactivate = function () {
8462 this._active = false;
8463
8464 this._rotationIndicator.hide();
8465
8466 this._state = STATE$2.WAITING;
8467 };
8468
8469 __proto.setInitialPos = function (coords) {
8470 if (coords.length < 2) return;
8471
8472 this._prevPos.set((coords[0].x + coords[1].x) / 2, (coords[0].y + coords[1].y) / 2);
8473 };
8474
8475 __proto.process = function (ctx, _a) {
8476 var coords = _a.coords;
8477 if (!this._active || coords.length !== 2) return;
8478 var state = this._state;
8479 var prevPos = this._prevPos;
8480 var motion = this._motion;
8481 var scale = this._userScale;
8482 var middlePos = new THREE.Vector2((coords[0].x + coords[1].x) / 2, (coords[0].y + coords[1].y) / 2);
8483 var posDiff = new THREE.Vector2().subVectors(prevPos, middlePos);
8484 var rotationAxis = state === STATE$2.ROTATE_HORIZONTAL ? this._horizontalAxis : this._verticalAxis;
8485 var rotationAngle = state === STATE$2.ROTATE_HORIZONTAL ? posDiff.x * scale : -posDiff.y * scale;
8486 var rotation = new THREE.Quaternion().setFromAxisAngle(rotationAxis, rotationAngle);
8487
8488 var interpolated = this._getInterpolatedQuaternion();
8489
8490 this._fromQuat.copy(interpolated);
8491
8492 this._toQuat.premultiply(rotation);
8493
8494 motion.reset(0);
8495 motion.setEndDelta(1);
8496 prevPos.copy(middlePos);
8497 };
8498
8499 __proto.update = function (_a, deltaTime) {
8500 var model = _a.model;
8501 var motion = this._motion;
8502 motion.update(deltaTime);
8503
8504 var interpolated = this._getInterpolatedQuaternion();
8505
8506 this.rotation.copy(interpolated);
8507 model.scene.quaternion.copy(this.rotation);
8508 };
8509
8510 __proto._getInterpolatedQuaternion = function () {
8511 var motion = this._motion;
8512 var toEuler = this._toQuat;
8513 var fromEuler = this._fromQuat;
8514 var progress = motion.val;
8515 return new THREE.Quaternion().copy(fromEuler).slerp(toEuler, progress);
8516 };
8517
8518 return ARSwipeControl;
8519 }();
8520
8521 /*
8522 * Copyright (c) 2020 NAVER Corp.
8523 * egjs projects are licensed under the MIT license
8524 */
8525 /**
8526 * Model's yaw(local y-axis rotation) controller which works on AR(WebXR) mode.
8527 * @category Controls-AR
8528 */
8529
8530 var ARHoverRotateControl =
8531 /*#__PURE__*/
8532 function () {
8533 /**
8534 * Create new instance of ARRotateControl
8535 * @param {ARHoverRotateControlOption} options Options
8536 */
8537 function ARHoverRotateControl(options) {
8538 if (options === void 0) {
8539 options = {};
8540 }
8541 /**
8542 * Current rotation value
8543 */
8544
8545
8546 this.rotation = new THREE.Quaternion();
8547 this._zRotationControl = new ARSwirlControl(options.swirl);
8548 this._xyRotationControl = new ARSwipeControl(options.swipe);
8549 this._activatedControl = null;
8550 }
8551
8552 var __proto = ARHoverRotateControl.prototype;
8553 Object.defineProperty(__proto, "enabled", {
8554 /**
8555 * Whether this control is enabled or not.
8556 * This returns true when either one finger control or two finger control is enabled.
8557 * @readonly
8558 */
8559 get: function () {
8560 return this._zRotationControl.enabled || this._xyRotationControl.enabled;
8561 },
8562 enumerable: false,
8563 configurable: true
8564 });
8565 Object.defineProperty(__proto, "swirl", {
8566 /**
8567 * {@link ARSwirlControl} of this control.
8568 */
8569 get: function () {
8570 return this._zRotationControl;
8571 },
8572 enumerable: false,
8573 configurable: true
8574 });
8575 Object.defineProperty(__proto, "swipe", {
8576 /**
8577 * {@link ARSwipeControl} of this control.
8578 */
8579 get: function () {
8580 return this._xyRotationControl;
8581 },
8582 enumerable: false,
8583 configurable: true
8584 });
8585
8586 __proto.init = function (ctx) {
8587 var initialRotation = ctx.view3d.model.scene.quaternion;
8588 this.rotation.copy(initialRotation);
8589
8590 this._zRotationControl.init(ctx);
8591
8592 this._xyRotationControl.init(ctx);
8593 };
8594
8595 __proto.destroy = function (ctx) {
8596 this._zRotationControl.destroy(ctx);
8597
8598 this._xyRotationControl.destroy(ctx);
8599 };
8600 /**
8601 * Enable this control
8602 */
8603
8604
8605 __proto.enable = function () {
8606 this._zRotationControl.enable();
8607
8608 this._xyRotationControl.enable();
8609 };
8610 /**
8611 * Disable this control
8612 */
8613
8614
8615 __proto.disable = function () {
8616 this._zRotationControl.disable();
8617
8618 this._xyRotationControl.disable();
8619 };
8620
8621 __proto.activate = function (ctx, gesture) {
8622 var zRotationControl = this._zRotationControl;
8623 var xyRotationControl = this._xyRotationControl;
8624
8625 if (gesture & GESTURE.ONE_FINGER) {
8626 zRotationControl.activate(ctx, gesture);
8627 zRotationControl.updateRotation(this.rotation);
8628 this._activatedControl = zRotationControl;
8629 } else if (gesture & GESTURE.TWO_FINGER) {
8630 xyRotationControl.activate(ctx, gesture);
8631 xyRotationControl.updateRotation(this.rotation);
8632 this._activatedControl = xyRotationControl;
8633 }
8634 };
8635
8636 __proto.deactivate = function () {
8637 this._zRotationControl.deactivate();
8638
8639 this._xyRotationControl.deactivate();
8640 };
8641
8642 __proto.process = function (ctx, inputs) {
8643 this._zRotationControl.process(ctx, inputs);
8644
8645 this._xyRotationControl.process(ctx, inputs);
8646 };
8647
8648 __proto.setInitialPos = function (coords) {
8649 this._zRotationControl.setInitialPos(coords);
8650
8651 this._xyRotationControl.setInitialPos(coords);
8652 };
8653
8654 __proto.update = function (ctx, deltaTime) {
8655 if (this._activatedControl) {
8656 this._activatedControl.update(ctx, deltaTime);
8657
8658 this.rotation.copy(this._activatedControl.rotation);
8659 }
8660 };
8661
8662 __proto.updateRotateAxis = function (_a) {
8663 var view3d = _a.view3d,
8664 xrCam = _a.xrCam;
8665 var model = view3d.model;
8666 var zRotateAxis = new THREE.Vector3();
8667 var horizontalRotateAxis = new THREE.Vector3();
8668 var verticalRotateAxis = new THREE.Vector3();
8669 var cameraRotation = new THREE.Quaternion().setFromRotationMatrix(xrCam.matrixWorld);
8670 var cameraBasis = [new THREE.Vector3(1, 0, 0), new THREE.Vector3(0, 1, 0), new THREE.Vector3(0, 0, 1)].map(function (axis) {
8671 return axis.applyQuaternion(cameraRotation).normalize();
8672 });
8673 var modelBasis = [new THREE.Vector3(1, 0, 0), new THREE.Vector3(0, 1, 0), new THREE.Vector3(0, 0, 1)].map(function (axis) {
8674 return axis.applyQuaternion(model.scene.quaternion);
8675 }); // Always use z-rotation
8676
8677 zRotateAxis.copy(modelBasis[2]); // Use more appropriate one between x/y axis
8678
8679 horizontalRotateAxis.copy(modelBasis[1]);
8680 verticalRotateAxis.copy(modelBasis[0]); // If it's facing other direction, negate it to face correct direction
8681
8682 if (zRotateAxis.dot(cameraBasis[2]) < 0) {
8683 zRotateAxis.negate();
8684 }
8685
8686 if (horizontalRotateAxis.dot(cameraBasis[1]) > 0) {
8687 horizontalRotateAxis.negate();
8688 }
8689
8690 if (verticalRotateAxis.dot(cameraBasis[0]) > 0) {
8691 verticalRotateAxis.negate();
8692 }
8693
8694 this._zRotationControl.updateAxis(zRotateAxis);
8695
8696 this._xyRotationControl.updateAxis(horizontalRotateAxis, verticalRotateAxis);
8697 };
8698
8699 return ARHoverRotateControl;
8700 }();
8701
8702 /*
8703 * Copyright (c) 2020 NAVER Corp.
8704 * egjs projects are licensed under the MIT license
8705 */
8706 /**
8707 * Model's translation(position) control for {@link ARHoverControl}
8708 * @category Controls-AR
8709 */
8710
8711 var ARHoverTranslateControl =
8712 /*#__PURE__*/
8713 function () {
8714 /**
8715 * Create new instance of ARTranslateControl
8716 * @param {ARHoverTranslateControlOption} [options={}] Options
8717 */
8718 function ARHoverTranslateControl(options) {
8719 if (options === void 0) {
8720 options = {};
8721 } // Internal states
8722
8723
8724 this._position = new THREE.Vector3();
8725 this._dragPlane = new THREE.Plane();
8726 this._enabled = true;
8727 this._active = false;
8728 this._initialPos = new THREE.Vector2();
8729 this._arrowIndicator = new ArrowIndicator(options.arrow);
8730 }
8731
8732 var __proto = ARHoverTranslateControl.prototype;
8733 Object.defineProperty(__proto, "enabled", {
8734 get: function () {
8735 return this._enabled;
8736 },
8737 enumerable: false,
8738 configurable: true
8739 });
8740 Object.defineProperty(__proto, "position", {
8741 get: function () {
8742 return this._position.clone();
8743 },
8744 enumerable: false,
8745 configurable: true
8746 });
8747
8748 __proto.init = function (_a) {
8749 var view3d = _a.view3d;
8750
8751 this._position.copy(view3d.model.scene.position);
8752
8753 view3d.scene.add(this._arrowIndicator.object);
8754 };
8755
8756 __proto.destroy = function (_a) {
8757 var view3d = _a.view3d;
8758 view3d.scene.remove(this._arrowIndicator.object);
8759 };
8760 /**
8761 * Enable this control
8762 */
8763
8764
8765 __proto.enable = function () {
8766 this._enabled = true;
8767 };
8768 /**
8769 * Disable this control
8770 */
8771
8772
8773 __proto.disable = function () {
8774 this._enabled = false;
8775 this.deactivate();
8776 };
8777
8778 __proto.activate = function (_a, gesture) {
8779 var model = _a.model,
8780 xrCam = _a.xrCam;
8781 if (!this._enabled) return;
8782 var modelPos = model.scene.position;
8783 var camPos = new THREE.Vector3().setFromMatrixPosition(xrCam.matrixWorld);
8784 var modelBasis = [new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3()];
8785 model.scene.matrixWorld.extractBasis(modelBasis[0], modelBasis[1], modelBasis[2]);
8786 modelBasis.forEach(function (axes) {
8787 return axes.normalize();
8788 });
8789 var camToModelDir = new THREE.Vector3().subVectors(modelPos, camPos).clone().normalize();
8790 var primaryAxisIdx = getPrimaryAxisIndex(modelBasis, camToModelDir);
8791 var primaryAxis = modelBasis[primaryAxisIdx]; // If axes is facing the opposite of camera, negate it
8792
8793 if (primaryAxis.dot(camToModelDir) < 0) {
8794 primaryAxis.negate();
8795 }
8796
8797 var originToDragPlane = new THREE.Plane(primaryAxis, 0).distanceToPoint(modelPos);
8798
8799 this._dragPlane.set(primaryAxis, -originToDragPlane);
8800
8801 this._active = true; // Update arrows
8802
8803 var arrowIndicator = this._arrowIndicator;
8804 var modelBbox = model.initialBbox;
8805 modelBbox.min.multiply(model.scene.scale);
8806 modelBbox.max.multiply(model.scene.scale);
8807 modelBbox.translate(modelPos);
8808 arrowIndicator.show();
8809 arrowIndicator.updatePosition(modelBbox.getCenter(new THREE.Vector3()));
8810 arrowIndicator.updateScale(model.size / 16);
8811 var arrowPlaneRotation = model.scene.quaternion.clone();
8812
8813 if (primaryAxisIdx === 0) {
8814 arrowPlaneRotation.multiply(new THREE.Quaternion().setFromEuler(new THREE.Euler(0, Math.PI / 2, 0)));
8815 } else if (primaryAxisIdx === 1) {
8816 arrowPlaneRotation.multiply(new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI / 2, 0, 0)));
8817 }
8818
8819 arrowIndicator.updateRotation(arrowPlaneRotation);
8820 arrowIndicator.updateOffset(new THREE.Vector3().subVectors(modelBbox.max, modelBbox.min).multiplyScalar(0.5));
8821 };
8822
8823 __proto.deactivate = function () {
8824 this._active = false;
8825
8826 this._arrowIndicator.hide();
8827 };
8828
8829 __proto.setInitialPos = function (coords) {
8830 this._initialPos.copy(coords[0]);
8831 };
8832
8833 __proto.process = function (_a, _b) {
8834 var view3d = _a.view3d,
8835 frame = _a.frame,
8836 referenceSpace = _a.referenceSpace,
8837 xrCam = _a.xrCam;
8838 var inputSources = _b.inputSources;
8839 if (inputSources.length !== 1 || !this._active) return;
8840 var inputSource = inputSources[0];
8841 var dragPlane = this._dragPlane;
8842 var targetRayPose = frame.getPose(inputSource.targetRaySpace, referenceSpace);
8843 var camPos = new THREE.Vector3().setFromMatrixPosition(xrCam.matrixWorld);
8844 var fingerDir = new THREE.Vector3().copy(targetRayPose.transform.position).sub(camPos).normalize();
8845 var fingerRay = new THREE.Ray(camPos, fingerDir);
8846 var intersection = fingerRay.intersectPlane(dragPlane, new THREE.Vector3());
8847
8848 if (intersection) {
8849 this._position.copy(intersection); // Update arrow position. As position is not a center of model, we should apply offset from it
8850
8851
8852 var model = view3d.model;
8853 var centerYOffset = model.initialBbox.getCenter(new THREE.Vector3()).multiply(model.scene.scale).y;
8854 var modelLocalYDir = new THREE.Vector3().applyQuaternion(model.scene.quaternion);
8855 var newCenter = intersection.add(modelLocalYDir.multiplyScalar(centerYOffset));
8856
8857 this._arrowIndicator.updatePosition(newCenter);
8858 }
8859 };
8860
8861 __proto.update = function (_a, delta) {
8862 var model = _a.model;
8863 model.scene.position.copy(this._position);
8864 };
8865
8866 return ARHoverTranslateControl;
8867 }();
8868
8869 /*
8870 * Copyright (c) 2020 NAVER Corp.
8871 * egjs projects are licensed under the MIT license
8872 */
8873 /**
8874 * AR control for {@link HoverARSession}
8875 * @category Controls-AR
8876 */
8877
8878 var ARHoverControl =
8879 /*#__PURE__*/
8880 function () {
8881 /**
8882 * Create new instance of ARHoverControl
8883 * @param {ARHoverControlOption} options Options
8884 */
8885 function ARHoverControl(options) {
8886 var _this = this;
8887
8888 if (options === void 0) {
8889 options = {};
8890 }
8891
8892 this._enabled = true;
8893 this._initialized = false;
8894 this._modelHit = false;
8895
8896 this.onSelectStart = function (ctx) {
8897 var view3d = ctx.view3d,
8898 session = ctx.session,
8899 frame = ctx.frame,
8900 referenceSpace = ctx.referenceSpace,
8901 xrCam = ctx.xrCam;
8902 if (!_this._enabled) return;
8903 var deadzoneChecker = _this._deadzoneChecker;
8904 var rotateControl = _this._rotateControl;
8905 var translateControl = _this._translateControl;
8906 var scaleControl = _this._scaleControl; // Update rotation axis
8907
8908 if (rotateControl.enabled) {
8909 rotateControl.updateRotateAxis(ctx);
8910 } // Update deadzone testing gestures
8911
8912
8913 if (rotateControl.swirl.enabled) {
8914 deadzoneChecker.addTestingGestures(GESTURE.ONE_FINGER);
8915 }
8916
8917 if (rotateControl.swipe.enabled) {
8918 deadzoneChecker.addTestingGestures(GESTURE.TWO_FINGER);
8919 }
8920
8921 if (translateControl.enabled) {
8922 deadzoneChecker.addTestingGestures(GESTURE.ONE_FINGER);
8923 }
8924
8925 if (scaleControl.enabled) {
8926 deadzoneChecker.addTestingGestures(GESTURE.PINCH);
8927 }
8928
8929 var coords = _this._inputSourceToVector(session.inputSources);
8930
8931 deadzoneChecker.applyScreenAspect(coords);
8932 deadzoneChecker.setFirstInput(coords);
8933
8934 if (coords.length === 1) {
8935 // Check finger is on the model
8936 var modelBbox = view3d.model.bbox;
8937 var targetRayPose = frame.getPose(session.inputSources[0].targetRaySpace, referenceSpace);
8938 var camPos = new THREE.Vector3().setFromMatrixPosition(xrCam.matrixWorld);
8939 var fingerDir = new THREE.Vector3().copy(targetRayPose.transform.position).sub(camPos).normalize();
8940 var fingerRay = new THREE.Ray(camPos, fingerDir);
8941 var intersection = fingerRay.intersectBox(modelBbox, new THREE.Vector3());
8942
8943 if (intersection) {
8944 // Touch point intersected with model
8945 _this._modelHit = true;
8946 }
8947 }
8948 };
8949
8950 this.onSelectEnd = function () {
8951 _this.deactivate();
8952 };
8953
8954 this._rotateControl = new ARHoverRotateControl(options.rotate);
8955 this._translateControl = new ARHoverTranslateControl(options.translate);
8956 this._scaleControl = new ARScaleControl(options.scale);
8957 this._deadzoneChecker = new DeadzoneChecker();
8958 }
8959
8960 var __proto = ARHoverControl.prototype;
8961 Object.defineProperty(__proto, "enabled", {
8962 /**
8963 * Return whether this control is enabled or not
8964 */
8965 get: function () {
8966 return this._enabled;
8967 },
8968 enumerable: false,
8969 configurable: true
8970 });
8971 Object.defineProperty(__proto, "rotate", {
8972 /**
8973 * {@link ARHoverRotateControlOption} in this control
8974 */
8975 get: function () {
8976 return this._rotateControl;
8977 },
8978 enumerable: false,
8979 configurable: true
8980 });
8981 Object.defineProperty(__proto, "translate", {
8982 /**
8983 * {@link ARHoverTranslateControlOption} in this control
8984 */
8985 get: function () {
8986 return this._translateControl;
8987 },
8988 enumerable: false,
8989 configurable: true
8990 });
8991 Object.defineProperty(__proto, "scale", {
8992 /**
8993 * {@link ARScaleControl} in this control
8994 */
8995 get: function () {
8996 return this._scaleControl;
8997 },
8998 enumerable: false,
8999 configurable: true
9000 });
9001 Object.defineProperty(__proto, "controls", {
9002 get: function () {
9003 return [this._rotateControl, this._translateControl, this._scaleControl];
9004 },
9005 enumerable: false,
9006 configurable: true
9007 });
9008
9009 __proto.init = function (ctx) {
9010 var size = ctx.size;
9011 this.controls.forEach(function (control) {
9012 return control.init(ctx);
9013 });
9014
9015 this._deadzoneChecker.setAspect(size.height / size.width);
9016
9017 this._initialized = true;
9018 };
9019 /**
9020 * Destroy this control and deactivate it
9021 * @param view3d Instance of the {@link View3D}
9022 */
9023
9024
9025 __proto.destroy = function (ctx) {
9026 if (!this._initialized) return;
9027 this.deactivate();
9028 this.controls.forEach(function (control) {
9029 return control.destroy(ctx);
9030 });
9031 this._initialized = false;
9032 };
9033
9034 __proto.deactivate = function () {
9035 this._modelHit = false;
9036
9037 this._deadzoneChecker.cleanup();
9038
9039 this.controls.forEach(function (control) {
9040 return control.deactivate();
9041 });
9042 };
9043 /**
9044 * Enable this control
9045 */
9046
9047
9048 __proto.enable = function () {
9049 this._enabled = true;
9050 };
9051 /**
9052 * Disable this control
9053 */
9054
9055
9056 __proto.disable = function () {
9057 this._enabled = false;
9058 this.deactivate();
9059 };
9060
9061 __proto.update = function (ctx) {
9062 var session = ctx.session;
9063 if (!this._initialized) return;
9064 var deadzoneChecker = this._deadzoneChecker;
9065 var inputSources = session.inputSources;
9066
9067 if (deadzoneChecker.inDeadzone) {
9068 this._checkDeadzone(ctx, inputSources);
9069 } else {
9070 this._processInput(ctx, inputSources);
9071 }
9072
9073 this._updateControls(ctx);
9074 };
9075
9076 __proto._checkDeadzone = function (ctx, inputSources) {
9077 var coords = this._inputSourceToVector(inputSources);
9078
9079 var gesture = this._deadzoneChecker.check(coords.map(function (coord) {
9080 return coord.clone();
9081 }));
9082
9083 var rotateControl = this._rotateControl;
9084 var translateControl = this._translateControl;
9085 var scaleControl = this._scaleControl;
9086 if (gesture === GESTURE.NONE) return;
9087
9088 switch (gesture) {
9089 case GESTURE.ONE_FINGER_HORIZONTAL:
9090 case GESTURE.ONE_FINGER_VERTICAL:
9091 if (this._modelHit) {
9092 translateControl.activate(ctx, gesture);
9093 translateControl.setInitialPos(coords);
9094 } else {
9095 rotateControl.activate(ctx, gesture);
9096 rotateControl.setInitialPos(coords);
9097 }
9098
9099 break;
9100
9101 case GESTURE.TWO_FINGER_HORIZONTAL:
9102 case GESTURE.TWO_FINGER_VERTICAL:
9103 rotateControl.activate(ctx, gesture);
9104 rotateControl.setInitialPos(coords);
9105 break;
9106
9107 case GESTURE.PINCH:
9108 scaleControl.activate(ctx, gesture);
9109 scaleControl.setInitialPos(coords);
9110 break;
9111 }
9112 };
9113
9114 __proto._processInput = function (ctx, inputSources) {
9115 var coords = this._inputSourceToVector(inputSources);
9116
9117 this.controls.forEach(function (control) {
9118 return control.process(ctx, {
9119 coords: coords,
9120 inputSources: inputSources
9121 });
9122 });
9123 };
9124
9125 __proto._updateControls = function (ctx) {
9126 var view3d = ctx.view3d,
9127 model = ctx.model,
9128 delta = ctx.delta;
9129 var deltaMilisec = delta * 1000;
9130 this.controls.forEach(function (control) {
9131 return control.update(ctx, deltaMilisec);
9132 });
9133 model.scene.updateMatrix();
9134 view3d.scene.update(model);
9135 };
9136
9137 __proto._inputSourceToVector = function (inputSources) {
9138 return Array.from(inputSources).map(function (inputSource) {
9139 var axes = inputSource.gamepad.axes;
9140 return new THREE.Vector2(axes[0], -axes[1]);
9141 });
9142 };
9143
9144 return ARHoverControl;
9145 }();
9146
9147 /*
9148 * Copyright (c) 2020 NAVER Corp.
9149 * egjs projects are licensed under the MIT license
9150 */
9151 /**
9152 * WebXR based AR session which puts model at the space front of camera.
9153 * @category XR
9154 * @fires WebARSession#start
9155 * @fires WebARSession#end
9156 * @fires WebARSession#canPlace
9157 * @fires WebARSession#modelPlaced
9158 */
9159
9160 var HoverARSession =
9161 /*#__PURE__*/
9162 function (_super) {
9163 __extends(HoverARSession, _super);
9164 /**
9165 * Create new instance of HoverARSession
9166 * @param {HoverARSessionOption} options Options
9167 */
9168
9169
9170 function HoverARSession(options) {
9171 if (options === void 0) {
9172 options = {};
9173 }
9174
9175 var _this = _super.call(this, options) || this;
9176
9177 _this.onStart = function (ctx) {
9178 var view3d = ctx.view3d;
9179
9180 _super.prototype.onStart.call(_this, ctx);
9181
9182 _this._control = new ARHoverControl(_this._options);
9183 view3d.scene.hide();
9184 };
9185
9186 _this.onEnd = function (ctx) {
9187 var view3d = ctx.view3d,
9188 session = ctx.session;
9189
9190 _super.prototype.onEnd.call(_this, ctx);
9191
9192 _this._renderContext = null;
9193 _this._modelPlaced = false;
9194 session.removeEventListener(EVENTS$1.SELECT_START, _this._onSelectStart);
9195 session.removeEventListener(EVENTS$1.SELECT_END, _this._onSelectEnd);
9196
9197 _this._control.destroy(ctx);
9198
9199 _this._control = null;
9200 view3d.scene.show();
9201 };
9202
9203 _this._beforeRender = function (ctx) {
9204 _this._renderContext = ctx;
9205
9206 if (!_this._modelPlaced) {
9207 _this._initModelPosition(ctx);
9208 } else {
9209 _this._control.update(ctx);
9210 }
9211 };
9212
9213 _this._onSelectStart = function (e) {
9214 _this._control.onSelectStart(__assign(__assign({}, _this._renderContext), {
9215 frame: e.frame
9216 }));
9217 };
9218
9219 _this._onSelectEnd = function () {
9220 _this._control.onSelectEnd();
9221 };
9222
9223 _this._control = null;
9224 _this._renderContext = null;
9225 _this._modelPlaced = false;
9226 _this._options = options;
9227 return _this;
9228 }
9229
9230 var __proto = HoverARSession.prototype;
9231 Object.defineProperty(__proto, "control", {
9232 /**
9233 * {@link ARControl} instance of this session
9234 * @type ARHoverControl | null
9235 */
9236 get: function () {
9237 return this._control;
9238 },
9239 enumerable: false,
9240 configurable: true
9241 });
9242 /**
9243 * Place model on the current position
9244 */
9245
9246 __proto.placeModel = function () {
9247 var ctx = this._renderContext; // Not ready to place model yet
9248
9249 if (!ctx || !ctx.view3d.scene.visible || this._modelPlaced) return;
9250 var session = ctx.session,
9251 view3d = ctx.view3d;
9252 var modelRoot = view3d.model.scene;
9253 var control = this._control;
9254 session.addEventListener(EVENTS$1.SELECT_START, this._onSelectStart);
9255 session.addEventListener(EVENTS$1.SELECT_END, this._onSelectEnd);
9256 this._modelPlaced = true;
9257 this.emit("modelPlaced"); // Show scale up animation
9258
9259 var originalModelScale = modelRoot.scale.clone();
9260 var scaleUpAnimation = new Animation({
9261 context: session
9262 });
9263 scaleUpAnimation.on("progress", function (evt) {
9264 var newScale = originalModelScale.clone().multiplyScalar(evt.easedProgress);
9265 modelRoot.scale.copy(newScale);
9266 });
9267 scaleUpAnimation.on("finish", function () {
9268 modelRoot.scale.copy(originalModelScale);
9269 control.init(ctx);
9270 });
9271 scaleUpAnimation.start();
9272 };
9273
9274 __proto._initModelPosition = function (ctx) {
9275 var view3d = ctx.view3d,
9276 xrCam = ctx.xrCam;
9277 var model = view3d.model; // Make sure the model exist
9278
9279 if (!model) return;
9280 var modelRoot = model.scene;
9281 var camPos = new THREE.Vector3().setFromMatrixPosition(xrCam.matrixWorld);
9282 var camQuat = new THREE.Quaternion().setFromRotationMatrix(xrCam.matrixWorld);
9283 var viewDir = new THREE.Vector3(0, 0, -1).applyQuaternion(camQuat);
9284 var modelBbox = model.bbox;
9285 var bboxDiff = new THREE.Vector3().subVectors(modelBbox.max, modelBbox.min);
9286 var maxComponent = Math.max(bboxDiff.x, bboxDiff.y, bboxDiff.z); // Reset rotation & update position
9287
9288 modelRoot.position.copy(camPos);
9289 modelRoot.position.add(viewDir.multiplyScalar(clamp(maxComponent, 0.5, 3))); // Place at 1m from camera
9290
9291 modelRoot.lookAt(camPos.setY(modelRoot.position.y));
9292 modelRoot.updateMatrix();
9293 view3d.scene.update(model);
9294
9295 if (!view3d.scene.visible) {
9296 view3d.scene.show();
9297 this.emit("canPlace");
9298 }
9299 };
9300
9301 return HoverARSession;
9302 }(WebARSession);
9303
9304 /*
9305 * Copyright (c) 2020 NAVER Corp.
9306 * egjs projects are licensed under the MIT license
9307 */
9308 // Browser related constants
9309 var IS_IOS = /iPad|iPhone|iPod/.test(navigator.userAgent) || navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1;
9310 var IS_ANDROID = /android/i.test(navigator.userAgent);
9311 var IS_SAFARI = /safari/i.test(navigator.userAgent);
9312
9313 /*
9314 * Copyright (c) 2020 NAVER Corp.
9315 * egjs projects are licensed under the MIT license
9316 */
9317 /**
9318 * AR session using Google's scene-viewer
9319 * @category XR
9320 * @see https://developers.google.com/ar/develop/java/scene-viewer
9321 */
9322
9323 var SceneViewerSession =
9324 /*#__PURE__*/
9325 function () {
9326 /**
9327 * Create new instance of SceneViewerSession
9328 * @see https://developers.google.com/ar/develop/java/scene-viewer
9329 * @param params Session params
9330 * @param {string} [params.file] This URL specifies the glTF or glb file that should be loaded into Scene Viewer. This should be URL-escaped.
9331 * @param {string} [params.browser_fallback_url] This is a Google Chrome feature supported only for web-based implementations. When the Google app com.google.android.googlequicksearchbox is not present on the device, this is the URL that Google Chrome navigates to.
9332 * @param {string} [params.mode="ar_only"] See {@link https://developers.google.com/ar/develop/java/scene-viewer} for available modes.
9333 * @param {string} [params.title] A name for the model. If present, it will be displayed in the UI. The name will be truncated with ellipses after 60 characters.
9334 * @param {string} [params.link] A URL for an external webpage. If present, a button will be surfaced in the UI that intents to this URL when clicked.
9335 * @param {string} [params.sound] A URL to a looping audio track that is synchronized with the first animation embedded in a glTF file. It should be provided alongside a glTF with an animation of matching length. If present, the sound is looped after the model is loaded. This should be URL-escaped.
9336 * @param {string} [params.resizable=true] When set to false, users will not be able to scale the model in the AR experience. Scaling works normally in the 3D experience.
9337 */
9338 function SceneViewerSession(params) {
9339 this.params = params;
9340 this.isWebXRSession = false;
9341
9342 if (!this.params.mode) {
9343 // Default mode is "ar_only", which should use com.google.ar.core package
9344 this.params.mode = "ar_only";
9345 }
9346 }
9347 /**
9348 * Return the availability of SceneViewerSession.
9349 * Scene-viewer is available on all android devices with google ARCore installed.
9350 * @returns {Promise} A Promise that resolves availability of this session(boolean).
9351 */
9352
9353
9354 var __proto = SceneViewerSession.prototype;
9355
9356 __proto.isAvailable = function () {
9357 return Promise.resolve(IS_ANDROID);
9358 };
9359 /**
9360 * Enter Scene-viewer AR session
9361 */
9362
9363
9364 __proto.enter = function () {
9365 var params = Object.assign({}, this.params);
9366 var fallback = params.browser_fallback_url;
9367 delete params.browser_fallback_url;
9368 var resizable = params.resizable;
9369 delete params.resizable;
9370
9371 if (resizable === true) {
9372 params.resizable = "true";
9373 } else if (resizable === false) {
9374 params.resizable = "false";
9375 } else if (resizable) {
9376 params.resizable = resizable;
9377 }
9378
9379 var queryString = Object.keys(params).filter(function (key) {
9380 return params[key] != null;
9381 }).map(function (key) {
9382 return key + "=" + params[key];
9383 }).join("&");
9384 var intentURL = params.mode === "ar_only" ? SCENE_VIEWER.INTENT_AR_CORE(queryString, fallback) : SCENE_VIEWER.INTENT_SEARCHBOX(queryString, fallback || SCENE_VIEWER.FALLBACK_DEFAULT(queryString));
9385 var anchor = document.createElement("a");
9386 anchor.href = intentURL;
9387 anchor.click();
9388 return Promise.resolve();
9389 };
9390
9391 __proto.exit = function () {// DO NOTHING
9392 };
9393
9394 return SceneViewerSession;
9395 }();
9396
9397 /*
9398 * Copyright (c) 2020 NAVER Corp.
9399 * egjs projects are licensed under the MIT license
9400 */
9401 /**
9402 * AR Session using Apple AR Quick Look Viewer
9403 * @category XR
9404 * @see https://developer.apple.com/augmented-reality/quick-look/
9405 */
9406
9407 var QuickLookSession =
9408 /*#__PURE__*/
9409 function () {
9410 /**
9411 * Create new instance of QuickLookSession
9412 * @param {object} [options] Quick Look options
9413 * @param {string} [options.file] USDZ file's location URL.
9414 * @param {boolean} [options.allowsContentScaling=true] Whether to allow content scaling.
9415 */
9416 function QuickLookSession(_a) {
9417 var file = _a.file,
9418 _b = _a.allowsContentScaling,
9419 allowsContentScaling = _b === void 0 ? true : _b;
9420 /**
9421 * Whether it's webxr-based session or not
9422 * @type false
9423 */
9424
9425 this.isWebXRSession = false;
9426 this._file = file;
9427 this._allowsContentScaling = allowsContentScaling;
9428 }
9429 /**
9430 * Return the availability of QuickLookSession.
9431 * QuickLook AR is available on iOS12+ on Safari & Chrome browser
9432 * Note that iOS Chrome won't show up QuickLook AR when it's local dev environment
9433 * @returns {Promise} A Promise that resolves availability of this session(boolean).
9434 */
9435
9436
9437 var __proto = QuickLookSession.prototype;
9438
9439 __proto.isAvailable = function () {
9440 // This can handle all WebKit based browsers including iOS Safari & iOS Chrome
9441 return Promise.resolve(QUICKLOOK_SUPPORTED && IS_IOS && IS_SAFARI);
9442 };
9443 /**
9444 * Enter QuickLook AR Session
9445 */
9446
9447
9448 __proto.enter = function () {
9449 var anchor = document.createElement("a");
9450 anchor.setAttribute("rel", "ar");
9451 anchor.appendChild(document.createElement("img"));
9452 var usdzURL = new URL(this._file, window.location.toString());
9453
9454 if (!this._allowsContentScaling) {
9455 usdzURL.hash = "allowsContentScaling=0";
9456 }
9457
9458 anchor.setAttribute("href", usdzURL.toString());
9459 anchor.click();
9460 return Promise.resolve();
9461 };
9462
9463 __proto.exit = function () {// DO NOTHING
9464 };
9465
9466 return QuickLookSession;
9467 }();
9468
9469 /*
9470 * Copyright (c) 2020 NAVER Corp.
9471 * egjs projects are licensed under the MIT license
9472 */
9473
9474 var XR = {
9475 __proto__: null,
9476 WebARSession: WebARSession,
9477 FloorARSession: FloorARSession,
9478 WallARSession: WallARSession,
9479 HoverARSession: HoverARSession,
9480 SceneViewerSession: SceneViewerSession,
9481 QuickLookSession: QuickLookSession
9482 };
9483
9484 /*
9485 * Copyright (c) 2020 NAVER Corp.
9486 * egjs projects are licensed under the MIT license
9487 */
9488 /**
9489 * Texture(image) model
9490 * @category Extra
9491 */
9492
9493 var TextureModel =
9494 /*#__PURE__*/
9495 function (_super) {
9496 __extends(TextureModel, _super);
9497 /**
9498 * Create new TextureModel
9499 * @param {object} options Options
9500 * @param {number} [options.width] Width of the model.
9501 * @param {number} [options.height] Height of the model.
9502 * @param {boolean} [options.billboard=false] When set to true, model will keep rotate to show its front face to camera. Only Y-axis rotation is considered.
9503 * @throws {View3DError} `CODES.PROVIDE_WIDTH_OR_HEIGHT` When both width and height are not given.
9504 */
9505
9506
9507 function TextureModel(_a) {
9508 var image = _a.image,
9509 width = _a.width,
9510 height = _a.height,
9511 _b = _a.billboard,
9512 billboard = _b === void 0 ? false : _b;
9513
9514 var _this = this;
9515
9516 var texture = image.isTexture ? image : new THREE.Texture(image);
9517 var aspect = texture.image.width / texture.image.height;
9518
9519 if (width == null && height == null) {
9520 throw new View3DError(MESSAGES.PROVIDE_WIDTH_OR_HEIGHT, CODES.PROVIDE_WIDTH_OR_HEIGHT);
9521 }
9522
9523 if (width == null) {
9524 width = height * aspect;
9525 } else if (height == null) {
9526 height = width / aspect;
9527 }
9528
9529 texture.encoding = THREE.sRGBEncoding;
9530 var geometry = new THREE.PlaneGeometry(width, height);
9531 var material = new THREE.MeshBasicMaterial({
9532 map: texture,
9533 side: THREE.DoubleSide
9534 });
9535 var mesh = new THREE.Mesh(geometry, material);
9536 _this = _super.call(this, {
9537 scenes: [mesh]
9538 }) || this;
9539 _this._texture = texture;
9540 _this._mesh = mesh;
9541
9542 if (billboard) {
9543 var root_1 = mesh;
9544
9545 root_1.onBeforeRender = function (renderer, scene, camera) {
9546 var pos = root_1.getWorldPosition(new THREE.Vector3());
9547 var camPos = new THREE.Vector3().setFromMatrixPosition(camera.matrixWorld);
9548 root_1.lookAt(camPos.setY(pos.y));
9549 mesh.updateMatrix();
9550 };
9551 }
9552
9553 return _this;
9554 }
9555
9556 var __proto = TextureModel.prototype;
9557 Object.defineProperty(__proto, "texture", {
9558 /**
9559 * Texture that used for this model
9560 * @see https://threejs.org/docs/index.html#api/en/textures/Texture
9561 * @type THREE.Texture
9562 */
9563 get: function () {
9564 return this._texture;
9565 },
9566 enumerable: false,
9567 configurable: true
9568 });
9569 Object.defineProperty(__proto, "mesh", {
9570 /**
9571 * Model's mesh object
9572 * @see https://threejs.org/docs/index.html#api/en/objects/Mesh
9573 * @type THREE.Mesh
9574 */
9575 get: function () {
9576 return this._mesh;
9577 },
9578 enumerable: false,
9579 configurable: true
9580 });
9581 return TextureModel;
9582 }(Model);
9583
9584 /*
9585 * Copyright (c) 2020 NAVER Corp.
9586 * egjs projects are licensed under the MIT license
9587 */
9588
9589 var Extra = {
9590 __proto__: null,
9591 TextureModel: TextureModel
9592 };
9593
9594 /*
9595 * Copyright (c) 2020 NAVER Corp.
9596 * egjs projects are licensed under the MIT license
9597 */
9598
9599 var Externals = {
9600 __proto__: null,
9601 THREE: THREE
9602 };
9603
9604 /*
9605 * Copyright (c) 2020 NAVER Corp.
9606 * egjs projects are licensed under the MIT license
9607 */
9608 merge(View3D, Core);
9609 merge(View3D, Environments);
9610 merge(View3D, Controls);
9611 merge(View3D, Loaders);
9612 merge(View3D, XR);
9613 merge(View3D, Extra);
9614 merge(View3D, Externals);
9615 View3D.View3DError = View3DError;
9616 View3D.ERROR_CODES = CODES;
9617 View3D.EASING = EASING;
9618
9619 return View3D;
9620
9621})));
9622//# sourceMappingURL=view3d.js.map