|
@@ -1,303 +1,366 @@
|
|
|
-/******/ (function(modules) { // webpackBootstrap
|
|
|
+(function webpackUniversalModuleDefinition(root, factory) {
|
|
|
+ if(typeof exports === 'object' && typeof module === 'object')
|
|
|
+ module.exports = factory();
|
|
|
+ else if(typeof define === 'function' && define.amd)
|
|
|
+ define([], factory);
|
|
|
+ else {
|
|
|
+ var a = factory();
|
|
|
+ for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
|
|
|
+ }
|
|
|
+})(typeof self !== 'undefined' ? self : this, function() {
|
|
|
+return /******/ (function(modules) { // webpackBootstrap
|
|
|
/******/ // The module cache
|
|
|
/******/ var installedModules = {};
|
|
|
-
|
|
|
+/******/
|
|
|
/******/ // The require function
|
|
|
/******/ function __webpack_require__(moduleId) {
|
|
|
-
|
|
|
+/******/
|
|
|
/******/ // Check if module is in cache
|
|
|
-/******/ if(installedModules[moduleId])
|
|
|
+/******/ if(installedModules[moduleId]) {
|
|
|
/******/ return installedModules[moduleId].exports;
|
|
|
-
|
|
|
+/******/ }
|
|
|
/******/ // Create a new module (and put it into the cache)
|
|
|
/******/ var module = installedModules[moduleId] = {
|
|
|
-/******/ exports: {},
|
|
|
-/******/ id: moduleId,
|
|
|
-/******/ loaded: false
|
|
|
+/******/ i: moduleId,
|
|
|
+/******/ l: false,
|
|
|
+/******/ exports: {}
|
|
|
/******/ };
|
|
|
-
|
|
|
+/******/
|
|
|
/******/ // Execute the module function
|
|
|
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
|
|
-
|
|
|
+/******/
|
|
|
/******/ // Flag the module as loaded
|
|
|
-/******/ module.loaded = true;
|
|
|
-
|
|
|
+/******/ module.l = true;
|
|
|
+/******/
|
|
|
/******/ // Return the exports of the module
|
|
|
/******/ return module.exports;
|
|
|
/******/ }
|
|
|
-
|
|
|
-
|
|
|
+/******/
|
|
|
+/******/
|
|
|
/******/ // expose the modules object (__webpack_modules__)
|
|
|
/******/ __webpack_require__.m = modules;
|
|
|
-
|
|
|
+/******/
|
|
|
/******/ // expose the module cache
|
|
|
/******/ __webpack_require__.c = installedModules;
|
|
|
-
|
|
|
+/******/
|
|
|
+/******/ // define getter function for harmony exports
|
|
|
+/******/ __webpack_require__.d = function(exports, name, getter) {
|
|
|
+/******/ if(!__webpack_require__.o(exports, name)) {
|
|
|
+/******/ Object.defineProperty(exports, name, {
|
|
|
+/******/ configurable: false,
|
|
|
+/******/ enumerable: true,
|
|
|
+/******/ get: getter
|
|
|
+/******/ });
|
|
|
+/******/ }
|
|
|
+/******/ };
|
|
|
+/******/
|
|
|
+/******/ // getDefaultExport function for compatibility with non-harmony modules
|
|
|
+/******/ __webpack_require__.n = function(module) {
|
|
|
+/******/ var getter = module && module.__esModule ?
|
|
|
+/******/ function getDefault() { return module['default']; } :
|
|
|
+/******/ function getModuleExports() { return module; };
|
|
|
+/******/ __webpack_require__.d(getter, 'a', getter);
|
|
|
+/******/ return getter;
|
|
|
+/******/ };
|
|
|
+/******/
|
|
|
+/******/ // Object.prototype.hasOwnProperty.call
|
|
|
+/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
|
|
+/******/
|
|
|
/******/ // __webpack_public_path__
|
|
|
/******/ __webpack_require__.p = "";
|
|
|
-
|
|
|
+/******/
|
|
|
/******/ // Load entry module and return exports
|
|
|
-/******/ return __webpack_require__(0);
|
|
|
+/******/ return __webpack_require__(__webpack_require__.s = 0);
|
|
|
/******/ })
|
|
|
/************************************************************************/
|
|
|
/******/ ([
|
|
|
/* 0 */
|
|
|
-/***/ (function(module, exports) {
|
|
|
-
|
|
|
- /* global AFRAME, THREE */
|
|
|
-
|
|
|
- if (typeof AFRAME === 'undefined') {
|
|
|
- throw new Error('Component attempted to register before AFRAME was available.');
|
|
|
- }
|
|
|
-
|
|
|
- // Configuration for the MutationObserver used to refresh the whitelist.
|
|
|
- // Listens for addition/removal of elements and attributes within the scene.
|
|
|
- var OBSERVER_CONFIG = {
|
|
|
- childList: true,
|
|
|
- attributes: true,
|
|
|
- subtree: true
|
|
|
- };
|
|
|
-
|
|
|
- /**
|
|
|
- * Implement AABB collision detection for entities with a mesh.
|
|
|
- * https://en.wikipedia.org/wiki/Minimum_bounding_box#Axis-aligned_minimum_bounding_box
|
|
|
- *
|
|
|
- * @property {string} objects - Selector of entities to test for collision.
|
|
|
- */
|
|
|
- AFRAME.registerComponent('aabb-collider', {
|
|
|
- schema: {
|
|
|
- collideNonVisible: {default: false},
|
|
|
- debug: {default: false},
|
|
|
- enabled: {default: true},
|
|
|
- interval: {default: 80},
|
|
|
- objects: {default: ''}
|
|
|
- },
|
|
|
-
|
|
|
- init: function () {
|
|
|
- this.centerDifferenceVec3 = new THREE.Vector3();
|
|
|
- this.clearedIntersectedEls = [];
|
|
|
- this.closestIntersectedEl = null;
|
|
|
- this.boundingBox = new THREE.Box3();
|
|
|
- this.boxCenter = new THREE.Vector3();
|
|
|
- this.boxHelper = new THREE.BoxHelper();
|
|
|
- this.boxMax = new THREE.Vector3();
|
|
|
- this.boxMin = new THREE.Vector3();
|
|
|
- this.hitClosestClearEventDetail = {};
|
|
|
- this.hitClosestEventDetail = {};
|
|
|
- this.intersectedEls = [];
|
|
|
- this.objectEls = [];
|
|
|
- this.newIntersectedEls = [];
|
|
|
- this.prevCheckTime = undefined;
|
|
|
- this.previousIntersectedEls = [];
|
|
|
-
|
|
|
- this.setDirty = this.setDirty.bind(this);
|
|
|
- this.observer = new MutationObserver(this.setDirty);
|
|
|
- this.dirty = true;
|
|
|
-
|
|
|
- this.hitStartEventDetail = {intersectedEls: this.newIntersectedEls};
|
|
|
- },
|
|
|
-
|
|
|
- play: function () {
|
|
|
- this.observer.observe(this.el.sceneEl, OBSERVER_CONFIG);
|
|
|
- this.el.sceneEl.addEventListener('object3dset', this.setDirty);
|
|
|
- this.el.sceneEl.addEventListener('object3dremove', this.setDirty);
|
|
|
- },
|
|
|
-
|
|
|
- remove: function () {
|
|
|
- this.observer.disconnect();
|
|
|
- this.el.sceneEl.removeEventListener('object3dset', this.setDirty);
|
|
|
- this.el.sceneEl.removeEventListener('object3dremove', this.setDirty);
|
|
|
- },
|
|
|
-
|
|
|
- tick: function (time) {
|
|
|
- var boxHelper;
|
|
|
- var boundingBox = this.boundingBox;
|
|
|
- var centerDifferenceVec3 = this.centerDifferenceVec3;
|
|
|
- var clearedIntersectedEls = this.clearedIntersectedEls;
|
|
|
- var closestCenterDifference;
|
|
|
- var newClosestEl;
|
|
|
- var intersectedEls = this.intersectedEls;
|
|
|
- var el = this.el;
|
|
|
- var i;
|
|
|
- var newIntersectedEls = this.newIntersectedEls;
|
|
|
- var objectEls = this.objectEls;
|
|
|
- var prevCheckTime = this.prevCheckTime;
|
|
|
- var previousIntersectedEls = this.previousIntersectedEls;
|
|
|
- var self = this;
|
|
|
-
|
|
|
- if (!this.data.enabled) { return; }
|
|
|
-
|
|
|
- // Only check for intersection if interval time has passed.
|
|
|
- if (prevCheckTime && (time - prevCheckTime < this.data.interval)) { return; }
|
|
|
- // Update check time.
|
|
|
- this.prevCheckTime = time;
|
|
|
-
|
|
|
- if (this.dirty) { this.refreshObjects(); }
|
|
|
-
|
|
|
- // Update the bounding box to account for rotations and position changes.
|
|
|
- boundingBox.setFromObject(el.object3D);
|
|
|
- this.boxMin.copy(boundingBox.min);
|
|
|
- this.boxMax.copy(boundingBox.max);
|
|
|
- boundingBox.getCenter(this.boxCenter);
|
|
|
-
|
|
|
- if (this.data.debug) {
|
|
|
- this.boxHelper.setFromObject(el.object3D);
|
|
|
- if (!this.boxHelper.parent) { el.sceneEl.object3D.add(this.boxHelper); }
|
|
|
- }
|
|
|
-
|
|
|
- copyArray(previousIntersectedEls, intersectedEls);
|
|
|
-
|
|
|
- // Populate intersectedEls array.
|
|
|
- intersectedEls.length = 0;
|
|
|
- for (i = 0; i < objectEls.length; i++) {
|
|
|
- if (objectEls[i] === this.el) { continue; }
|
|
|
-
|
|
|
- // Don't collide with non-visible if flag set.
|
|
|
- if (!this.data.collideNonVisible && !objectEls[i].getAttribute('visible')) {
|
|
|
- // Remove box helper if debug flag set and has box helper.
|
|
|
- if (this.data.debug) {
|
|
|
- boxHelper = objectEls[i].object3D.boxHelper;
|
|
|
- if (boxHelper) {
|
|
|
- el.sceneEl.object3D.remove(boxHelper);
|
|
|
- objectEls[i].object3D.boxHelper = null;
|
|
|
- }
|
|
|
- }
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- // Check for interection.
|
|
|
- if (this.isIntersecting(objectEls[i])) { intersectedEls.push(objectEls[i]); }
|
|
|
- }
|
|
|
-
|
|
|
- // Get newly intersected entities.
|
|
|
- newIntersectedEls.length = 0;
|
|
|
- for (i = 0; i < intersectedEls.length; i++) {
|
|
|
- if (previousIntersectedEls.indexOf(intersectedEls[i]) === -1) {
|
|
|
- newIntersectedEls.push(intersectedEls[i]);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Emit cleared events on no longer intersected entities.
|
|
|
- clearedIntersectedEls.length = 0;
|
|
|
- for (i = 0; i < previousIntersectedEls.length; i++) {
|
|
|
- if (intersectedEls.indexOf(previousIntersectedEls[i]) !== -1) { continue; }
|
|
|
- if (!previousIntersectedEls[i].hasAttribute('aabb-collider')) {
|
|
|
- previousIntersectedEls[i].emit('hitend');
|
|
|
- }
|
|
|
- clearedIntersectedEls.push(previousIntersectedEls[i]);
|
|
|
- }
|
|
|
-
|
|
|
- // Emit events on intersected entities. Do this after the cleared events.
|
|
|
- for (i = 0; i < newIntersectedEls.length; i++) {
|
|
|
- if (newIntersectedEls[i] === this.el) { continue; }
|
|
|
- if (newIntersectedEls[i].hasAttribute('aabb-collider')) { continue; }
|
|
|
- newIntersectedEls[i].emit('hitstart');
|
|
|
- }
|
|
|
-
|
|
|
- // Calculate closest intersected entity based on centers.
|
|
|
- for (i = 0; i < intersectedEls.length; i++) {
|
|
|
- if (intersectedEls[i] === this.el) { continue; }
|
|
|
- centerDifferenceVec3
|
|
|
- .copy(intersectedEls[i].object3D.boundingBoxCenter)
|
|
|
- .sub(this.boxCenter);
|
|
|
- if (closestCenterDifference === undefined ||
|
|
|
- centerDifferenceVec3.length() < closestCenterDifference) {
|
|
|
- closestCenterDifference = centerDifferenceVec3.length();
|
|
|
- newClosestEl = intersectedEls[i];
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Emit events for the new closest entity and the old closest entity.
|
|
|
- if (!intersectedEls.length && this.closestIntersectedEl) {
|
|
|
- // No intersected entities, clear any closest entity.
|
|
|
- this.hitClosestClearEventDetail.el = this.closestIntersectedEl;
|
|
|
- this.closestIntersectedEl.emit('hitclosestclear');
|
|
|
- this.closestIntersectedEl = null;
|
|
|
- el.emit('hitclosestclear', this.hitClosestClearEventDetail);
|
|
|
- } else if (newClosestEl !== this.closestIntersectedEl) {
|
|
|
- // Clear the previous closest entity.
|
|
|
- if (this.closestIntersectedEl) {
|
|
|
- this.hitClosestClearEventDetail.el = this.closestIntersectedEl;
|
|
|
- this.closestIntersectedEl.emit('hitclosestclear', this.hitClosestClearEventDetail);
|
|
|
- }
|
|
|
- if (newClosestEl) {
|
|
|
- // Emit for the new closest entity.
|
|
|
- newClosestEl.emit('hitclosest');
|
|
|
- this.closestIntersectedEl = newClosestEl;
|
|
|
- this.hitClosestEventDetail.el = newClosestEl;
|
|
|
- el.emit('hitclosest', this.hitClosestEventDetail);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (clearedIntersectedEls.length) {
|
|
|
- el.emit('hitend');
|
|
|
- }
|
|
|
-
|
|
|
- if (newIntersectedEls.length) {
|
|
|
- el.emit('hitstart', this.hitStartEventDetail);
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * AABB collision detection.
|
|
|
- * 3D version of https://www.youtube.com/watch?v=ghqD3e37R7E
|
|
|
- */
|
|
|
- isIntersecting: (function () {
|
|
|
- var boundingBox = new THREE.Box3();
|
|
|
-
|
|
|
- return function (el) {
|
|
|
- var isIntersecting;
|
|
|
- var boxHelper;
|
|
|
- var boxMin;
|
|
|
- var boxMax;
|
|
|
-
|
|
|
- boundingBox.setFromObject(el.object3D);
|
|
|
-
|
|
|
- if (this.data.debug) {
|
|
|
- if (!el.object3D.boxHelper) {
|
|
|
- el.object3D.boxHelper = new THREE.BoxHelper(
|
|
|
- el.object3D, new THREE.Color(Math.random(), Math.random(), Math.random()));
|
|
|
- el.sceneEl.object3D.add(el.object3D.boxHelper);
|
|
|
- }
|
|
|
- el.object3D.boxHelper.setFromObject(el.object3D);
|
|
|
- }
|
|
|
-
|
|
|
- boxMin = boundingBox.min;
|
|
|
- boxMax = boundingBox.max;
|
|
|
- el.object3D.boundingBoxCenter = el.object3D.boundingBoxCenter || new THREE.Vector3();
|
|
|
- boundingBox.getCenter(el.object3D.boundingBoxCenter);
|
|
|
- return (this.boxMin.x <= boxMax.x && this.boxMax.x >= boxMin.x) &&
|
|
|
- (this.boxMin.y <= boxMax.y && this.boxMax.y >= boxMin.y) &&
|
|
|
- (this.boxMin.z <= boxMax.z && this.boxMax.z >= boxMin.z);
|
|
|
- };
|
|
|
- })(),
|
|
|
-
|
|
|
- /**
|
|
|
- * Mark the object list as dirty, to be refreshed before next raycast.
|
|
|
- */
|
|
|
- setDirty: function () {
|
|
|
- this.dirty = true;
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * Update list of objects to test for intersection.
|
|
|
- */
|
|
|
- refreshObjects: function () {
|
|
|
- var data = this.data;
|
|
|
- // If objects not defined, intersect with everything.
|
|
|
- this.objectEls = data.objects
|
|
|
- ? this.el.sceneEl.querySelectorAll(data.objects)
|
|
|
- : this.el.sceneEl.children;
|
|
|
- this.dirty = false;
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- function copyArray (dest, source) {
|
|
|
- var i;
|
|
|
- dest.length = 0;
|
|
|
- for (i = 0; i < source.length; i++) { dest[i] = source[i]; }
|
|
|
- }
|
|
|
-
|
|
|
+/***/ (function(module, exports, __webpack_require__) {
|
|
|
+
|
|
|
+"use strict";
|
|
|
+
|
|
|
+
|
|
|
+/* global AFRAME, THREE */
|
|
|
+
|
|
|
+if (typeof AFRAME === 'undefined') {
|
|
|
+ throw new Error('Component attempted to register before AFRAME was available.');
|
|
|
+}
|
|
|
+
|
|
|
+// Configuration for the MutationObserver used to refresh the whitelist.
|
|
|
+// Listens for addition/removal of elements and attributes within the scene.
|
|
|
+var OBSERVER_CONFIG = {
|
|
|
+ childList: true,
|
|
|
+ attributes: true,
|
|
|
+ subtree: true
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * Implement AABB collision detection for entities with a mesh.
|
|
|
+ * https://en.wikipedia.org/wiki/Minimum_bounding_box#Axis-aligned_minimum_bounding_box
|
|
|
+ *
|
|
|
+ * @property {string} objects - Selector of entities to test for collision.
|
|
|
+ */
|
|
|
+AFRAME.registerComponent('aabb-collider', {
|
|
|
+ schema: {
|
|
|
+ collideNonVisible: { default: false },
|
|
|
+ debug: { default: false },
|
|
|
+ enabled: { default: true },
|
|
|
+ interval: { default: 80 },
|
|
|
+ objects: { default: '' }
|
|
|
+ },
|
|
|
+
|
|
|
+ init: function init() {
|
|
|
+ this.centerDifferenceVec3 = new THREE.Vector3();
|
|
|
+ this.clearedIntersectedEls = [];
|
|
|
+ this.closestIntersectedEl = null;
|
|
|
+ this.boundingBox = new THREE.Box3();
|
|
|
+ this.boxCenter = new THREE.Vector3();
|
|
|
+ this.boxHelper = new THREE.BoxHelper();
|
|
|
+ this.boxMax = new THREE.Vector3();
|
|
|
+ this.boxMin = new THREE.Vector3();
|
|
|
+ this.hitClosestClearEventDetail = {};
|
|
|
+ this.hitClosestEventDetail = {};
|
|
|
+ this.intersectedEls = [];
|
|
|
+ this.objectEls = [];
|
|
|
+ this.newIntersectedEls = [];
|
|
|
+ this.prevCheckTime = undefined;
|
|
|
+ this.previousIntersectedEls = [];
|
|
|
+
|
|
|
+ this.setDirty = this.setDirty.bind(this);
|
|
|
+ this.observer = new MutationObserver(this.setDirty);
|
|
|
+ this.dirty = true;
|
|
|
+
|
|
|
+ this.hitStartEventDetail = { intersectedEls: this.newIntersectedEls };
|
|
|
+ },
|
|
|
+
|
|
|
+ play: function play() {
|
|
|
+ this.observer.observe(this.el.sceneEl, OBSERVER_CONFIG);
|
|
|
+ this.el.sceneEl.addEventListener('object3dset', this.setDirty);
|
|
|
+ this.el.sceneEl.addEventListener('object3dremove', this.setDirty);
|
|
|
+ },
|
|
|
+
|
|
|
+ remove: function remove() {
|
|
|
+ this.observer.disconnect();
|
|
|
+ this.el.sceneEl.removeEventListener('object3dset', this.setDirty);
|
|
|
+ this.el.sceneEl.removeEventListener('object3dremove', this.setDirty);
|
|
|
+ },
|
|
|
+
|
|
|
+ tick: function tick(time) {
|
|
|
+ var boundingBox = this.boundingBox;
|
|
|
+ var centerDifferenceVec3 = this.centerDifferenceVec3;
|
|
|
+ var clearedIntersectedEls = this.clearedIntersectedEls;
|
|
|
+ var el = this.el;
|
|
|
+ var intersectedEls = this.intersectedEls;
|
|
|
+ var newIntersectedEls = this.newIntersectedEls;
|
|
|
+ var objectEls = this.objectEls;
|
|
|
+ var prevCheckTime = this.prevCheckTime;
|
|
|
+ var previousIntersectedEls = this.previousIntersectedEls;
|
|
|
+
|
|
|
+ var closestCenterDifference = void 0;
|
|
|
+ var newClosestEl = void 0;
|
|
|
+ var i = void 0;
|
|
|
+
|
|
|
+ if (!this.data.enabled) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Only check for intersection if interval time has passed.
|
|
|
+ if (prevCheckTime && time - prevCheckTime < this.data.interval) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // Update check time.
|
|
|
+ this.prevCheckTime = time;
|
|
|
+
|
|
|
+ if (this.dirty) {
|
|
|
+ this.refreshObjects();
|
|
|
+ }
|
|
|
+
|
|
|
+ // Update the bounding box to account for rotations and position changes.
|
|
|
+ boundingBox.setFromObject(el.object3D);
|
|
|
+ this.boxMin.copy(boundingBox.min);
|
|
|
+ this.boxMax.copy(boundingBox.max);
|
|
|
+ boundingBox.getCenter(this.boxCenter);
|
|
|
+
|
|
|
+ if (this.data.debug) {
|
|
|
+ this.boxHelper.setFromObject(el.object3D);
|
|
|
+ if (!this.boxHelper.parent) {
|
|
|
+ el.sceneEl.object3D.add(this.boxHelper);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ copyArray(previousIntersectedEls, intersectedEls);
|
|
|
+
|
|
|
+ // Populate intersectedEls array.
|
|
|
+ intersectedEls.length = 0;
|
|
|
+ for (i = 0; i < objectEls.length; i++) {
|
|
|
+ if (objectEls[i] === this.el) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Don't collide with non-visible if flag set.
|
|
|
+ if (!this.data.collideNonVisible && !objectEls[i].getAttribute('visible')) {
|
|
|
+ // Remove box helper if debug flag set and has box helper.
|
|
|
+ if (this.data.debug) {
|
|
|
+ var boxHelper = objectEls[i].object3D.boxHelper;
|
|
|
+ if (boxHelper) {
|
|
|
+ el.sceneEl.object3D.remove(boxHelper);
|
|
|
+ objectEls[i].object3D.boxHelper = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check for interection.
|
|
|
+ if (this.isIntersecting(objectEls[i])) {
|
|
|
+ intersectedEls.push(objectEls[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Get newly intersected entities.
|
|
|
+ newIntersectedEls.length = 0;
|
|
|
+ for (i = 0; i < intersectedEls.length; i++) {
|
|
|
+ if (previousIntersectedEls.indexOf(intersectedEls[i]) === -1) {
|
|
|
+ newIntersectedEls.push(intersectedEls[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Emit cleared events on no longer intersected entities.
|
|
|
+ clearedIntersectedEls.length = 0;
|
|
|
+ for (i = 0; i < previousIntersectedEls.length; i++) {
|
|
|
+ if (intersectedEls.indexOf(previousIntersectedEls[i]) !== -1) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (!previousIntersectedEls[i].hasAttribute('aabb-collider')) {
|
|
|
+ previousIntersectedEls[i].emit('hitend');
|
|
|
+ }
|
|
|
+ clearedIntersectedEls.push(previousIntersectedEls[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Emit events on intersected entities. Do this after the cleared events.
|
|
|
+ for (i = 0; i < newIntersectedEls.length; i++) {
|
|
|
+ if (newIntersectedEls[i] === this.el) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (newIntersectedEls[i].hasAttribute('aabb-collider')) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ newIntersectedEls[i].emit('hitstart');
|
|
|
+ }
|
|
|
+
|
|
|
+ // Calculate closest intersected entity based on centers.
|
|
|
+ for (i = 0; i < intersectedEls.length; i++) {
|
|
|
+ if (intersectedEls[i] === this.el) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ centerDifferenceVec3.copy(intersectedEls[i].object3D.boundingBoxCenter).sub(this.boxCenter);
|
|
|
+ if (closestCenterDifference === undefined || centerDifferenceVec3.length() < closestCenterDifference) {
|
|
|
+ closestCenterDifference = centerDifferenceVec3.length();
|
|
|
+ newClosestEl = intersectedEls[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Emit events for the new closest entity and the old closest entity.
|
|
|
+ if (!intersectedEls.length && this.closestIntersectedEl) {
|
|
|
+ // No intersected entities, clear any closest entity.
|
|
|
+ this.hitClosestClearEventDetail.el = this.closestIntersectedEl;
|
|
|
+ this.closestIntersectedEl.emit('hitclosestclear');
|
|
|
+ this.closestIntersectedEl = null;
|
|
|
+ el.emit('hitclosestclear', this.hitClosestClearEventDetail);
|
|
|
+ } else if (newClosestEl !== this.closestIntersectedEl) {
|
|
|
+ // Clear the previous closest entity.
|
|
|
+ if (this.closestIntersectedEl) {
|
|
|
+ this.hitClosestClearEventDetail.el = this.closestIntersectedEl;
|
|
|
+ this.closestIntersectedEl.emit('hitclosestclear', this.hitClosestClearEventDetail);
|
|
|
+ }
|
|
|
+ if (newClosestEl) {
|
|
|
+ // Emit for the new closest entity.
|
|
|
+ newClosestEl.emit('hitclosest');
|
|
|
+ this.closestIntersectedEl = newClosestEl;
|
|
|
+ this.hitClosestEventDetail.el = newClosestEl;
|
|
|
+ el.emit('hitclosest', this.hitClosestEventDetail);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (clearedIntersectedEls.length) {
|
|
|
+ el.emit('hitend');
|
|
|
+ }
|
|
|
+
|
|
|
+ if (newIntersectedEls.length) {
|
|
|
+ el.emit('hitstart', this.hitStartEventDetail);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * AABB collision detection.
|
|
|
+ * 3D version of https://www.youtube.com/watch?v=ghqD3e37R7E
|
|
|
+ */
|
|
|
+ isIntersecting: function () {
|
|
|
+ var boundingBox = new THREE.Box3();
|
|
|
+
|
|
|
+ return function (el) {
|
|
|
+ var box = void 0;
|
|
|
+
|
|
|
+ // Dynamic, recalculate each tick.
|
|
|
+ if (el.dataset.aabbColliderDynamic) {
|
|
|
+ // Box.
|
|
|
+ boundingBox.setFromObject(el.object3D);
|
|
|
+ box = boundingBox;
|
|
|
+ // Center.
|
|
|
+ el.object3D.boundingBoxCenter = el.object3D.boundingBoxCenter || new THREE.Vector3();
|
|
|
+ box.getCenter(el.object3D.boundingBoxCenter);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Static, reuse box and centers.
|
|
|
+ if (!el.dataset.aabbColliderDynamic) {
|
|
|
+ if (!el.object3D.aabbBox) {
|
|
|
+ // Box.
|
|
|
+ el.object3D.aabbBox = new THREE.Box3().setFromObject(el.object3D);
|
|
|
+ // Center.
|
|
|
+ el.object3D.boundingBoxCenter = new THREE.Vector3();
|
|
|
+ el.object3D.aabbBox.getCenter(el.object3D.boundingBoxCenter);
|
|
|
+ }
|
|
|
+ box = el.object3D.aabbBox;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.data.debug) {
|
|
|
+ if (!el.object3D.boxHelper) {
|
|
|
+ el.object3D.boxHelper = new THREE.BoxHelper(el.object3D, new THREE.Color(Math.random(), Math.random(), Math.random()));
|
|
|
+ el.sceneEl.object3D.add(el.object3D.boxHelper);
|
|
|
+ }
|
|
|
+ el.object3D.boxHelper.setFromObject(el.object3D);
|
|
|
+ }
|
|
|
+
|
|
|
+ var boxMin = box.min;
|
|
|
+ var boxMax = box.max;
|
|
|
+ return this.boxMin.x <= boxMax.x && this.boxMax.x >= boxMin.x && this.boxMin.y <= boxMax.y && this.boxMax.y >= boxMin.y && this.boxMin.z <= boxMax.z && this.boxMax.z >= boxMin.z;
|
|
|
+ };
|
|
|
+ }(),
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Mark the object list as dirty, to be refreshed before next raycast.
|
|
|
+ */
|
|
|
+ setDirty: function setDirty() {
|
|
|
+ this.dirty = true;
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Update list of objects to test for intersection.
|
|
|
+ */
|
|
|
+ refreshObjects: function refreshObjects() {
|
|
|
+ var data = this.data;
|
|
|
+ // If objects not defined, intersect with everything.
|
|
|
+ this.objectEls = data.objects ? this.el.sceneEl.querySelectorAll(data.objects) : this.el.sceneEl.children;
|
|
|
+ this.dirty = false;
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+function copyArray(dest, source) {
|
|
|
+ dest.length = 0;
|
|
|
+ for (var i = 0; i < source.length; i++) {
|
|
|
+ dest[i] = source[i];
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
/***/ })
|
|
|
-/******/ ]);
|
|
|
+/******/ ]);
|
|
|
+});
|