(function (global, factory) { if (typeof define === "function" && define.amd) { define(["exports", "three"], factory); } else if (typeof exports !== "undefined") { factory(exports, require("three")); } else { var mod = { exports: {} }; factory(mod.exports, global.three); global.OBB = mod.exports; } })(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, _three) { "use strict"; Object.defineProperty(_exports, "__esModule", { value: true }); _exports.OBB = void 0; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } // module scope helper variables var a = { c: null, // center u: [new _three.Vector3(), new _three.Vector3(), new _three.Vector3()], // basis vectors e: [] // half width }; var b = { c: null, // center u: [new _three.Vector3(), new _three.Vector3(), new _three.Vector3()], // basis vectors e: [] // half width }; var R = [[], [], []]; var AbsR = [[], [], []]; var t = []; var xAxis = new _three.Vector3(); var yAxis = new _three.Vector3(); var zAxis = new _three.Vector3(); var v1 = new _three.Vector3(); var size = new _three.Vector3(); var closestPoint = new _three.Vector3(); var rotationMatrix = new _three.Matrix3(); var aabb = new _three.Box3(); var matrix = new _three.Matrix4(); var inverse = new _three.Matrix4(); var localRay = new _three.Ray(); // OBB var OBB = /*#__PURE__*/function () { function OBB() { var center = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new _three.Vector3(); var halfSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new _three.Vector3(); var rotation = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : new _three.Matrix3(); _classCallCheck(this, OBB); this.center = center; this.halfSize = halfSize; this.rotation = rotation; } _createClass(OBB, [{ key: "set", value: function set(center, halfSize, rotation) { this.center = center; this.halfSize = halfSize; this.rotation = rotation; return this; } }, { key: "copy", value: function copy(obb) { this.center.copy(obb.center); this.halfSize.copy(obb.halfSize); this.rotation.copy(obb.rotation); return this; } }, { key: "clone", value: function clone() { return new this.constructor().copy(this); } }, { key: "getSize", value: function getSize(result) { return result.copy(this.halfSize).multiplyScalar(2); } /** * Reference: Closest Point on OBB to Point in Real-Time Collision Detection * by Christer Ericson (chapter 5.1.4) */ }, { key: "clampPoint", value: function clampPoint(point, result) { var halfSize = this.halfSize; v1.subVectors(point, this.center); this.rotation.extractBasis(xAxis, yAxis, zAxis); // start at the center position of the OBB result.copy(this.center); // project the target onto the OBB axes and walk towards that point var x = _three.MathUtils.clamp(v1.dot(xAxis), -halfSize.x, halfSize.x); result.add(xAxis.multiplyScalar(x)); var y = _three.MathUtils.clamp(v1.dot(yAxis), -halfSize.y, halfSize.y); result.add(yAxis.multiplyScalar(y)); var z = _three.MathUtils.clamp(v1.dot(zAxis), -halfSize.z, halfSize.z); result.add(zAxis.multiplyScalar(z)); return result; } }, { key: "containsPoint", value: function containsPoint(point) { v1.subVectors(point, this.center); this.rotation.extractBasis(xAxis, yAxis, zAxis); // project v1 onto each axis and check if these points lie inside the OBB return Math.abs(v1.dot(xAxis)) <= this.halfSize.x && Math.abs(v1.dot(yAxis)) <= this.halfSize.y && Math.abs(v1.dot(zAxis)) <= this.halfSize.z; } }, { key: "intersectsBox3", value: function intersectsBox3(box3) { return this.intersectsOBB(obb.fromBox3(box3)); } }, { key: "intersectsSphere", value: function intersectsSphere(sphere) { // find the point on the OBB closest to the sphere center this.clampPoint(sphere.center, closestPoint); // if that point is inside the sphere, the OBB and sphere intersect return closestPoint.distanceToSquared(sphere.center) <= sphere.radius * sphere.radius; } /** * Reference: OBB-OBB Intersection in Real-Time Collision Detection * by Christer Ericson (chapter 4.4.1) * */ }, { key: "intersectsOBB", value: function intersectsOBB(obb) { var epsilon = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Number.EPSILON; // prepare data structures (the code uses the same nomenclature like the reference) a.c = this.center; a.e[0] = this.halfSize.x; a.e[1] = this.halfSize.y; a.e[2] = this.halfSize.z; this.rotation.extractBasis(a.u[0], a.u[1], a.u[2]); b.c = obb.center; b.e[0] = obb.halfSize.x; b.e[1] = obb.halfSize.y; b.e[2] = obb.halfSize.z; obb.rotation.extractBasis(b.u[0], b.u[1], b.u[2]); // compute rotation matrix expressing b in a's coordinate frame for (var i = 0; i < 3; i++) { for (var j = 0; j < 3; j++) { R[i][j] = a.u[i].dot(b.u[j]); } } // compute translation vector v1.subVectors(b.c, a.c); // bring translation into a's coordinate frame t[0] = v1.dot(a.u[0]); t[1] = v1.dot(a.u[1]); t[2] = v1.dot(a.u[2]); // compute common subexpressions. Add in an epsilon term to // counteract arithmetic errors when two edges are parallel and // their cross product is (near) null for (var _i = 0; _i < 3; _i++) { for (var _j = 0; _j < 3; _j++) { AbsR[_i][_j] = Math.abs(R[_i][_j]) + epsilon; } } var ra, rb; // test axes L = A0, L = A1, L = A2 for (var _i2 = 0; _i2 < 3; _i2++) { ra = a.e[_i2]; rb = b.e[0] * AbsR[_i2][0] + b.e[1] * AbsR[_i2][1] + b.e[2] * AbsR[_i2][2]; if (Math.abs(t[_i2]) > ra + rb) return false; } // test axes L = B0, L = B1, L = B2 for (var _i3 = 0; _i3 < 3; _i3++) { ra = a.e[0] * AbsR[0][_i3] + a.e[1] * AbsR[1][_i3] + a.e[2] * AbsR[2][_i3]; rb = b.e[_i3]; if (Math.abs(t[0] * R[0][_i3] + t[1] * R[1][_i3] + t[2] * R[2][_i3]) > ra + rb) return false; } // test axis L = A0 x B0 ra = a.e[1] * AbsR[2][0] + a.e[2] * AbsR[1][0]; rb = b.e[1] * AbsR[0][2] + b.e[2] * AbsR[0][1]; if (Math.abs(t[2] * R[1][0] - t[1] * R[2][0]) > ra + rb) return false; // test axis L = A0 x B1 ra = a.e[1] * AbsR[2][1] + a.e[2] * AbsR[1][1]; rb = b.e[0] * AbsR[0][2] + b.e[2] * AbsR[0][0]; if (Math.abs(t[2] * R[1][1] - t[1] * R[2][1]) > ra + rb) return false; // test axis L = A0 x B2 ra = a.e[1] * AbsR[2][2] + a.e[2] * AbsR[1][2]; rb = b.e[0] * AbsR[0][1] + b.e[1] * AbsR[0][0]; if (Math.abs(t[2] * R[1][2] - t[1] * R[2][2]) > ra + rb) return false; // test axis L = A1 x B0 ra = a.e[0] * AbsR[2][0] + a.e[2] * AbsR[0][0]; rb = b.e[1] * AbsR[1][2] + b.e[2] * AbsR[1][1]; if (Math.abs(t[0] * R[2][0] - t[2] * R[0][0]) > ra + rb) return false; // test axis L = A1 x B1 ra = a.e[0] * AbsR[2][1] + a.e[2] * AbsR[0][1]; rb = b.e[0] * AbsR[1][2] + b.e[2] * AbsR[1][0]; if (Math.abs(t[0] * R[2][1] - t[2] * R[0][1]) > ra + rb) return false; // test axis L = A1 x B2 ra = a.e[0] * AbsR[2][2] + a.e[2] * AbsR[0][2]; rb = b.e[0] * AbsR[1][1] + b.e[1] * AbsR[1][0]; if (Math.abs(t[0] * R[2][2] - t[2] * R[0][2]) > ra + rb) return false; // test axis L = A2 x B0 ra = a.e[0] * AbsR[1][0] + a.e[1] * AbsR[0][0]; rb = b.e[1] * AbsR[2][2] + b.e[2] * AbsR[2][1]; if (Math.abs(t[1] * R[0][0] - t[0] * R[1][0]) > ra + rb) return false; // test axis L = A2 x B1 ra = a.e[0] * AbsR[1][1] + a.e[1] * AbsR[0][1]; rb = b.e[0] * AbsR[2][2] + b.e[2] * AbsR[2][0]; if (Math.abs(t[1] * R[0][1] - t[0] * R[1][1]) > ra + rb) return false; // test axis L = A2 x B2 ra = a.e[0] * AbsR[1][2] + a.e[1] * AbsR[0][2]; rb = b.e[0] * AbsR[2][1] + b.e[1] * AbsR[2][0]; if (Math.abs(t[1] * R[0][2] - t[0] * R[1][2]) > ra + rb) return false; // since no separating axis is found, the OBBs must be intersecting return true; } /** * Reference: Testing Box Against Plane in Real-Time Collision Detection * by Christer Ericson (chapter 5.2.3) */ }, { key: "intersectsPlane", value: function intersectsPlane(plane) { this.rotation.extractBasis(xAxis, yAxis, zAxis); // compute the projection interval radius of this OBB onto L(t) = this->center + t * p.normal; var r = this.halfSize.x * Math.abs(plane.normal.dot(xAxis)) + this.halfSize.y * Math.abs(plane.normal.dot(yAxis)) + this.halfSize.z * Math.abs(plane.normal.dot(zAxis)); // compute distance of the OBB's center from the plane var d = plane.normal.dot(this.center) - plane.constant; // Intersection occurs when distance d falls within [-r,+r] interval return Math.abs(d) <= r; } /** * Performs a ray/OBB intersection test and stores the intersection point * to the given 3D vector. If no intersection is detected, *null* is returned. */ }, { key: "intersectRay", value: function intersectRay(ray, result) { // the idea is to perform the intersection test in the local space // of the OBB. this.getSize(size); aabb.setFromCenterAndSize(v1.set(0, 0, 0), size); // create a 4x4 transformation matrix matrix.setFromMatrix3(this.rotation); matrix.setPosition(this.center); // transform ray to the local space of the OBB inverse.copy(matrix).invert(); localRay.copy(ray).applyMatrix4(inverse); // perform ray <-> AABB intersection test if (localRay.intersectBox(aabb, result)) { // transform the intersection point back to world space return result.applyMatrix4(matrix); } else { return null; } } /** * Performs a ray/OBB intersection test. Returns either true or false if * there is a intersection or not. */ }, { key: "intersectsRay", value: function intersectsRay(ray) { return this.intersectRay(ray, v1) !== null; } }, { key: "fromBox3", value: function fromBox3(box3) { box3.getCenter(this.center); box3.getSize(this.halfSize).multiplyScalar(0.5); this.rotation.identity(); return this; } }, { key: "equals", value: function equals(obb) { return obb.center.equals(this.center) && obb.halfSize.equals(this.halfSize) && obb.rotation.equals(this.rotation); } }, { key: "applyMatrix4", value: function applyMatrix4(matrix) { var e = matrix.elements; var sx = v1.set(e[0], e[1], e[2]).length(); var sy = v1.set(e[4], e[5], e[6]).length(); var sz = v1.set(e[8], e[9], e[10]).length(); var det = matrix.determinant(); if (det < 0) sx = -sx; rotationMatrix.setFromMatrix4(matrix); var invSX = 1 / sx; var invSY = 1 / sy; var invSZ = 1 / sz; rotationMatrix.elements[0] *= invSX; rotationMatrix.elements[1] *= invSX; rotationMatrix.elements[2] *= invSX; rotationMatrix.elements[3] *= invSY; rotationMatrix.elements[4] *= invSY; rotationMatrix.elements[5] *= invSY; rotationMatrix.elements[6] *= invSZ; rotationMatrix.elements[7] *= invSZ; rotationMatrix.elements[8] *= invSZ; this.rotation.multiply(rotationMatrix); this.halfSize.x *= sx; this.halfSize.y *= sy; this.halfSize.z *= sz; v1.setFromMatrixPosition(matrix); this.center.add(v1); return this; } }]); return OBB; }(); _exports.OBB = OBB; var obb = new OBB(); });