import { BackSide, Box3, BufferAttribute, BufferGeometry, ByteType, DataTexture, DoubleSide, FloatType, FrontSide, Group, IntType, Line3, LineBasicMaterial, Matrix3, Matrix4, Mesh, MeshBasicMaterial, NearestFilter, Object3D, Plane, RGBAFormat, RGBAIntegerFormat, RGFormat, RGIntegerFormat, Ray, RedFormat, RedIntegerFormat, ShortType, Sphere, Triangle, UnsignedByteType, UnsignedIntType, UnsignedShortType, Vector2, Vector3, Vector4 } from "/_nuxt/node_modules/.cache/vite/client/deps/chunk-KHL3VXVA.js?v=e4f18c29"; import "/_nuxt/node_modules/.cache/vite/client/deps/chunk-V4OQ3NZ2.js?v=e4f18c29"; // ../../node_modules/three-mesh-bvh/src/core/Constants.js var CENTER = 0; var AVERAGE = 1; var SAH = 2; var NOT_INTERSECTED = 0; var INTERSECTED = 1; var CONTAINED = 2; var TRIANGLE_INTERSECT_COST = 1.25; var TRAVERSAL_COST = 1; var BYTES_PER_NODE = 6 * 4 + 4 + 4; var IS_LEAFNODE_FLAG = 65535; var FLOAT32_EPSILON = Math.pow(2, -24); // ../../node_modules/three-mesh-bvh/src/core/MeshBVHNode.js var MeshBVHNode = class { constructor() { } }; // ../../node_modules/three-mesh-bvh/src/utils/ArrayBoxUtilities.js function arrayToBox(nodeIndex32, array, target) { target.min.x = array[nodeIndex32]; target.min.y = array[nodeIndex32 + 1]; target.min.z = array[nodeIndex32 + 2]; target.max.x = array[nodeIndex32 + 3]; target.max.y = array[nodeIndex32 + 4]; target.max.z = array[nodeIndex32 + 5]; return target; } function getLongestEdgeIndex(bounds) { let splitDimIdx = -1; let splitDist = -Infinity; for (let i = 0; i < 3; i++) { const dist = bounds[i + 3] - bounds[i]; if (dist > splitDist) { splitDist = dist; splitDimIdx = i; } } return splitDimIdx; } function copyBounds(source, target) { target.set(source); } function unionBounds(a, b, target) { let aVal, bVal; for (let d = 0; d < 3; d++) { const d3 = d + 3; aVal = a[d]; bVal = b[d]; target[d] = aVal < bVal ? aVal : bVal; aVal = a[d3]; bVal = b[d3]; target[d3] = aVal > bVal ? aVal : bVal; } } function expandByTriangleBounds(startIndex, triangleBounds, bounds) { for (let d = 0; d < 3; d++) { const tCenter = triangleBounds[startIndex + 2 * d]; const tHalf = triangleBounds[startIndex + 2 * d + 1]; const tMin = tCenter - tHalf; const tMax = tCenter + tHalf; if (tMin < bounds[d]) { bounds[d] = tMin; } if (tMax > bounds[d + 3]) { bounds[d + 3] = tMax; } } } function computeSurfaceArea(bounds) { const d0 = bounds[3] - bounds[0]; const d1 = bounds[4] - bounds[1]; const d2 = bounds[5] - bounds[2]; return 2 * (d0 * d1 + d1 * d2 + d2 * d0); } // ../../node_modules/three-mesh-bvh/src/core/buildFunctions.js function ensureIndex(geo, options) { if (!geo.index) { const vertexCount = geo.attributes.position.count; const BufferConstructor = options.useSharedArrayBuffer ? SharedArrayBuffer : ArrayBuffer; let index; if (vertexCount > 65535) { index = new Uint32Array(new BufferConstructor(4 * vertexCount)); } else { index = new Uint16Array(new BufferConstructor(2 * vertexCount)); } geo.setIndex(new BufferAttribute(index, 1)); for (let i = 0; i < vertexCount; i++) { index[i] = i; } } } function getRootIndexRanges(geo) { if (!geo.groups || !geo.groups.length) { return [{ offset: 0, count: geo.index.count / 3 }]; } const ranges = []; const rangeBoundaries = /* @__PURE__ */ new Set(); for (const group of geo.groups) { rangeBoundaries.add(group.start); rangeBoundaries.add(group.start + group.count); } const sortedBoundaries = Array.from(rangeBoundaries.values()).sort((a, b) => a - b); for (let i = 0; i < sortedBoundaries.length - 1; i++) { const start = sortedBoundaries[i], end = sortedBoundaries[i + 1]; ranges.push({ offset: start / 3, count: (end - start) / 3 }); } return ranges; } function getBounds(triangleBounds, offset, count, target, centroidTarget = null) { let minx = Infinity; let miny = Infinity; let minz = Infinity; let maxx = -Infinity; let maxy = -Infinity; let maxz = -Infinity; let cminx = Infinity; let cminy = Infinity; let cminz = Infinity; let cmaxx = -Infinity; let cmaxy = -Infinity; let cmaxz = -Infinity; const includeCentroid = centroidTarget !== null; for (let i = offset * 6, end = (offset + count) * 6; i < end; i += 6) { const cx = triangleBounds[i + 0]; const hx = triangleBounds[i + 1]; const lx = cx - hx; const rx = cx + hx; if (lx < minx) minx = lx; if (rx > maxx) maxx = rx; if (includeCentroid && cx < cminx) cminx = cx; if (includeCentroid && cx > cmaxx) cmaxx = cx; const cy = triangleBounds[i + 2]; const hy = triangleBounds[i + 3]; const ly = cy - hy; const ry = cy + hy; if (ly < miny) miny = ly; if (ry > maxy) maxy = ry; if (includeCentroid && cy < cminy) cminy = cy; if (includeCentroid && cy > cmaxy) cmaxy = cy; const cz = triangleBounds[i + 4]; const hz = triangleBounds[i + 5]; const lz = cz - hz; const rz = cz + hz; if (lz < minz) minz = lz; if (rz > maxz) maxz = rz; if (includeCentroid && cz < cminz) cminz = cz; if (includeCentroid && cz > cmaxz) cmaxz = cz; } target[0] = minx; target[1] = miny; target[2] = minz; target[3] = maxx; target[4] = maxy; target[5] = maxz; if (includeCentroid) { centroidTarget[0] = cminx; centroidTarget[1] = cminy; centroidTarget[2] = cminz; centroidTarget[3] = cmaxx; centroidTarget[4] = cmaxy; centroidTarget[5] = cmaxz; } } function getCentroidBounds(triangleBounds, offset, count, centroidTarget) { let cminx = Infinity; let cminy = Infinity; let cminz = Infinity; let cmaxx = -Infinity; let cmaxy = -Infinity; let cmaxz = -Infinity; for (let i = offset * 6, end = (offset + count) * 6; i < end; i += 6) { const cx = triangleBounds[i + 0]; if (cx < cminx) cminx = cx; if (cx > cmaxx) cmaxx = cx; const cy = triangleBounds[i + 2]; if (cy < cminy) cminy = cy; if (cy > cmaxy) cmaxy = cy; const cz = triangleBounds[i + 4]; if (cz < cminz) cminz = cz; if (cz > cmaxz) cmaxz = cz; } centroidTarget[0] = cminx; centroidTarget[1] = cminy; centroidTarget[2] = cminz; centroidTarget[3] = cmaxx; centroidTarget[4] = cmaxy; centroidTarget[5] = cmaxz; } function partition(index, triangleBounds, offset, count, split) { let left = offset; let right = offset + count - 1; const pos = split.pos; const axisOffset = split.axis * 2; while (true) { while (left <= right && triangleBounds[left * 6 + axisOffset] < pos) { left++; } while (left <= right && triangleBounds[right * 6 + axisOffset] >= pos) { right--; } if (left < right) { for (let i = 0; i < 3; i++) { let t0 = index[left * 3 + i]; index[left * 3 + i] = index[right * 3 + i]; index[right * 3 + i] = t0; let t1 = triangleBounds[left * 6 + i * 2 + 0]; triangleBounds[left * 6 + i * 2 + 0] = triangleBounds[right * 6 + i * 2 + 0]; triangleBounds[right * 6 + i * 2 + 0] = t1; let t2 = triangleBounds[left * 6 + i * 2 + 1]; triangleBounds[left * 6 + i * 2 + 1] = triangleBounds[right * 6 + i * 2 + 1]; triangleBounds[right * 6 + i * 2 + 1] = t2; } left++; right--; } else { return left; } } } var BIN_COUNT = 32; var binsSort = (a, b) => a.candidate - b.candidate; var sahBins = new Array(BIN_COUNT).fill().map(() => { return { count: 0, bounds: new Float32Array(6), rightCacheBounds: new Float32Array(6), leftCacheBounds: new Float32Array(6), candidate: 0 }; }); var leftBounds = new Float32Array(6); function getOptimalSplit(nodeBoundingData, centroidBoundingData, triangleBounds, offset, count, strategy) { let axis = -1; let pos = 0; if (strategy === CENTER) { axis = getLongestEdgeIndex(centroidBoundingData); if (axis !== -1) { pos = (centroidBoundingData[axis] + centroidBoundingData[axis + 3]) / 2; } } else if (strategy === AVERAGE) { axis = getLongestEdgeIndex(nodeBoundingData); if (axis !== -1) { pos = getAverage(triangleBounds, offset, count, axis); } } else if (strategy === SAH) { const rootSurfaceArea = computeSurfaceArea(nodeBoundingData); let bestCost = TRIANGLE_INTERSECT_COST * count; const cStart = offset * 6; const cEnd = (offset + count) * 6; for (let a = 0; a < 3; a++) { const axisLeft = centroidBoundingData[a]; const axisRight = centroidBoundingData[a + 3]; const axisLength = axisRight - axisLeft; const binWidth = axisLength / BIN_COUNT; if (count < BIN_COUNT / 4) { const truncatedBins = [...sahBins]; truncatedBins.length = count; let b = 0; for (let c = cStart; c < cEnd; c += 6, b++) { const bin = truncatedBins[b]; bin.candidate = triangleBounds[c + 2 * a]; bin.count = 0; const { bounds, leftCacheBounds, rightCacheBounds } = bin; for (let d = 0; d < 3; d++) { rightCacheBounds[d] = Infinity; rightCacheBounds[d + 3] = -Infinity; leftCacheBounds[d] = Infinity; leftCacheBounds[d + 3] = -Infinity; bounds[d] = Infinity; bounds[d + 3] = -Infinity; } expandByTriangleBounds(c, triangleBounds, bounds); } truncatedBins.sort(binsSort); let splitCount = count; for (let bi = 0; bi < splitCount; bi++) { const bin = truncatedBins[bi]; while (bi + 1 < splitCount && truncatedBins[bi + 1].candidate === bin.candidate) { truncatedBins.splice(bi + 1, 1); splitCount--; } } for (let c = cStart; c < cEnd; c += 6) { const center = triangleBounds[c + 2 * a]; for (let bi = 0; bi < splitCount; bi++) { const bin = truncatedBins[bi]; if (center >= bin.candidate) { expandByTriangleBounds(c, triangleBounds, bin.rightCacheBounds); } else { expandByTriangleBounds(c, triangleBounds, bin.leftCacheBounds); bin.count++; } } } for (let bi = 0; bi < splitCount; bi++) { const bin = truncatedBins[bi]; const leftCount = bin.count; const rightCount = count - bin.count; const leftBounds2 = bin.leftCacheBounds; const rightBounds = bin.rightCacheBounds; let leftProb = 0; if (leftCount !== 0) { leftProb = computeSurfaceArea(leftBounds2) / rootSurfaceArea; } let rightProb = 0; if (rightCount !== 0) { rightProb = computeSurfaceArea(rightBounds) / rootSurfaceArea; } const cost = TRAVERSAL_COST + TRIANGLE_INTERSECT_COST * (leftProb * leftCount + rightProb * rightCount); if (cost < bestCost) { axis = a; bestCost = cost; pos = bin.candidate; } } } else { for (let i = 0; i < BIN_COUNT; i++) { const bin = sahBins[i]; bin.count = 0; bin.candidate = axisLeft + binWidth + i * binWidth; const bounds = bin.bounds; for (let d = 0; d < 3; d++) { bounds[d] = Infinity; bounds[d + 3] = -Infinity; } } for (let c = cStart; c < cEnd; c += 6) { const triCenter = triangleBounds[c + 2 * a]; const relativeCenter = triCenter - axisLeft; let binIndex = ~~(relativeCenter / binWidth); if (binIndex >= BIN_COUNT) binIndex = BIN_COUNT - 1; const bin = sahBins[binIndex]; bin.count++; expandByTriangleBounds(c, triangleBounds, bin.bounds); } const lastBin = sahBins[BIN_COUNT - 1]; copyBounds(lastBin.bounds, lastBin.rightCacheBounds); for (let i = BIN_COUNT - 2; i >= 0; i--) { const bin = sahBins[i]; const nextBin = sahBins[i + 1]; unionBounds(bin.bounds, nextBin.rightCacheBounds, bin.rightCacheBounds); } let leftCount = 0; for (let i = 0; i < BIN_COUNT - 1; i++) { const bin = sahBins[i]; const binCount = bin.count; const bounds = bin.bounds; const nextBin = sahBins[i + 1]; const rightBounds = nextBin.rightCacheBounds; if (binCount !== 0) { if (leftCount === 0) { copyBounds(bounds, leftBounds); } else { unionBounds(bounds, leftBounds, leftBounds); } } leftCount += binCount; let leftProb = 0; let rightProb = 0; if (leftCount !== 0) { leftProb = computeSurfaceArea(leftBounds) / rootSurfaceArea; } const rightCount = count - leftCount; if (rightCount !== 0) { rightProb = computeSurfaceArea(rightBounds) / rootSurfaceArea; } const cost = TRAVERSAL_COST + TRIANGLE_INTERSECT_COST * (leftProb * leftCount + rightProb * rightCount); if (cost < bestCost) { axis = a; bestCost = cost; pos = bin.candidate; } } } } } else { console.warn(`MeshBVH: Invalid build strategy value ${strategy} used.`); } return { axis, pos }; } function getAverage(triangleBounds, offset, count, axis) { let avg = 0; for (let i = offset, end = offset + count; i < end; i++) { avg += triangleBounds[i * 6 + axis * 2]; } return avg / count; } function computeTriangleBounds(geo, fullBounds) { const posAttr = geo.attributes.position; const index = geo.index.array; const triCount = index.length / 3; const triangleBounds = new Float32Array(triCount * 6); const normalized = posAttr.normalized; const posArr = posAttr.array; const bufferOffset = posAttr.offset || 0; let stride = 3; if (posAttr.isInterleavedBufferAttribute) { stride = posAttr.data.stride; } const getters = ["getX", "getY", "getZ"]; for (let tri = 0; tri < triCount; tri++) { const tri3 = tri * 3; const tri6 = tri * 6; let ai, bi, ci; if (normalized) { ai = index[tri3 + 0]; bi = index[tri3 + 1]; ci = index[tri3 + 2]; } else { ai = index[tri3 + 0] * stride + bufferOffset; bi = index[tri3 + 1] * stride + bufferOffset; ci = index[tri3 + 2] * stride + bufferOffset; } for (let el = 0; el < 3; el++) { let a, b, c; if (normalized) { a = posAttr[getters[el]](ai); b = posAttr[getters[el]](bi); c = posAttr[getters[el]](ci); } else { a = posArr[ai + el]; b = posArr[bi + el]; c = posArr[ci + el]; } let min = a; if (b < min) min = b; if (c < min) min = c; let max = a; if (b > max) max = b; if (c > max) max = c; const halfExtents = (max - min) / 2; const el2 = el * 2; triangleBounds[tri6 + el2 + 0] = min + halfExtents; triangleBounds[tri6 + el2 + 1] = halfExtents + (Math.abs(min) + halfExtents) * FLOAT32_EPSILON; if (min < fullBounds[el]) fullBounds[el] = min; if (max > fullBounds[el + 3]) fullBounds[el + 3] = max; } } return triangleBounds; } function buildTree(geo, options) { function triggerProgress(trianglesProcessed) { if (onProgress) { onProgress(trianglesProcessed / totalTriangles); } } function splitNode(node, offset, count, centroidBoundingData = null, depth = 0) { if (!reachedMaxDepth && depth >= maxDepth) { reachedMaxDepth = true; if (verbose) { console.warn(`MeshBVH: Max depth of ${maxDepth} reached when generating BVH. Consider increasing maxDepth.`); console.warn(geo); } } if (count <= maxLeafTris || depth >= maxDepth) { triggerProgress(offset + count); node.offset = offset; node.count = count; return node; } const split = getOptimalSplit(node.boundingData, centroidBoundingData, triangleBounds, offset, count, strategy); if (split.axis === -1) { triggerProgress(offset + count); node.offset = offset; node.count = count; return node; } const splitOffset = partition(indexArray, triangleBounds, offset, count, split); if (splitOffset === offset || splitOffset === offset + count) { triggerProgress(offset + count); node.offset = offset; node.count = count; } else { node.splitAxis = split.axis; const left = new MeshBVHNode(); const lstart = offset; const lcount = splitOffset - offset; node.left = left; left.boundingData = new Float32Array(6); getBounds(triangleBounds, lstart, lcount, left.boundingData, cacheCentroidBoundingData); splitNode(left, lstart, lcount, cacheCentroidBoundingData, depth + 1); const right = new MeshBVHNode(); const rstart = splitOffset; const rcount = count - lcount; node.right = right; right.boundingData = new Float32Array(6); getBounds(triangleBounds, rstart, rcount, right.boundingData, cacheCentroidBoundingData); splitNode(right, rstart, rcount, cacheCentroidBoundingData, depth + 1); } return node; } ensureIndex(geo, options); const fullBounds = new Float32Array(6); const cacheCentroidBoundingData = new Float32Array(6); const triangleBounds = computeTriangleBounds(geo, fullBounds); const indexArray = geo.index.array; const maxDepth = options.maxDepth; const verbose = options.verbose; const maxLeafTris = options.maxLeafTris; const strategy = options.strategy; const onProgress = options.onProgress; const totalTriangles = geo.index.count / 3; let reachedMaxDepth = false; const roots = []; const ranges = getRootIndexRanges(geo); if (ranges.length === 1) { const range = ranges[0]; const root = new MeshBVHNode(); root.boundingData = fullBounds; getCentroidBounds(triangleBounds, range.offset, range.count, cacheCentroidBoundingData); splitNode(root, range.offset, range.count, cacheCentroidBoundingData); roots.push(root); } else { for (let range of ranges) { const root = new MeshBVHNode(); root.boundingData = new Float32Array(6); getBounds(triangleBounds, range.offset, range.count, root.boundingData, cacheCentroidBoundingData); splitNode(root, range.offset, range.count, cacheCentroidBoundingData); roots.push(root); } } return roots; } function buildPackedTree(geo, options) { const roots = buildTree(geo, options); let float32Array; let uint32Array; let uint16Array; const packedRoots = []; const BufferConstructor = options.useSharedArrayBuffer ? SharedArrayBuffer : ArrayBuffer; for (let i = 0; i < roots.length; i++) { const root = roots[i]; let nodeCount = countNodes(root); const buffer = new BufferConstructor(BYTES_PER_NODE * nodeCount); float32Array = new Float32Array(buffer); uint32Array = new Uint32Array(buffer); uint16Array = new Uint16Array(buffer); populateBuffer(0, root); packedRoots.push(buffer); } return packedRoots; function countNodes(node) { if (node.count) { return 1; } else { return 1 + countNodes(node.left) + countNodes(node.right); } } function populateBuffer(byteOffset, node) { const stride4Offset = byteOffset / 4; const stride2Offset = byteOffset / 2; const isLeaf = !!node.count; const boundingData = node.boundingData; for (let i = 0; i < 6; i++) { float32Array[stride4Offset + i] = boundingData[i]; } if (isLeaf) { const offset = node.offset; const count = node.count; uint32Array[stride4Offset + 6] = offset; uint16Array[stride2Offset + 14] = count; uint16Array[stride2Offset + 15] = IS_LEAFNODE_FLAG; return byteOffset + BYTES_PER_NODE; } else { const left = node.left; const right = node.right; const splitAxis = node.splitAxis; let nextUnusedPointer; nextUnusedPointer = populateBuffer(byteOffset + BYTES_PER_NODE, left); if (nextUnusedPointer / 4 > Math.pow(2, 32)) { throw new Error("MeshBVH: Cannot store child pointer greater than 32 bits."); } uint32Array[stride4Offset + 6] = nextUnusedPointer / 4; nextUnusedPointer = populateBuffer(nextUnusedPointer, right); uint32Array[stride4Offset + 7] = splitAxis; return nextUnusedPointer; } } } // ../../node_modules/three-mesh-bvh/src/math/SeparatingAxisBounds.js var SeparatingAxisBounds = class { constructor() { this.min = Infinity; this.max = -Infinity; } setFromPointsField(points, field) { let min = Infinity; let max = -Infinity; for (let i = 0, l = points.length; i < l; i++) { const p = points[i]; const val = p[field]; min = val < min ? val : min; max = val > max ? val : max; } this.min = min; this.max = max; } setFromPoints(axis, points) { let min = Infinity; let max = -Infinity; for (let i = 0, l = points.length; i < l; i++) { const p = points[i]; const val = axis.dot(p); min = val < min ? val : min; max = val > max ? val : max; } this.min = min; this.max = max; } isSeparated(other) { return this.min > other.max || other.min > this.max; } }; SeparatingAxisBounds.prototype.setFromBox = function() { const p = new Vector3(); return function setFromBox(axis, box) { const boxMin = box.min; const boxMax = box.max; let min = Infinity; let max = -Infinity; for (let x = 0; x <= 1; x++) { for (let y = 0; y <= 1; y++) { for (let z = 0; z <= 1; z++) { p.x = boxMin.x * x + boxMax.x * (1 - x); p.y = boxMin.y * y + boxMax.y * (1 - y); p.z = boxMin.z * z + boxMax.z * (1 - z); const val = axis.dot(p); min = Math.min(val, min); max = Math.max(val, max); } } } this.min = min; this.max = max; }; }(); var areIntersecting = function() { const cacheSatBounds = new SeparatingAxisBounds(); return function areIntersecting2(shape1, shape2) { const points1 = shape1.points; const satAxes1 = shape1.satAxes; const satBounds1 = shape1.satBounds; const points2 = shape2.points; const satAxes2 = shape2.satAxes; const satBounds2 = shape2.satBounds; for (let i = 0; i < 3; i++) { const sb = satBounds1[i]; const sa = satAxes1[i]; cacheSatBounds.setFromPoints(sa, points2); if (sb.isSeparated(cacheSatBounds)) return false; } for (let i = 0; i < 3; i++) { const sb = satBounds2[i]; const sa = satAxes2[i]; cacheSatBounds.setFromPoints(sa, points1); if (sb.isSeparated(cacheSatBounds)) return false; } }; }(); // ../../node_modules/three-mesh-bvh/src/math/MathUtilities.js var closestPointLineToLine = function() { const dir1 = new Vector3(); const dir2 = new Vector3(); const v02 = new Vector3(); return function closestPointLineToLine2(l1, l2, result) { const v0 = l1.start; const v10 = dir1; const v2 = l2.start; const v32 = dir2; v02.subVectors(v0, v2); dir1.subVectors(l1.end, l1.start); dir2.subVectors(l2.end, l2.start); const d0232 = v02.dot(v32); const d3210 = v32.dot(v10); const d3232 = v32.dot(v32); const d0210 = v02.dot(v10); const d1010 = v10.dot(v10); const denom = d1010 * d3232 - d3210 * d3210; let d, d2; if (denom !== 0) { d = (d0232 * d3210 - d0210 * d3232) / denom; } else { d = 0; } d2 = (d0232 + d * d3210) / d3232; result.x = d; result.y = d2; }; }(); var closestPointsSegmentToSegment = function() { const paramResult = new Vector2(); const temp12 = new Vector3(); const temp22 = new Vector3(); return function closestPointsSegmentToSegment2(l1, l2, target1, target2) { closestPointLineToLine(l1, l2, paramResult); let d = paramResult.x; let d2 = paramResult.y; if (d >= 0 && d <= 1 && d2 >= 0 && d2 <= 1) { l1.at(d, target1); l2.at(d2, target2); return; } else if (d >= 0 && d <= 1) { if (d2 < 0) { l2.at(0, target2); } else { l2.at(1, target2); } l1.closestPointToPoint(target2, true, target1); return; } else if (d2 >= 0 && d2 <= 1) { if (d < 0) { l1.at(0, target1); } else { l1.at(1, target1); } l2.closestPointToPoint(target1, true, target2); return; } else { let p; if (d < 0) { p = l1.start; } else { p = l1.end; } let p2; if (d2 < 0) { p2 = l2.start; } else { p2 = l2.end; } const closestPoint = temp12; const closestPoint2 = temp22; l1.closestPointToPoint(p2, true, temp12); l2.closestPointToPoint(p, true, temp22); if (closestPoint.distanceToSquared(p2) <= closestPoint2.distanceToSquared(p)) { target1.copy(closestPoint); target2.copy(p2); return; } else { target1.copy(p); target2.copy(closestPoint2); return; } } }; }(); var sphereIntersectTriangle = function() { const closestPointTemp = new Vector3(); const projectedPointTemp = new Vector3(); const planeTemp = new Plane(); const lineTemp = new Line3(); return function sphereIntersectTriangle2(sphere, triangle) { const { radius, center } = sphere; const { a, b, c } = triangle; lineTemp.start = a; lineTemp.end = b; const closestPoint1 = lineTemp.closestPointToPoint(center, true, closestPointTemp); if (closestPoint1.distanceTo(center) <= radius) return true; lineTemp.start = a; lineTemp.end = c; const closestPoint2 = lineTemp.closestPointToPoint(center, true, closestPointTemp); if (closestPoint2.distanceTo(center) <= radius) return true; lineTemp.start = b; lineTemp.end = c; const closestPoint3 = lineTemp.closestPointToPoint(center, true, closestPointTemp); if (closestPoint3.distanceTo(center) <= radius) return true; const plane = triangle.getPlane(planeTemp); const dp = Math.abs(plane.distanceToPoint(center)); if (dp <= radius) { const pp = plane.projectPoint(center, projectedPointTemp); const cp = triangle.containsPoint(pp); if (cp) return true; } return false; }; }(); // ../../node_modules/three-mesh-bvh/src/math/ExtendedTriangle.js var DIST_EPSILON = 1e-15; function isNearZero(value) { return Math.abs(value) < DIST_EPSILON; } var ExtendedTriangle = class extends Triangle { constructor(...args) { super(...args); this.isExtendedTriangle = true; this.satAxes = new Array(4).fill().map(() => new Vector3()); this.satBounds = new Array(4).fill().map(() => new SeparatingAxisBounds()); this.points = [this.a, this.b, this.c]; this.sphere = new Sphere(); this.plane = new Plane(); this.needsUpdate = true; } intersectsSphere(sphere) { return sphereIntersectTriangle(sphere, this); } update() { const a = this.a; const b = this.b; const c = this.c; const points = this.points; const satAxes = this.satAxes; const satBounds = this.satBounds; const axis0 = satAxes[0]; const sab0 = satBounds[0]; this.getNormal(axis0); sab0.setFromPoints(axis0, points); const axis1 = satAxes[1]; const sab1 = satBounds[1]; axis1.subVectors(a, b); sab1.setFromPoints(axis1, points); const axis2 = satAxes[2]; const sab2 = satBounds[2]; axis2.subVectors(b, c); sab2.setFromPoints(axis2, points); const axis3 = satAxes[3]; const sab3 = satBounds[3]; axis3.subVectors(c, a); sab3.setFromPoints(axis3, points); this.sphere.setFromPoints(this.points); this.plane.setFromNormalAndCoplanarPoint(axis0, a); this.needsUpdate = false; } }; ExtendedTriangle.prototype.closestPointToSegment = function() { const point1 = new Vector3(); const point2 = new Vector3(); const edge = new Line3(); return function distanceToSegment(segment, target1 = null, target2 = null) { const { start, end } = segment; const points = this.points; let distSq; let closestDistanceSq = Infinity; for (let i = 0; i < 3; i++) { const nexti = (i + 1) % 3; edge.start.copy(points[i]); edge.end.copy(points[nexti]); closestPointsSegmentToSegment(edge, segment, point1, point2); distSq = point1.distanceToSquared(point2); if (distSq < closestDistanceSq) { closestDistanceSq = distSq; if (target1) target1.copy(point1); if (target2) target2.copy(point2); } } this.closestPointToPoint(start, point1); distSq = start.distanceToSquared(point1); if (distSq < closestDistanceSq) { closestDistanceSq = distSq; if (target1) target1.copy(point1); if (target2) target2.copy(start); } this.closestPointToPoint(end, point1); distSq = end.distanceToSquared(point1); if (distSq < closestDistanceSq) { closestDistanceSq = distSq; if (target1) target1.copy(point1); if (target2) target2.copy(end); } return Math.sqrt(closestDistanceSq); }; }(); ExtendedTriangle.prototype.intersectsTriangle = function() { const saTri2 = new ExtendedTriangle(); const arr1 = new Array(3); const arr2 = new Array(3); const cachedSatBounds = new SeparatingAxisBounds(); const cachedSatBounds2 = new SeparatingAxisBounds(); const cachedAxis = new Vector3(); const dir1 = new Vector3(); const dir2 = new Vector3(); const tempDir = new Vector3(); const edge = new Line3(); const edge1 = new Line3(); const edge2 = new Line3(); return function intersectsTriangle(other, target = null) { if (this.needsUpdate) { this.update(); } if (!other.isExtendedTriangle) { saTri2.copy(other); saTri2.update(); other = saTri2; } else if (other.needsUpdate) { other.update(); } const plane1 = this.plane; const plane2 = other.plane; if (Math.abs(plane1.normal.dot(plane2.normal)) > 1 - 1e-10) { const satBounds1 = this.satBounds; const satAxes1 = this.satAxes; arr2[0] = other.a; arr2[1] = other.b; arr2[2] = other.c; for (let i = 0; i < 4; i++) { const sb = satBounds1[i]; const sa = satAxes1[i]; cachedSatBounds.setFromPoints(sa, arr2); if (sb.isSeparated(cachedSatBounds)) return false; } const satBounds2 = other.satBounds; const satAxes2 = other.satAxes; arr1[0] = this.a; arr1[1] = this.b; arr1[2] = this.c; for (let i = 0; i < 4; i++) { const sb = satBounds2[i]; const sa = satAxes2[i]; cachedSatBounds.setFromPoints(sa, arr1); if (sb.isSeparated(cachedSatBounds)) return false; } for (let i = 0; i < 4; i++) { const sa1 = satAxes1[i]; for (let i2 = 0; i2 < 4; i2++) { const sa2 = satAxes2[i2]; cachedAxis.crossVectors(sa1, sa2); cachedSatBounds.setFromPoints(cachedAxis, arr1); cachedSatBounds2.setFromPoints(cachedAxis, arr2); if (cachedSatBounds.isSeparated(cachedSatBounds2)) return false; } } if (target) { console.warn("ExtendedTriangle.intersectsTriangle: Triangles are coplanar which does not support an output edge. Setting edge to 0, 0, 0."); target.start.set(0, 0, 0); target.end.set(0, 0, 0); } return true; } else { const points1 = this.points; let found1 = false; let count1 = 0; for (let i = 0; i < 3; i++) { const p = points1[i]; const pNext = points1[(i + 1) % 3]; edge.start.copy(p); edge.end.copy(pNext); edge.delta(dir1); const targetPoint = found1 ? edge1.start : edge1.end; const startIntersects = isNearZero(plane2.distanceToPoint(p)); if (isNearZero(plane2.normal.dot(dir1)) && startIntersects) { edge1.copy(edge); count1 = 2; break; } const doesIntersect = plane2.intersectLine(edge, targetPoint) || startIntersects; if (doesIntersect && !isNearZero(targetPoint.distanceTo(pNext))) { count1++; if (found1) { break; } found1 = true; } } if (count1 === 1 && this.containsPoint(edge1.end)) { if (target) { target.start.copy(edge1.end); target.end.copy(edge1.end); } return true; } else if (count1 !== 2) { return false; } const points2 = other.points; let found2 = false; let count2 = 0; for (let i = 0; i < 3; i++) { const p = points2[i]; const pNext = points2[(i + 1) % 3]; edge.start.copy(p); edge.end.copy(pNext); edge.delta(dir2); const targetPoint = found2 ? edge2.start : edge2.end; const startIntersects = isNearZero(plane1.distanceToPoint(p)); if (isNearZero(plane1.normal.dot(dir2)) && startIntersects) { edge2.copy(edge); count2 = 2; break; } const doesIntersect = plane1.intersectLine(edge, targetPoint) || startIntersects; if (doesIntersect && !isNearZero(targetPoint.distanceTo(pNext))) { count2++; if (found2) { break; } found2 = true; } } if (count2 === 1 && this.containsPoint(edge2.end)) { if (target) { target.start.copy(edge2.end); target.end.copy(edge2.end); } return true; } else if (count2 !== 2) { return false; } edge1.delta(dir1); edge2.delta(dir2); if (dir1.dot(dir2) < 0) { let tmp = edge2.start; edge2.start = edge2.end; edge2.end = tmp; } const s1 = edge1.start.dot(dir1); const e1 = edge1.end.dot(dir1); const s2 = edge2.start.dot(dir1); const e2 = edge2.end.dot(dir1); const separated1 = e1 < s2; const separated2 = s1 < e2; if (s1 !== e2 && s2 !== e1 && separated1 === separated2) { return false; } if (target) { tempDir.subVectors(edge1.start, edge2.start); if (tempDir.dot(dir1) > 0) { target.start.copy(edge1.start); } else { target.start.copy(edge2.start); } tempDir.subVectors(edge1.end, edge2.end); if (tempDir.dot(dir1) < 0) { target.end.copy(edge1.end); } else { target.end.copy(edge2.end); } } return true; } }; }(); ExtendedTriangle.prototype.distanceToPoint = function() { const target = new Vector3(); return function distanceToPoint(point) { this.closestPointToPoint(point, target); return point.distanceTo(target); }; }(); ExtendedTriangle.prototype.distanceToTriangle = function() { const point = new Vector3(); const point2 = new Vector3(); const cornerFields = ["a", "b", "c"]; const line1 = new Line3(); const line2 = new Line3(); return function distanceToTriangle(other, target1 = null, target2 = null) { const lineTarget = target1 || target2 ? line1 : null; if (this.intersectsTriangle(other, lineTarget)) { if (target1 || target2) { if (target1) lineTarget.getCenter(target1); if (target2) lineTarget.getCenter(target2); } return 0; } let closestDistanceSq = Infinity; for (let i = 0; i < 3; i++) { let dist; const field = cornerFields[i]; const otherVec = other[field]; this.closestPointToPoint(otherVec, point); dist = otherVec.distanceToSquared(point); if (dist < closestDistanceSq) { closestDistanceSq = dist; if (target1) target1.copy(point); if (target2) target2.copy(otherVec); } const thisVec = this[field]; other.closestPointToPoint(thisVec, point); dist = thisVec.distanceToSquared(point); if (dist < closestDistanceSq) { closestDistanceSq = dist; if (target1) target1.copy(thisVec); if (target2) target2.copy(point); } } for (let i = 0; i < 3; i++) { const f11 = cornerFields[i]; const f12 = cornerFields[(i + 1) % 3]; line1.set(this[f11], this[f12]); for (let i2 = 0; i2 < 3; i2++) { const f21 = cornerFields[i2]; const f22 = cornerFields[(i2 + 1) % 3]; line2.set(other[f21], other[f22]); closestPointsSegmentToSegment(line1, line2, point, point2); const dist = point.distanceToSquared(point2); if (dist < closestDistanceSq) { closestDistanceSq = dist; if (target1) target1.copy(point); if (target2) target2.copy(point2); } } } return Math.sqrt(closestDistanceSq); }; }(); // ../../node_modules/three-mesh-bvh/src/math/OrientedBox.js var OrientedBox = class { constructor(min, max, matrix) { this.isOrientedBox = true; this.min = new Vector3(); this.max = new Vector3(); this.matrix = new Matrix4(); this.invMatrix = new Matrix4(); this.points = new Array(8).fill().map(() => new Vector3()); this.satAxes = new Array(3).fill().map(() => new Vector3()); this.satBounds = new Array(3).fill().map(() => new SeparatingAxisBounds()); this.alignedSatBounds = new Array(3).fill().map(() => new SeparatingAxisBounds()); this.needsUpdate = false; if (min) this.min.copy(min); if (max) this.max.copy(max); if (matrix) this.matrix.copy(matrix); } set(min, max, matrix) { this.min.copy(min); this.max.copy(max); this.matrix.copy(matrix); this.needsUpdate = true; } copy(other) { this.min.copy(other.min); this.max.copy(other.max); this.matrix.copy(other.matrix); this.needsUpdate = true; } }; OrientedBox.prototype.update = /* @__PURE__ */ function() { return function update() { const matrix = this.matrix; const min = this.min; const max = this.max; const points = this.points; for (let x = 0; x <= 1; x++) { for (let y = 0; y <= 1; y++) { for (let z = 0; z <= 1; z++) { const i = (1 << 0) * x | (1 << 1) * y | (1 << 2) * z; const v = points[i]; v.x = x ? max.x : min.x; v.y = y ? max.y : min.y; v.z = z ? max.z : min.z; v.applyMatrix4(matrix); } } } const satBounds = this.satBounds; const satAxes = this.satAxes; const minVec = points[0]; for (let i = 0; i < 3; i++) { const axis = satAxes[i]; const sb = satBounds[i]; const index = 1 << i; const pi = points[index]; axis.subVectors(minVec, pi); sb.setFromPoints(axis, points); } const alignedSatBounds = this.alignedSatBounds; alignedSatBounds[0].setFromPointsField(points, "x"); alignedSatBounds[1].setFromPointsField(points, "y"); alignedSatBounds[2].setFromPointsField(points, "z"); this.invMatrix.copy(this.matrix).invert(); this.needsUpdate = false; }; }(); OrientedBox.prototype.intersectsBox = function() { const aabbBounds = new SeparatingAxisBounds(); return function intersectsBox(box) { if (this.needsUpdate) { this.update(); } const min = box.min; const max = box.max; const satBounds = this.satBounds; const satAxes = this.satAxes; const alignedSatBounds = this.alignedSatBounds; aabbBounds.min = min.x; aabbBounds.max = max.x; if (alignedSatBounds[0].isSeparated(aabbBounds)) return false; aabbBounds.min = min.y; aabbBounds.max = max.y; if (alignedSatBounds[1].isSeparated(aabbBounds)) return false; aabbBounds.min = min.z; aabbBounds.max = max.z; if (alignedSatBounds[2].isSeparated(aabbBounds)) return false; for (let i = 0; i < 3; i++) { const axis = satAxes[i]; const sb = satBounds[i]; aabbBounds.setFromBox(axis, box); if (sb.isSeparated(aabbBounds)) return false; } return true; }; }(); OrientedBox.prototype.intersectsTriangle = function() { const saTri = new ExtendedTriangle(); const pointsArr = new Array(3); const cachedSatBounds = new SeparatingAxisBounds(); const cachedSatBounds2 = new SeparatingAxisBounds(); const cachedAxis = new Vector3(); return function intersectsTriangle(triangle) { if (this.needsUpdate) { this.update(); } if (!triangle.isExtendedTriangle) { saTri.copy(triangle); saTri.update(); triangle = saTri; } else if (triangle.needsUpdate) { triangle.update(); } const satBounds = this.satBounds; const satAxes = this.satAxes; pointsArr[0] = triangle.a; pointsArr[1] = triangle.b; pointsArr[2] = triangle.c; for (let i = 0; i < 3; i++) { const sb = satBounds[i]; const sa = satAxes[i]; cachedSatBounds.setFromPoints(sa, pointsArr); if (sb.isSeparated(cachedSatBounds)) return false; } const triSatBounds = triangle.satBounds; const triSatAxes = triangle.satAxes; const points = this.points; for (let i = 0; i < 3; i++) { const sb = triSatBounds[i]; const sa = triSatAxes[i]; cachedSatBounds.setFromPoints(sa, points); if (sb.isSeparated(cachedSatBounds)) return false; } for (let i = 0; i < 3; i++) { const sa1 = satAxes[i]; for (let i2 = 0; i2 < 4; i2++) { const sa2 = triSatAxes[i2]; cachedAxis.crossVectors(sa1, sa2); cachedSatBounds.setFromPoints(cachedAxis, pointsArr); cachedSatBounds2.setFromPoints(cachedAxis, points); if (cachedSatBounds.isSeparated(cachedSatBounds2)) return false; } } return true; }; }(); OrientedBox.prototype.closestPointToPoint = /* @__PURE__ */ function() { return function closestPointToPoint(point, target1) { if (this.needsUpdate) { this.update(); } target1.copy(point).applyMatrix4(this.invMatrix).clamp(this.min, this.max).applyMatrix4(this.matrix); return target1; }; }(); OrientedBox.prototype.distanceToPoint = function() { const target = new Vector3(); return function distanceToPoint(point) { this.closestPointToPoint(point, target); return point.distanceTo(target); }; }(); OrientedBox.prototype.distanceToBox = function() { const xyzFields2 = ["x", "y", "z"]; const segments1 = new Array(12).fill().map(() => new Line3()); const segments2 = new Array(12).fill().map(() => new Line3()); const point1 = new Vector3(); const point2 = new Vector3(); return function distanceToBox(box, threshold = 0, target1 = null, target2 = null) { if (this.needsUpdate) { this.update(); } if (this.intersectsBox(box)) { if (target1 || target2) { box.getCenter(point2); this.closestPointToPoint(point2, point1); box.closestPointToPoint(point1, point2); if (target1) target1.copy(point1); if (target2) target2.copy(point2); } return 0; } const threshold2 = threshold * threshold; const min = box.min; const max = box.max; const points = this.points; let closestDistanceSq = Infinity; for (let i = 0; i < 8; i++) { const p = points[i]; point2.copy(p).clamp(min, max); const dist = p.distanceToSquared(point2); if (dist < closestDistanceSq) { closestDistanceSq = dist; if (target1) target1.copy(p); if (target2) target2.copy(point2); if (dist < threshold2) return Math.sqrt(dist); } } let count = 0; for (let i = 0; i < 3; i++) { for (let i1 = 0; i1 <= 1; i1++) { for (let i2 = 0; i2 <= 1; i2++) { const nextIndex = (i + 1) % 3; const nextIndex2 = (i + 2) % 3; const index = i1 << nextIndex | i2 << nextIndex2; const index2 = 1 << i | i1 << nextIndex | i2 << nextIndex2; const p1 = points[index]; const p2 = points[index2]; const line1 = segments1[count]; line1.set(p1, p2); const f1 = xyzFields2[i]; const f2 = xyzFields2[nextIndex]; const f3 = xyzFields2[nextIndex2]; const line2 = segments2[count]; const start = line2.start; const end = line2.end; start[f1] = min[f1]; start[f2] = i1 ? min[f2] : max[f2]; start[f3] = i2 ? min[f3] : max[f2]; end[f1] = max[f1]; end[f2] = i1 ? min[f2] : max[f2]; end[f3] = i2 ? min[f3] : max[f2]; count++; } } } for (let x = 0; x <= 1; x++) { for (let y = 0; y <= 1; y++) { for (let z = 0; z <= 1; z++) { point2.x = x ? max.x : min.x; point2.y = y ? max.y : min.y; point2.z = z ? max.z : min.z; this.closestPointToPoint(point2, point1); const dist = point2.distanceToSquared(point1); if (dist < closestDistanceSq) { closestDistanceSq = dist; if (target1) target1.copy(point1); if (target2) target2.copy(point2); if (dist < threshold2) return Math.sqrt(dist); } } } } for (let i = 0; i < 12; i++) { const l1 = segments1[i]; for (let i2 = 0; i2 < 12; i2++) { const l2 = segments2[i2]; closestPointsSegmentToSegment(l1, l2, point1, point2); const dist = point1.distanceToSquared(point2); if (dist < closestDistanceSq) { closestDistanceSq = dist; if (target1) target1.copy(point1); if (target2) target2.copy(point2); if (dist < threshold2) return Math.sqrt(dist); } } } return Math.sqrt(closestDistanceSq); }; }(); // ../../node_modules/three-mesh-bvh/src/utils/ThreeRayIntersectUtilities.js var vA = new Vector3(); var vB = new Vector3(); var vC = new Vector3(); var uvA = new Vector2(); var uvB = new Vector2(); var uvC = new Vector2(); var intersectionPoint = new Vector3(); function checkIntersection(ray2, pA, pB, pC, point, side) { let intersect; if (side === BackSide) { intersect = ray2.intersectTriangle(pC, pB, pA, true, point); } else { intersect = ray2.intersectTriangle(pA, pB, pC, side !== DoubleSide, point); } if (intersect === null) return null; const distance = ray2.origin.distanceTo(point); return { distance, point: point.clone() }; } function checkBufferGeometryIntersection(ray2, position, uv, a, b, c, side) { vA.fromBufferAttribute(position, a); vB.fromBufferAttribute(position, b); vC.fromBufferAttribute(position, c); const intersection = checkIntersection(ray2, vA, vB, vC, intersectionPoint, side); if (intersection) { if (uv) { uvA.fromBufferAttribute(uv, a); uvB.fromBufferAttribute(uv, b); uvC.fromBufferAttribute(uv, c); intersection.uv = Triangle.getUV(intersectionPoint, vA, vB, vC, uvA, uvB, uvC, new Vector2()); } const face = { a, b, c, normal: new Vector3(), materialIndex: 0 }; Triangle.getNormal(vA, vB, vC, face.normal); intersection.face = face; intersection.faceIndex = a; } return intersection; } function intersectTri(geo, side, ray2, tri, intersections) { const triOffset = tri * 3; const a = geo.index.getX(triOffset); const b = geo.index.getX(triOffset + 1); const c = geo.index.getX(triOffset + 2); const intersection = checkBufferGeometryIntersection(ray2, geo.attributes.position, geo.attributes.uv, a, b, c, side); if (intersection) { intersection.faceIndex = tri; if (intersections) intersections.push(intersection); return intersection; } return null; } // ../../node_modules/three-mesh-bvh/src/utils/GeometryRayIntersectUtilities.js function intersectTris(geo, side, ray2, offset, count, intersections) { for (let i = offset, end = offset + count; i < end; i++) { intersectTri(geo, side, ray2, i, intersections); } } function intersectClosestTri(geo, side, ray2, offset, count) { let dist = Infinity; let res = null; for (let i = offset, end = offset + count; i < end; i++) { const intersection = intersectTri(geo, side, ray2, i); if (intersection && intersection.distance < dist) { res = intersection; dist = intersection.distance; } } return res; } function convertRaycastIntersect(hit, object, raycaster) { if (hit === null) { return null; } hit.point.applyMatrix4(object.matrixWorld); hit.distance = hit.point.distanceTo(raycaster.ray.origin); hit.object = object; if (hit.distance < raycaster.near || hit.distance > raycaster.far) { return null; } else { return hit; } } // ../../node_modules/three-mesh-bvh/src/utils/TriangleUtilities.js function setTriangle(tri, i, index, pos) { const ta = tri.a; const tb = tri.b; const tc = tri.c; let i0 = i; let i1 = i + 1; let i2 = i + 2; if (index) { i0 = index.getX(i); i1 = index.getX(i + 1); i2 = index.getX(i + 2); } ta.x = pos.getX(i0); ta.y = pos.getY(i0); ta.z = pos.getZ(i0); tb.x = pos.getX(i1); tb.y = pos.getY(i1); tb.z = pos.getZ(i1); tc.x = pos.getX(i2); tc.y = pos.getY(i2); tc.z = pos.getZ(i2); } function iterateOverTriangles(offset, count, geometry, intersectsTriangleFunc, contained, depth, triangle) { const index = geometry.index; const pos = geometry.attributes.position; for (let i = offset, l = count + offset; i < l; i++) { setTriangle(triangle, i * 3, index, pos); triangle.needsUpdate = true; if (intersectsTriangleFunc(triangle, i, contained, depth)) { return true; } } return false; } var tempV1 = new Vector3(); var tempV2 = new Vector3(); var tempV3 = new Vector3(); var tempUV1 = new Vector2(); var tempUV2 = new Vector2(); var tempUV3 = new Vector2(); function getTriangleHitPointInfo(point, geometry, triangleIndex, target) { const indices = geometry.getIndex().array; const positions = geometry.getAttribute("position"); const uvs = geometry.getAttribute("uv"); const a = indices[triangleIndex * 3]; const b = indices[triangleIndex * 3 + 1]; const c = indices[triangleIndex * 3 + 2]; tempV1.fromBufferAttribute(positions, a); tempV2.fromBufferAttribute(positions, b); tempV3.fromBufferAttribute(positions, c); let materialIndex = 0; const groups = geometry.groups; const firstVertexIndex = triangleIndex * 3; for (let i = 0, l = groups.length; i < l; i++) { const group = groups[i]; const { start, count } = group; if (firstVertexIndex >= start && firstVertexIndex < start + count) { materialIndex = group.materialIndex; break; } } let uv = null; if (uvs) { tempUV1.fromBufferAttribute(uvs, a); tempUV2.fromBufferAttribute(uvs, b); tempUV3.fromBufferAttribute(uvs, c); if (target && target.uv) uv = target.uv; else uv = new Vector2(); Triangle.getUV(point, tempV1, tempV2, tempV3, tempUV1, tempUV2, tempUV3, uv); } if (target) { if (!target.face) target.face = {}; target.face.a = a; target.face.b = b; target.face.c = c; target.face.materialIndex = materialIndex; if (!target.face.normal) target.face.normal = new Vector3(); Triangle.getNormal(tempV1, tempV2, tempV3, target.face.normal); if (!target.uv) target.uv = new Vector2(); target.uv.copy(uv); return target; } else { return { face: { a, b, c, materialIndex, normal: Triangle.getNormal(tempV1, tempV2, tempV3, new Vector3()) }, uv }; } } // ../../node_modules/three-mesh-bvh/src/utils/PrimitivePool.js var PrimitivePool = class { constructor(getNewPrimitive) { this._getNewPrimitive = getNewPrimitive; this._primitives = []; } getPrimitive() { const primitives = this._primitives; if (primitives.length === 0) { return this._getNewPrimitive(); } else { return primitives.pop(); } } releasePrimitive(primitive) { this._primitives.push(primitive); } }; // ../../node_modules/three-mesh-bvh/src/core/nodeBufferFunctions.js function IS_LEAF(n16, uint16Array) { return uint16Array[n16 + 15] === 65535; } function OFFSET(n32, uint32Array) { return uint32Array[n32 + 6]; } function COUNT(n16, uint16Array) { return uint16Array[n16 + 14]; } function LEFT_NODE(n32) { return n32 + 8; } function RIGHT_NODE(n32, uint32Array) { return uint32Array[n32 + 6]; } function SPLIT_AXIS(n32, uint32Array) { return uint32Array[n32 + 7]; } function BOUNDING_DATA_INDEX(n32) { return n32; } // ../../node_modules/three-mesh-bvh/src/core/castFunctions.js var boundingBox = new Box3(); var boxIntersection = new Vector3(); var xyzFields = ["x", "y", "z"]; function raycast(nodeIndex32, geometry, side, ray2, intersects) { let nodeIndex16 = nodeIndex32 * 2, float32Array = _float32Array, uint16Array = _uint16Array, uint32Array = _uint32Array; const isLeaf = IS_LEAF(nodeIndex16, uint16Array); if (isLeaf) { const offset = OFFSET(nodeIndex32, uint32Array); const count = COUNT(nodeIndex16, uint16Array); intersectTris(geometry, side, ray2, offset, count, intersects); } else { const leftIndex = LEFT_NODE(nodeIndex32); if (intersectRay(leftIndex, float32Array, ray2, boxIntersection)) { raycast(leftIndex, geometry, side, ray2, intersects); } const rightIndex = RIGHT_NODE(nodeIndex32, uint32Array); if (intersectRay(rightIndex, float32Array, ray2, boxIntersection)) { raycast(rightIndex, geometry, side, ray2, intersects); } } } function raycastFirst(nodeIndex32, geometry, side, ray2) { let nodeIndex16 = nodeIndex32 * 2, float32Array = _float32Array, uint16Array = _uint16Array, uint32Array = _uint32Array; const isLeaf = IS_LEAF(nodeIndex16, uint16Array); if (isLeaf) { const offset = OFFSET(nodeIndex32, uint32Array); const count = COUNT(nodeIndex16, uint16Array); return intersectClosestTri(geometry, side, ray2, offset, count); } else { const splitAxis = SPLIT_AXIS(nodeIndex32, uint32Array); const xyzAxis = xyzFields[splitAxis]; const rayDir = ray2.direction[xyzAxis]; const leftToRight = rayDir >= 0; let c1, c2; if (leftToRight) { c1 = LEFT_NODE(nodeIndex32); c2 = RIGHT_NODE(nodeIndex32, uint32Array); } else { c1 = RIGHT_NODE(nodeIndex32, uint32Array); c2 = LEFT_NODE(nodeIndex32); } const c1Intersection = intersectRay(c1, float32Array, ray2, boxIntersection); const c1Result = c1Intersection ? raycastFirst(c1, geometry, side, ray2) : null; if (c1Result) { const point = c1Result.point[xyzAxis]; const isOutside = leftToRight ? point <= float32Array[c2 + splitAxis] : ( // min bounding data point >= float32Array[c2 + splitAxis + 3] ); if (isOutside) { return c1Result; } } const c2Intersection = intersectRay(c2, float32Array, ray2, boxIntersection); const c2Result = c2Intersection ? raycastFirst(c2, geometry, side, ray2) : null; if (c1Result && c2Result) { return c1Result.distance <= c2Result.distance ? c1Result : c2Result; } else { return c1Result || c2Result || null; } } } var shapecast = function() { let _box12, _box22; const boxStack = []; const boxPool = new PrimitivePool(() => new Box3()); return function shapecast2(...args) { _box12 = boxPool.getPrimitive(); _box22 = boxPool.getPrimitive(); boxStack.push(_box12, _box22); const result = shapecastTraverse(...args); boxPool.releasePrimitive(_box12); boxPool.releasePrimitive(_box22); boxStack.pop(); boxStack.pop(); const length = boxStack.length; if (length > 0) { _box22 = boxStack[length - 1]; _box12 = boxStack[length - 2]; } return result; }; function shapecastTraverse(nodeIndex32, geometry, intersectsBoundsFunc, intersectsRangeFunc, nodeScoreFunc = null, nodeIndexByteOffset = 0, depth = 0) { function getLeftOffset(nodeIndex322) { let nodeIndex162 = nodeIndex322 * 2, uint16Array2 = _uint16Array, uint32Array2 = _uint32Array; while (!IS_LEAF(nodeIndex162, uint16Array2)) { nodeIndex322 = LEFT_NODE(nodeIndex322); nodeIndex162 = nodeIndex322 * 2; } return OFFSET(nodeIndex322, uint32Array2); } function getRightEndOffset(nodeIndex322) { let nodeIndex162 = nodeIndex322 * 2, uint16Array2 = _uint16Array, uint32Array2 = _uint32Array; while (!IS_LEAF(nodeIndex162, uint16Array2)) { nodeIndex322 = RIGHT_NODE(nodeIndex322, uint32Array2); nodeIndex162 = nodeIndex322 * 2; } return OFFSET(nodeIndex322, uint32Array2) + COUNT(nodeIndex162, uint16Array2); } let nodeIndex16 = nodeIndex32 * 2, float32Array = _float32Array, uint16Array = _uint16Array, uint32Array = _uint32Array; const isLeaf = IS_LEAF(nodeIndex16, uint16Array); if (isLeaf) { const offset = OFFSET(nodeIndex32, uint32Array); const count = COUNT(nodeIndex16, uint16Array); arrayToBox(BOUNDING_DATA_INDEX(nodeIndex32), float32Array, _box12); return intersectsRangeFunc(offset, count, false, depth, nodeIndexByteOffset + nodeIndex32, _box12); } else { const left = LEFT_NODE(nodeIndex32); const right = RIGHT_NODE(nodeIndex32, uint32Array); let c1 = left; let c2 = right; let score1, score2; let box1, box2; if (nodeScoreFunc) { box1 = _box12; box2 = _box22; arrayToBox(BOUNDING_DATA_INDEX(c1), float32Array, box1); arrayToBox(BOUNDING_DATA_INDEX(c2), float32Array, box2); score1 = nodeScoreFunc(box1); score2 = nodeScoreFunc(box2); if (score2 < score1) { c1 = right; c2 = left; const temp5 = score1; score1 = score2; score2 = temp5; box1 = box2; } } if (!box1) { box1 = _box12; arrayToBox(BOUNDING_DATA_INDEX(c1), float32Array, box1); } const isC1Leaf = IS_LEAF(c1 * 2, uint16Array); const c1Intersection = intersectsBoundsFunc(box1, isC1Leaf, score1, depth + 1, nodeIndexByteOffset + c1); let c1StopTraversal; if (c1Intersection === CONTAINED) { const offset = getLeftOffset(c1); const end = getRightEndOffset(c1); const count = end - offset; c1StopTraversal = intersectsRangeFunc(offset, count, true, depth + 1, nodeIndexByteOffset + c1, box1); } else { c1StopTraversal = c1Intersection && shapecastTraverse( c1, geometry, intersectsBoundsFunc, intersectsRangeFunc, nodeScoreFunc, nodeIndexByteOffset, depth + 1 ); } if (c1StopTraversal) return true; box2 = _box22; arrayToBox(BOUNDING_DATA_INDEX(c2), float32Array, box2); const isC2Leaf = IS_LEAF(c2 * 2, uint16Array); const c2Intersection = intersectsBoundsFunc(box2, isC2Leaf, score2, depth + 1, nodeIndexByteOffset + c2); let c2StopTraversal; if (c2Intersection === CONTAINED) { const offset = getLeftOffset(c2); const end = getRightEndOffset(c2); const count = end - offset; c2StopTraversal = intersectsRangeFunc(offset, count, true, depth + 1, nodeIndexByteOffset + c2, box2); } else { c2StopTraversal = c2Intersection && shapecastTraverse( c2, geometry, intersectsBoundsFunc, intersectsRangeFunc, nodeScoreFunc, nodeIndexByteOffset, depth + 1 ); } if (c2StopTraversal) return true; return false; } } }(); var intersectsGeometry = function() { const triangle = new ExtendedTriangle(); const triangle2 = new ExtendedTriangle(); const invertedMat = new Matrix4(); const obb3 = new OrientedBox(); const obb22 = new OrientedBox(); return function intersectsGeometry2(nodeIndex32, geometry, otherGeometry, geometryToBvh, cachedObb = null) { let nodeIndex16 = nodeIndex32 * 2, float32Array = _float32Array, uint16Array = _uint16Array, uint32Array = _uint32Array; if (cachedObb === null) { if (!otherGeometry.boundingBox) { otherGeometry.computeBoundingBox(); } obb3.set(otherGeometry.boundingBox.min, otherGeometry.boundingBox.max, geometryToBvh); cachedObb = obb3; } const isLeaf = IS_LEAF(nodeIndex16, uint16Array); if (isLeaf) { const thisGeometry = geometry; const thisIndex = thisGeometry.index; const thisPos = thisGeometry.attributes.position; const index = otherGeometry.index; const pos = otherGeometry.attributes.position; const offset = OFFSET(nodeIndex32, uint32Array); const count = COUNT(nodeIndex16, uint16Array); invertedMat.copy(geometryToBvh).invert(); if (otherGeometry.boundsTree) { arrayToBox(BOUNDING_DATA_INDEX(nodeIndex32), float32Array, obb22); obb22.matrix.copy(invertedMat); obb22.needsUpdate = true; const res = otherGeometry.boundsTree.shapecast({ intersectsBounds: (box) => obb22.intersectsBox(box), intersectsTriangle: (tri) => { tri.a.applyMatrix4(geometryToBvh); tri.b.applyMatrix4(geometryToBvh); tri.c.applyMatrix4(geometryToBvh); tri.needsUpdate = true; for (let i = offset * 3, l = (count + offset) * 3; i < l; i += 3) { setTriangle(triangle2, i, thisIndex, thisPos); triangle2.needsUpdate = true; if (tri.intersectsTriangle(triangle2)) { return true; } } return false; } }); return res; } else { for (let i = offset * 3, l = count + offset * 3; i < l; i += 3) { setTriangle(triangle, i, thisIndex, thisPos); triangle.a.applyMatrix4(invertedMat); triangle.b.applyMatrix4(invertedMat); triangle.c.applyMatrix4(invertedMat); triangle.needsUpdate = true; for (let i2 = 0, l2 = index.count; i2 < l2; i2 += 3) { setTriangle(triangle2, i2, index, pos); triangle2.needsUpdate = true; if (triangle.intersectsTriangle(triangle2)) { return true; } } } } } else { const left = nodeIndex32 + 8; const right = uint32Array[nodeIndex32 + 6]; arrayToBox(BOUNDING_DATA_INDEX(left), float32Array, boundingBox); const leftIntersection = cachedObb.intersectsBox(boundingBox) && intersectsGeometry2(left, geometry, otherGeometry, geometryToBvh, cachedObb); if (leftIntersection) return true; arrayToBox(BOUNDING_DATA_INDEX(right), float32Array, boundingBox); const rightIntersection = cachedObb.intersectsBox(boundingBox) && intersectsGeometry2(right, geometry, otherGeometry, geometryToBvh, cachedObb); if (rightIntersection) return true; return false; } }; }(); function intersectRay(nodeIndex32, array, ray2, target) { arrayToBox(nodeIndex32, array, boundingBox); return ray2.intersectBox(boundingBox, target); } var bufferStack = []; var _prevBuffer; var _float32Array; var _uint16Array; var _uint32Array; function setBuffer(buffer) { if (_prevBuffer) { bufferStack.push(_prevBuffer); } _prevBuffer = buffer; _float32Array = new Float32Array(buffer); _uint16Array = new Uint16Array(buffer); _uint32Array = new Uint32Array(buffer); } function clearBuffer() { _prevBuffer = null; _float32Array = null; _uint16Array = null; _uint32Array = null; if (bufferStack.length) { setBuffer(bufferStack.pop()); } } // ../../node_modules/three-mesh-bvh/src/core/MeshBVH.js var SKIP_GENERATION = Symbol("skip tree generation"); var aabb = new Box3(); var aabb2 = new Box3(); var tempMatrix = new Matrix4(); var obb = new OrientedBox(); var obb2 = new OrientedBox(); var temp = new Vector3(); var temp1 = new Vector3(); var temp2 = new Vector3(); var temp3 = new Vector3(); var temp4 = new Vector3(); var tempBox = new Box3(); var trianglePool = new PrimitivePool(() => new ExtendedTriangle()); var MeshBVH = class _MeshBVH { static serialize(bvh, options = {}) { if (options.isBufferGeometry) { console.warn("MeshBVH.serialize: The arguments for the function have changed. See documentation for new signature."); return _MeshBVH.serialize( arguments[0], { cloneBuffers: arguments[2] === void 0 ? true : arguments[2] } ); } options = { cloneBuffers: true, ...options }; const geometry = bvh.geometry; const rootData = bvh._roots; const indexAttribute = geometry.getIndex(); let result; if (options.cloneBuffers) { result = { roots: rootData.map((root) => root.slice()), index: indexAttribute.array.slice() }; } else { result = { roots: rootData, index: indexAttribute.array }; } return result; } static deserialize(data, geometry, options = {}) { if (typeof options === "boolean") { console.warn("MeshBVH.deserialize: The arguments for the function have changed. See documentation for new signature."); return _MeshBVH.deserialize( arguments[0], arguments[1], { setIndex: arguments[2] === void 0 ? true : arguments[2] } ); } options = { setIndex: true, ...options }; const { index, roots } = data; const bvh = new _MeshBVH(geometry, { ...options, [SKIP_GENERATION]: true }); bvh._roots = roots; if (options.setIndex) { const indexAttribute = geometry.getIndex(); if (indexAttribute === null) { const newIndex = new BufferAttribute(data.index, 1, false); geometry.setIndex(newIndex); } else if (indexAttribute.array !== index) { indexAttribute.array.set(index); indexAttribute.needsUpdate = true; } } return bvh; } constructor(geometry, options = {}) { if (!geometry.isBufferGeometry) { throw new Error("MeshBVH: Only BufferGeometries are supported."); } else if (geometry.index && geometry.index.isInterleavedBufferAttribute) { throw new Error("MeshBVH: InterleavedBufferAttribute is not supported for the index attribute."); } options = Object.assign({ strategy: CENTER, maxDepth: 40, maxLeafTris: 10, verbose: true, useSharedArrayBuffer: false, setBoundingBox: true, onProgress: null, // undocumented options // Whether to skip generating the tree. Used for deserialization. [SKIP_GENERATION]: false }, options); if (options.useSharedArrayBuffer && typeof SharedArrayBuffer === "undefined") { throw new Error("MeshBVH: SharedArrayBuffer is not available."); } this._roots = null; if (!options[SKIP_GENERATION]) { this._roots = buildPackedTree(geometry, options); if (!geometry.boundingBox && options.setBoundingBox) { geometry.boundingBox = this.getBoundingBox(new Box3()); } } this.geometry = geometry; } refit(nodeIndices = null) { if (nodeIndices && Array.isArray(nodeIndices)) { nodeIndices = new Set(nodeIndices); } const geometry = this.geometry; const indexArr = geometry.index.array; const posAttr = geometry.attributes.position; let buffer, uint32Array, uint16Array, float32Array; let byteOffset = 0; const roots = this._roots; for (let i = 0, l = roots.length; i < l; i++) { buffer = roots[i]; uint32Array = new Uint32Array(buffer); uint16Array = new Uint16Array(buffer); float32Array = new Float32Array(buffer); _traverse(0, byteOffset); byteOffset += buffer.byteLength; } function _traverse(node32Index, byteOffset2, force = false) { const node16Index = node32Index * 2; const isLeaf = uint16Array[node16Index + 15] === IS_LEAFNODE_FLAG; if (isLeaf) { const offset = uint32Array[node32Index + 6]; const count = uint16Array[node16Index + 14]; let minx = Infinity; let miny = Infinity; let minz = Infinity; let maxx = -Infinity; let maxy = -Infinity; let maxz = -Infinity; for (let i = 3 * offset, l = 3 * (offset + count); i < l; i++) { const index = indexArr[i]; const x = posAttr.getX(index); const y = posAttr.getY(index); const z = posAttr.getZ(index); if (x < minx) minx = x; if (x > maxx) maxx = x; if (y < miny) miny = y; if (y > maxy) maxy = y; if (z < minz) minz = z; if (z > maxz) maxz = z; } if (float32Array[node32Index + 0] !== minx || float32Array[node32Index + 1] !== miny || float32Array[node32Index + 2] !== minz || float32Array[node32Index + 3] !== maxx || float32Array[node32Index + 4] !== maxy || float32Array[node32Index + 5] !== maxz) { float32Array[node32Index + 0] = minx; float32Array[node32Index + 1] = miny; float32Array[node32Index + 2] = minz; float32Array[node32Index + 3] = maxx; float32Array[node32Index + 4] = maxy; float32Array[node32Index + 5] = maxz; return true; } else { return false; } } else { const left = node32Index + 8; const right = uint32Array[node32Index + 6]; const offsetLeft = left + byteOffset2; const offsetRight = right + byteOffset2; let forceChildren = force; let includesLeft = false; let includesRight = false; if (nodeIndices) { if (!forceChildren) { includesLeft = nodeIndices.has(offsetLeft); includesRight = nodeIndices.has(offsetRight); forceChildren = !includesLeft && !includesRight; } } else { includesLeft = true; includesRight = true; } const traverseLeft = forceChildren || includesLeft; const traverseRight = forceChildren || includesRight; let leftChange = false; if (traverseLeft) { leftChange = _traverse(left, byteOffset2, forceChildren); } let rightChange = false; if (traverseRight) { rightChange = _traverse(right, byteOffset2, forceChildren); } const didChange = leftChange || rightChange; if (didChange) { for (let i = 0; i < 3; i++) { const lefti = left + i; const righti = right + i; const minLeftValue = float32Array[lefti]; const maxLeftValue = float32Array[lefti + 3]; const minRightValue = float32Array[righti]; const maxRightValue = float32Array[righti + 3]; float32Array[node32Index + i] = minLeftValue < minRightValue ? minLeftValue : minRightValue; float32Array[node32Index + i + 3] = maxLeftValue > maxRightValue ? maxLeftValue : maxRightValue; } } return didChange; } } } traverse(callback, rootIndex = 0) { const buffer = this._roots[rootIndex]; const uint32Array = new Uint32Array(buffer); const uint16Array = new Uint16Array(buffer); _traverse(0); function _traverse(node32Index, depth = 0) { const node16Index = node32Index * 2; const isLeaf = uint16Array[node16Index + 15] === IS_LEAFNODE_FLAG; if (isLeaf) { const offset = uint32Array[node32Index + 6]; const count = uint16Array[node16Index + 14]; callback(depth, isLeaf, new Float32Array(buffer, node32Index * 4, 6), offset, count); } else { const left = node32Index + BYTES_PER_NODE / 4; const right = uint32Array[node32Index + 6]; const splitAxis = uint32Array[node32Index + 7]; const stopTraversal = callback(depth, isLeaf, new Float32Array(buffer, node32Index * 4, 6), splitAxis); if (!stopTraversal) { _traverse(left, depth + 1); _traverse(right, depth + 1); } } } } /* Core Cast Functions */ raycast(ray2, materialOrSide = FrontSide) { const roots = this._roots; const geometry = this.geometry; const intersects = []; const isMaterial = materialOrSide.isMaterial; const isArrayMaterial = Array.isArray(materialOrSide); const groups = geometry.groups; const side = isMaterial ? materialOrSide.side : materialOrSide; for (let i = 0, l = roots.length; i < l; i++) { const materialSide = isArrayMaterial ? materialOrSide[groups[i].materialIndex].side : side; const startCount = intersects.length; setBuffer(roots[i]); raycast(0, geometry, materialSide, ray2, intersects); clearBuffer(); if (isArrayMaterial) { const materialIndex = groups[i].materialIndex; for (let j = startCount, jl = intersects.length; j < jl; j++) { intersects[j].face.materialIndex = materialIndex; } } } return intersects; } raycastFirst(ray2, materialOrSide = FrontSide) { const roots = this._roots; const geometry = this.geometry; const isMaterial = materialOrSide.isMaterial; const isArrayMaterial = Array.isArray(materialOrSide); let closestResult = null; const groups = geometry.groups; const side = isMaterial ? materialOrSide.side : materialOrSide; for (let i = 0, l = roots.length; i < l; i++) { const materialSide = isArrayMaterial ? materialOrSide[groups[i].materialIndex].side : side; setBuffer(roots[i]); const result = raycastFirst(0, geometry, materialSide, ray2); clearBuffer(); if (result != null && (closestResult == null || result.distance < closestResult.distance)) { closestResult = result; if (isArrayMaterial) { result.face.materialIndex = groups[i].materialIndex; } } } return closestResult; } intersectsGeometry(otherGeometry, geomToMesh) { const geometry = this.geometry; let result = false; for (const root of this._roots) { setBuffer(root); result = intersectsGeometry(0, geometry, otherGeometry, geomToMesh); clearBuffer(); if (result) { break; } } return result; } shapecast(callbacks, _intersectsTriangleFunc, _orderNodesFunc) { const geometry = this.geometry; if (callbacks instanceof Function) { if (_intersectsTriangleFunc) { const originalTriangleFunc = _intersectsTriangleFunc; _intersectsTriangleFunc = (tri, index, contained, depth) => { const i3 = index * 3; return originalTriangleFunc(tri, i3, i3 + 1, i3 + 2, contained, depth); }; } callbacks = { boundsTraverseOrder: _orderNodesFunc, intersectsBounds: callbacks, intersectsTriangle: _intersectsTriangleFunc, intersectsRange: null }; console.warn("MeshBVH: Shapecast function signature has changed and now takes an object of callbacks as a second argument. See docs for new signature."); } const triangle = trianglePool.getPrimitive(); let { boundsTraverseOrder, intersectsBounds, intersectsRange, intersectsTriangle } = callbacks; if (intersectsRange && intersectsTriangle) { const originalIntersectsRange = intersectsRange; intersectsRange = (offset, count, contained, depth, nodeIndex) => { if (!originalIntersectsRange(offset, count, contained, depth, nodeIndex)) { return iterateOverTriangles(offset, count, geometry, intersectsTriangle, contained, depth, triangle); } return true; }; } else if (!intersectsRange) { if (intersectsTriangle) { intersectsRange = (offset, count, contained, depth) => { return iterateOverTriangles(offset, count, geometry, intersectsTriangle, contained, depth, triangle); }; } else { intersectsRange = (offset, count, contained) => { return contained; }; } } let result = false; let byteOffset = 0; for (const root of this._roots) { setBuffer(root); result = shapecast(0, geometry, intersectsBounds, intersectsRange, boundsTraverseOrder, byteOffset); clearBuffer(); if (result) { break; } byteOffset += root.byteLength; } trianglePool.releasePrimitive(triangle); return result; } bvhcast(otherBvh, matrixToLocal, callbacks) { let { intersectsRanges, intersectsTriangles } = callbacks; const indexAttr = this.geometry.index; const positionAttr = this.geometry.attributes.position; const otherIndexAttr = otherBvh.geometry.index; const otherPositionAttr = otherBvh.geometry.attributes.position; tempMatrix.copy(matrixToLocal).invert(); const triangle = trianglePool.getPrimitive(); const triangle2 = trianglePool.getPrimitive(); if (intersectsTriangles) { let iterateOverDoubleTriangles = function(offset1, count1, offset2, count2, depth1, index1, depth2, index2) { for (let i2 = offset2, l2 = offset2 + count2; i2 < l2; i2++) { setTriangle(triangle2, i2 * 3, otherIndexAttr, otherPositionAttr); triangle2.a.applyMatrix4(matrixToLocal); triangle2.b.applyMatrix4(matrixToLocal); triangle2.c.applyMatrix4(matrixToLocal); triangle2.needsUpdate = true; for (let i1 = offset1, l1 = offset1 + count1; i1 < l1; i1++) { setTriangle(triangle, i1 * 3, indexAttr, positionAttr); triangle.needsUpdate = true; if (intersectsTriangles(triangle, triangle2, i1, i2, depth1, index1, depth2, index2)) { return true; } } } return false; }; if (intersectsRanges) { const originalIntersectsRanges = intersectsRanges; intersectsRanges = function(offset1, count1, offset2, count2, depth1, index1, depth2, index2) { if (!originalIntersectsRanges(offset1, count1, offset2, count2, depth1, index1, depth2, index2)) { return iterateOverDoubleTriangles(offset1, count1, offset2, count2, depth1, index1, depth2, index2); } return true; }; } else { intersectsRanges = iterateOverDoubleTriangles; } } otherBvh.getBoundingBox(aabb2); aabb2.applyMatrix4(matrixToLocal); const result = this.shapecast({ intersectsBounds: (box) => aabb2.intersectsBox(box), intersectsRange: (offset1, count1, contained, depth1, nodeIndex1, box) => { aabb.copy(box); aabb.applyMatrix4(tempMatrix); return otherBvh.shapecast({ intersectsBounds: (box2) => aabb.intersectsBox(box2), intersectsRange: (offset2, count2, contained2, depth2, nodeIndex2) => { return intersectsRanges(offset1, count1, offset2, count2, depth1, nodeIndex1, depth2, nodeIndex2); } }); } }); trianglePool.releasePrimitive(triangle); trianglePool.releasePrimitive(triangle2); return result; } /* Derived Cast Functions */ intersectsBox(box, boxToMesh) { obb.set(box.min, box.max, boxToMesh); obb.needsUpdate = true; return this.shapecast( { intersectsBounds: (box2) => obb.intersectsBox(box2), intersectsTriangle: (tri) => obb.intersectsTriangle(tri) } ); } intersectsSphere(sphere) { return this.shapecast( { intersectsBounds: (box) => sphere.intersectsBox(box), intersectsTriangle: (tri) => tri.intersectsSphere(sphere) } ); } closestPointToGeometry(otherGeometry, geometryToBvh, target1 = {}, target2 = {}, minThreshold = 0, maxThreshold = Infinity) { if (!otherGeometry.boundingBox) { otherGeometry.computeBoundingBox(); } obb.set(otherGeometry.boundingBox.min, otherGeometry.boundingBox.max, geometryToBvh); obb.needsUpdate = true; const geometry = this.geometry; const pos = geometry.attributes.position; const index = geometry.index; const otherPos = otherGeometry.attributes.position; const otherIndex = otherGeometry.index; const triangle = trianglePool.getPrimitive(); const triangle2 = trianglePool.getPrimitive(); let tempTarget1 = temp1; let tempTargetDest1 = temp2; let tempTarget2 = null; let tempTargetDest2 = null; if (target2) { tempTarget2 = temp3; tempTargetDest2 = temp4; } let closestDistance = Infinity; let closestDistanceTriIndex = null; let closestDistanceOtherTriIndex = null; tempMatrix.copy(geometryToBvh).invert(); obb2.matrix.copy(tempMatrix); this.shapecast( { boundsTraverseOrder: (box) => { return obb.distanceToBox(box); }, intersectsBounds: (box, isLeaf, score) => { if (score < closestDistance && score < maxThreshold) { if (isLeaf) { obb2.min.copy(box.min); obb2.max.copy(box.max); obb2.needsUpdate = true; } return true; } return false; }, intersectsRange: (offset, count) => { if (otherGeometry.boundsTree) { return otherGeometry.boundsTree.shapecast({ boundsTraverseOrder: (box) => { return obb2.distanceToBox(box); }, intersectsBounds: (box, isLeaf, score) => { return score < closestDistance && score < maxThreshold; }, intersectsRange: (otherOffset, otherCount) => { for (let i2 = otherOffset * 3, l2 = (otherOffset + otherCount) * 3; i2 < l2; i2 += 3) { setTriangle(triangle2, i2, otherIndex, otherPos); triangle2.a.applyMatrix4(geometryToBvh); triangle2.b.applyMatrix4(geometryToBvh); triangle2.c.applyMatrix4(geometryToBvh); triangle2.needsUpdate = true; for (let i = offset * 3, l = (offset + count) * 3; i < l; i += 3) { setTriangle(triangle, i, index, pos); triangle.needsUpdate = true; const dist = triangle.distanceToTriangle(triangle2, tempTarget1, tempTarget2); if (dist < closestDistance) { tempTargetDest1.copy(tempTarget1); if (tempTargetDest2) { tempTargetDest2.copy(tempTarget2); } closestDistance = dist; closestDistanceTriIndex = i / 3; closestDistanceOtherTriIndex = i2 / 3; } if (dist < minThreshold) { return true; } } } } }); } else { const triCount = otherIndex ? otherIndex.count : otherPos.count; for (let i2 = 0, l2 = triCount; i2 < l2; i2 += 3) { setTriangle(triangle2, i2, otherIndex, otherPos); triangle2.a.applyMatrix4(geometryToBvh); triangle2.b.applyMatrix4(geometryToBvh); triangle2.c.applyMatrix4(geometryToBvh); triangle2.needsUpdate = true; for (let i = offset * 3, l = (offset + count) * 3; i < l; i += 3) { setTriangle(triangle, i, index, pos); triangle.needsUpdate = true; const dist = triangle.distanceToTriangle(triangle2, tempTarget1, tempTarget2); if (dist < closestDistance) { tempTargetDest1.copy(tempTarget1); if (tempTargetDest2) { tempTargetDest2.copy(tempTarget2); } closestDistance = dist; closestDistanceTriIndex = i / 3; closestDistanceOtherTriIndex = i2 / 3; } if (dist < minThreshold) { return true; } } } } } } ); trianglePool.releasePrimitive(triangle); trianglePool.releasePrimitive(triangle2); if (closestDistance === Infinity) return null; if (!target1.point) target1.point = tempTargetDest1.clone(); else target1.point.copy(tempTargetDest1); target1.distance = closestDistance, target1.faceIndex = closestDistanceTriIndex; if (target2) { if (!target2.point) target2.point = tempTargetDest2.clone(); else target2.point.copy(tempTargetDest2); target2.point.applyMatrix4(tempMatrix); tempTargetDest1.applyMatrix4(tempMatrix); target2.distance = tempTargetDest1.sub(target2.point).length(); target2.faceIndex = closestDistanceOtherTriIndex; } return target1; } closestPointToPoint(point, target = {}, minThreshold = 0, maxThreshold = Infinity) { const minThresholdSq = minThreshold * minThreshold; const maxThresholdSq = maxThreshold * maxThreshold; let closestDistanceSq = Infinity; let closestDistanceTriIndex = null; this.shapecast( { boundsTraverseOrder: (box) => { temp.copy(point).clamp(box.min, box.max); return temp.distanceToSquared(point); }, intersectsBounds: (box, isLeaf, score) => { return score < closestDistanceSq && score < maxThresholdSq; }, intersectsTriangle: (tri, triIndex) => { tri.closestPointToPoint(point, temp); const distSq = point.distanceToSquared(temp); if (distSq < closestDistanceSq) { temp1.copy(temp); closestDistanceSq = distSq; closestDistanceTriIndex = triIndex; } if (distSq < minThresholdSq) { return true; } else { return false; } } } ); if (closestDistanceSq === Infinity) return null; const closestDistance = Math.sqrt(closestDistanceSq); if (!target.point) target.point = temp1.clone(); else target.point.copy(temp1); target.distance = closestDistance, target.faceIndex = closestDistanceTriIndex; return target; } getBoundingBox(target) { target.makeEmpty(); const roots = this._roots; roots.forEach((buffer) => { arrayToBox(0, new Float32Array(buffer), tempBox); target.union(tempBox); }); return target; } }; // ../../node_modules/three-mesh-bvh/src/objects/MeshBVHVisualizer.js var boundingBox2 = new Box3(); var MeshBVHRootVisualizer = class extends Object3D { get isMesh() { return !this.displayEdges; } get isLineSegments() { return this.displayEdges; } get isLine() { return this.displayEdges; } constructor(mesh, material, depth = 10, group = 0) { super(); this.material = material; this.geometry = new BufferGeometry(); this.name = "MeshBVHRootVisualizer"; this.depth = depth; this.displayParents = false; this.mesh = mesh; this.displayEdges = true; this._group = group; } raycast() { } update() { const geometry = this.geometry; const boundsTree = this.mesh.geometry.boundsTree; const group = this._group; geometry.dispose(); this.visible = false; if (boundsTree) { const targetDepth = this.depth - 1; const displayParents = this.displayParents; let boundsCount = 0; boundsTree.traverse((depth, isLeaf) => { if (depth === targetDepth || isLeaf) { boundsCount++; return true; } else if (displayParents) { boundsCount++; } }, group); let posIndex = 0; const positionArray = new Float32Array(8 * 3 * boundsCount); boundsTree.traverse((depth, isLeaf, boundingData) => { const terminate = depth === targetDepth || isLeaf; if (terminate || displayParents) { arrayToBox(0, boundingData, boundingBox2); const { min, max } = boundingBox2; for (let x = -1; x <= 1; x += 2) { const xVal = x < 0 ? min.x : max.x; for (let y = -1; y <= 1; y += 2) { const yVal = y < 0 ? min.y : max.y; for (let z = -1; z <= 1; z += 2) { const zVal = z < 0 ? min.z : max.z; positionArray[posIndex + 0] = xVal; positionArray[posIndex + 1] = yVal; positionArray[posIndex + 2] = zVal; posIndex += 3; } } } return terminate; } }, group); let indexArray; let indices; if (this.displayEdges) { indices = new Uint8Array([ // x axis 0, 4, 1, 5, 2, 6, 3, 7, // y axis 0, 2, 1, 3, 4, 6, 5, 7, // z axis 0, 1, 2, 3, 4, 5, 6, 7 ]); } else { indices = new Uint8Array([ // X-, X+ 0, 1, 2, 2, 1, 3, 4, 6, 5, 6, 7, 5, // Y-, Y+ 1, 4, 5, 0, 4, 1, 2, 3, 6, 3, 7, 6, // Z-, Z+ 0, 2, 4, 2, 6, 4, 1, 5, 3, 3, 5, 7 ]); } if (positionArray.length > 65535) { indexArray = new Uint32Array(indices.length * boundsCount); } else { indexArray = new Uint16Array(indices.length * boundsCount); } const indexLength = indices.length; for (let i = 0; i < boundsCount; i++) { const posOffset = i * 8; const indexOffset = i * indexLength; for (let j = 0; j < indexLength; j++) { indexArray[indexOffset + j] = posOffset + indices[j]; } } geometry.setIndex( new BufferAttribute(indexArray, 1, false) ); geometry.setAttribute( "position", new BufferAttribute(positionArray, 3, false) ); this.visible = true; } } }; var MeshBVHVisualizer = class _MeshBVHVisualizer extends Group { get color() { return this.edgeMaterial.color; } get opacity() { return this.edgeMaterial.opacity; } set opacity(v) { this.edgeMaterial.opacity = v; this.meshMaterial.opacity = v; } constructor(mesh, depth = 10) { super(); this.name = "MeshBVHVisualizer"; this.depth = depth; this.mesh = mesh; this.displayParents = false; this.displayEdges = true; this._roots = []; const edgeMaterial = new LineBasicMaterial({ color: 65416, transparent: true, opacity: 0.3, depthWrite: false }); const meshMaterial = new MeshBasicMaterial({ color: 65416, transparent: true, opacity: 0.3, depthWrite: false }); meshMaterial.color = edgeMaterial.color; this.edgeMaterial = edgeMaterial; this.meshMaterial = meshMaterial; this.update(); } update() { const bvh = this.mesh.geometry.boundsTree; const totalRoots = bvh ? bvh._roots.length : 0; while (this._roots.length > totalRoots) { const root = this._roots.pop(); root.geometry.dispose(); this.remove(root); } for (let i = 0; i < totalRoots; i++) { if (i >= this._roots.length) { const root2 = new MeshBVHRootVisualizer(this.mesh, this.edgeMaterial, this.depth, i); this.add(root2); this._roots.push(root2); } const root = this._roots[i]; root.depth = this.depth; root.mesh = this.mesh; root.displayParents = this.displayParents; root.displayEdges = this.displayEdges; root.material = this.displayEdges ? this.edgeMaterial : this.meshMaterial; root.update(); } } updateMatrixWorld(...args) { this.position.copy(this.mesh.position); this.rotation.copy(this.mesh.rotation); this.scale.copy(this.mesh.scale); super.updateMatrixWorld(...args); } copy(source) { this.depth = source.depth; this.mesh = source.mesh; } clone() { return new _MeshBVHVisualizer(this.mesh, this.depth); } dispose() { this.edgeMaterial.dispose(); this.meshMaterial.dispose(); const children = this.children; for (let i = 0, l = children.length; i < l; i++) { children[i].geometry.dispose(); } } }; // ../../node_modules/three-mesh-bvh/src/debug/Debug.js var _box1 = new Box3(); var _box2 = new Box3(); var _vec = new Vector3(); function getPrimitiveSize(el) { switch (typeof el) { case "number": return 8; case "string": return el.length * 2; case "boolean": return 4; default: return 0; } } function isTypedArray(arr) { const regex = /(Uint|Int|Float)(8|16|32)Array/; return regex.test(arr.constructor.name); } function getRootExtremes(bvh, group) { const result = { nodeCount: 0, leafNodeCount: 0, depth: { min: Infinity, max: -Infinity }, tris: { min: Infinity, max: -Infinity }, splits: [0, 0, 0], surfaceAreaScore: 0 }; bvh.traverse((depth, isLeaf, boundingData, offsetOrSplit, count) => { const l0 = boundingData[0 + 3] - boundingData[0]; const l1 = boundingData[1 + 3] - boundingData[1]; const l2 = boundingData[2 + 3] - boundingData[2]; const surfaceArea = 2 * (l0 * l1 + l1 * l2 + l2 * l0); result.nodeCount++; if (isLeaf) { result.leafNodeCount++; result.depth.min = Math.min(depth, result.depth.min); result.depth.max = Math.max(depth, result.depth.max); result.tris.min = Math.min(count, result.tris.min); result.tris.max = Math.max(count, result.tris.max); result.surfaceAreaScore += surfaceArea * TRIANGLE_INTERSECT_COST * count; } else { result.splits[offsetOrSplit]++; result.surfaceAreaScore += surfaceArea * TRAVERSAL_COST; } }, group); if (result.tris.min === Infinity) { result.tris.min = 0; result.tris.max = 0; } if (result.depth.min === Infinity) { result.depth.min = 0; result.depth.max = 0; } return result; } function getBVHExtremes(bvh) { return bvh._roots.map((root, i) => getRootExtremes(bvh, i)); } function estimateMemoryInBytes(obj) { const traversed = /* @__PURE__ */ new Set(); const stack = [obj]; let bytes = 0; while (stack.length) { const curr = stack.pop(); if (traversed.has(curr)) { continue; } traversed.add(curr); for (let key in curr) { if (!curr.hasOwnProperty(key)) { continue; } bytes += getPrimitiveSize(key); const value = curr[key]; if (value && (typeof value === "object" || typeof value === "function")) { if (isTypedArray(value)) { bytes += value.byteLength; } else if (value instanceof ArrayBuffer) { bytes += value.byteLength; } else { stack.push(value); } } else { bytes += getPrimitiveSize(value); } } } return bytes; } function validateBounds(bvh) { const geometry = bvh.geometry; const depthStack = []; const index = geometry.index; const position = geometry.getAttribute("position"); let passes = true; bvh.traverse((depth, isLeaf, boundingData, offset, count) => { const info = { depth, isLeaf, boundingData, offset, count }; depthStack[depth] = info; arrayToBox(0, boundingData, _box1); const parent = depthStack[depth - 1]; if (isLeaf) { for (let i = offset * 3, l = (offset + count) * 3; i < l; i += 3) { const i0 = index.getX(i); const i1 = index.getX(i + 1); const i2 = index.getX(i + 2); let isContained; _vec.fromBufferAttribute(position, i0); isContained = _box1.containsPoint(_vec); _vec.fromBufferAttribute(position, i1); isContained = isContained && _box1.containsPoint(_vec); _vec.fromBufferAttribute(position, i2); isContained = isContained && _box1.containsPoint(_vec); console.assert(isContained, "Leaf bounds does not fully contain triangle."); passes = passes && isContained; } } if (parent) { arrayToBox(0, boundingData, _box2); const isContained = _box2.containsBox(_box1); console.assert(isContained, "Parent bounds does not fully contain child."); passes = passes && isContained; } }); return passes; } function getJSONStructure(bvh) { const depthStack = []; bvh.traverse((depth, isLeaf, boundingData, offset, count) => { const info = { bounds: arrayToBox(0, boundingData, new Box3()) }; if (isLeaf) { info.count = count; info.offset = offset; } else { info.left = null; info.right = null; } depthStack[depth] = info; const parent = depthStack[depth - 1]; if (parent) { if (parent.left === null) { parent.left = info; } else { parent.right = info; } } }); return depthStack[0]; } // ../../node_modules/three-mesh-bvh/src/utils/ExtensionUtilities.js var ray = new Ray(); var tmpInverseMatrix = new Matrix4(); var origMeshRaycastFunc = Mesh.prototype.raycast; function acceleratedRaycast(raycaster, intersects) { if (this.geometry.boundsTree) { if (this.material === void 0) return; tmpInverseMatrix.copy(this.matrixWorld).invert(); ray.copy(raycaster.ray).applyMatrix4(tmpInverseMatrix); const bvh = this.geometry.boundsTree; if (raycaster.firstHitOnly === true) { const hit = convertRaycastIntersect(bvh.raycastFirst(ray, this.material), this, raycaster); if (hit) { intersects.push(hit); } } else { const hits = bvh.raycast(ray, this.material); for (let i = 0, l = hits.length; i < l; i++) { const hit = convertRaycastIntersect(hits[i], this, raycaster); if (hit) { intersects.push(hit); } } } } else { origMeshRaycastFunc.call(this, raycaster, intersects); } } function computeBoundsTree(options) { this.boundsTree = new MeshBVH(this, options); return this.boundsTree; } function disposeBoundsTree() { this.boundsTree = null; } // ../../node_modules/three-mesh-bvh/src/gpu/VertexAttributeTexture.js function countToStringFormat(count) { switch (count) { case 1: return "R"; case 2: return "RG"; case 3: return "RGBA"; case 4: return "RGBA"; } throw new Error(); } function countToFormat(count) { switch (count) { case 1: return RedFormat; case 2: return RGFormat; case 3: return RGBAFormat; case 4: return RGBAFormat; } } function countToIntFormat(count) { switch (count) { case 1: return RedIntegerFormat; case 2: return RGIntegerFormat; case 3: return RGBAIntegerFormat; case 4: return RGBAIntegerFormat; } } var VertexAttributeTexture = class extends DataTexture { constructor() { super(); this.minFilter = NearestFilter; this.magFilter = NearestFilter; this.generateMipmaps = false; this.overrideItemSize = null; this._forcedType = null; } updateFrom(attr) { const overrideItemSize = this.overrideItemSize; const originalItemSize = attr.itemSize; const originalCount = attr.count; if (overrideItemSize !== null) { if (originalItemSize * originalCount % overrideItemSize !== 0) { throw new Error("VertexAttributeTexture: overrideItemSize must divide evenly into buffer length."); } attr.itemSize = overrideItemSize; attr.count = originalCount * originalItemSize / overrideItemSize; } const itemSize = attr.itemSize; const count = attr.count; const normalized = attr.normalized; const originalBufferCons = attr.array.constructor; const byteCount = originalBufferCons.BYTES_PER_ELEMENT; let targetType = this._forcedType; let finalStride = itemSize; if (targetType === null) { switch (originalBufferCons) { case Float32Array: targetType = FloatType; break; case Uint8Array: case Uint16Array: case Uint32Array: targetType = UnsignedIntType; break; case Int8Array: case Int16Array: case Int32Array: targetType = IntType; break; } } let type, format, normalizeValue, targetBufferCons; let internalFormat = countToStringFormat(itemSize); switch (targetType) { case FloatType: normalizeValue = 1; format = countToFormat(itemSize); if (normalized && byteCount === 1) { targetBufferCons = originalBufferCons; internalFormat += "8"; if (originalBufferCons === Uint8Array) { type = UnsignedByteType; } else { type = ByteType; internalFormat += "_SNORM"; } } else { targetBufferCons = Float32Array; internalFormat += "32F"; type = FloatType; } break; case IntType: internalFormat += byteCount * 8 + "I"; normalizeValue = normalized ? Math.pow(2, originalBufferCons.BYTES_PER_ELEMENT * 8 - 1) : 1; format = countToIntFormat(itemSize); if (byteCount === 1) { targetBufferCons = Int8Array; type = ByteType; } else if (byteCount === 2) { targetBufferCons = Int16Array; type = ShortType; } else { targetBufferCons = Int32Array; type = IntType; } break; case UnsignedIntType: internalFormat += byteCount * 8 + "UI"; normalizeValue = normalized ? Math.pow(2, originalBufferCons.BYTES_PER_ELEMENT * 8 - 1) : 1; format = countToIntFormat(itemSize); if (byteCount === 1) { targetBufferCons = Uint8Array; type = UnsignedByteType; } else if (byteCount === 2) { targetBufferCons = Uint16Array; type = UnsignedShortType; } else { targetBufferCons = Uint32Array; type = UnsignedIntType; } break; } if (finalStride === 3 && (format === RGBAFormat || format === RGBAIntegerFormat)) { finalStride = 4; } const dimension = Math.ceil(Math.sqrt(count)); const length = finalStride * dimension * dimension; const dataArray = new targetBufferCons(length); const originalNormalized = attr.normalized; attr.normalized = false; for (let i = 0; i < count; i++) { const ii = finalStride * i; dataArray[ii] = attr.getX(i) / normalizeValue; if (itemSize >= 2) { dataArray[ii + 1] = attr.getY(i) / normalizeValue; } if (itemSize >= 3) { dataArray[ii + 2] = attr.getZ(i) / normalizeValue; if (finalStride === 4) { dataArray[ii + 3] = 1; } } if (itemSize >= 4) { dataArray[ii + 3] = attr.getW(i) / normalizeValue; } } attr.normalized = originalNormalized; this.internalFormat = internalFormat; this.format = format; this.type = type; this.image.width = dimension; this.image.height = dimension; this.image.data = dataArray; this.needsUpdate = true; this.dispose(); attr.itemSize = originalItemSize; attr.count = originalCount; } }; var UIntVertexAttributeTexture = class extends VertexAttributeTexture { constructor() { super(); this._forcedType = UnsignedIntType; } }; var IntVertexAttributeTexture = class extends VertexAttributeTexture { constructor() { super(); this._forcedType = IntType; } }; var FloatVertexAttributeTexture = class extends VertexAttributeTexture { constructor() { super(); this._forcedType = FloatType; } }; // ../../node_modules/three-mesh-bvh/src/gpu/MeshBVHUniformStruct.js function bvhToTextures(bvh, boundsTexture, contentsTexture) { const roots = bvh._roots; if (roots.length !== 1) { throw new Error("MeshBVHUniformStruct: Multi-root BVHs not supported."); } const root = roots[0]; const uint16Array = new Uint16Array(root); const uint32Array = new Uint32Array(root); const float32Array = new Float32Array(root); const nodeCount = root.byteLength / BYTES_PER_NODE; const boundsDimension = 2 * Math.ceil(Math.sqrt(nodeCount / 2)); const boundsArray = new Float32Array(4 * boundsDimension * boundsDimension); const contentsDimension = Math.ceil(Math.sqrt(nodeCount)); const contentsArray = new Uint32Array(2 * contentsDimension * contentsDimension); for (let i = 0; i < nodeCount; i++) { const nodeIndex32 = i * BYTES_PER_NODE / 4; const nodeIndex16 = nodeIndex32 * 2; const boundsIndex = BOUNDING_DATA_INDEX(nodeIndex32); for (let b = 0; b < 3; b++) { boundsArray[8 * i + 0 + b] = float32Array[boundsIndex + 0 + b]; boundsArray[8 * i + 4 + b] = float32Array[boundsIndex + 3 + b]; } if (IS_LEAF(nodeIndex16, uint16Array)) { const count = COUNT(nodeIndex16, uint16Array); const offset = OFFSET(nodeIndex32, uint32Array); const mergedLeafCount = 4294901760 | count; contentsArray[i * 2 + 0] = mergedLeafCount; contentsArray[i * 2 + 1] = offset; } else { const rightIndex = 4 * RIGHT_NODE(nodeIndex32, uint32Array) / BYTES_PER_NODE; const splitAxis = SPLIT_AXIS(nodeIndex32, uint32Array); contentsArray[i * 2 + 0] = splitAxis; contentsArray[i * 2 + 1] = rightIndex; } } boundsTexture.image.data = boundsArray; boundsTexture.image.width = boundsDimension; boundsTexture.image.height = boundsDimension; boundsTexture.format = RGBAFormat; boundsTexture.type = FloatType; boundsTexture.internalFormat = "RGBA32F"; boundsTexture.minFilter = NearestFilter; boundsTexture.magFilter = NearestFilter; boundsTexture.generateMipmaps = false; boundsTexture.needsUpdate = true; boundsTexture.dispose(); contentsTexture.image.data = contentsArray; contentsTexture.image.width = contentsDimension; contentsTexture.image.height = contentsDimension; contentsTexture.format = RGIntegerFormat; contentsTexture.type = UnsignedIntType; contentsTexture.internalFormat = "RG32UI"; contentsTexture.minFilter = NearestFilter; contentsTexture.magFilter = NearestFilter; contentsTexture.generateMipmaps = false; contentsTexture.needsUpdate = true; contentsTexture.dispose(); } var MeshBVHUniformStruct = class { constructor() { this.autoDispose = true; this.index = new UIntVertexAttributeTexture(); this.position = new FloatVertexAttributeTexture(); this.bvhBounds = new DataTexture(); this.bvhContents = new DataTexture(); this.index.overrideItemSize = 3; } updateFrom(bvh) { const { geometry } = bvh; bvhToTextures(bvh, this.bvhBounds, this.bvhContents); this.index.updateFrom(geometry.index); this.position.updateFrom(geometry.attributes.position); } dispose() { const { index, position, bvhBounds, bvhContents } = this; if (index) index.dispose(); if (position) position.dispose(); if (bvhBounds) bvhBounds.dispose(); if (bvhContents) bvhContents.dispose(); } }; // ../../node_modules/three-mesh-bvh/src/gpu/shaderFunctions.js var shaderStructs = ( /* glsl */ ` #ifndef TRI_INTERSECT_EPSILON #define TRI_INTERSECT_EPSILON 1e-5 #endif #ifndef INFINITY #define INFINITY 1e20 #endif struct BVH { usampler2D index; sampler2D position; sampler2D bvhBounds; usampler2D bvhContents; }; // Note that a struct cannot be used for the hit record including faceIndices, faceNormal, barycoord, // side, and dist because on some mobile GPUS (such as Adreno) numbers are afforded less precision specifically // when in a struct leading to inaccurate hit results. See KhronosGroup/WebGL#3351 for more details. ` ); var shaderIntersectFunction = ( /* glsl */ ` uvec4 uTexelFetch1D( usampler2D tex, uint index ) { uint width = uint( textureSize( tex, 0 ).x ); uvec2 uv; uv.x = index % width; uv.y = index / width; return texelFetch( tex, ivec2( uv ), 0 ); } ivec4 iTexelFetch1D( isampler2D tex, uint index ) { uint width = uint( textureSize( tex, 0 ).x ); uvec2 uv; uv.x = index % width; uv.y = index / width; return texelFetch( tex, ivec2( uv ), 0 ); } vec4 texelFetch1D( sampler2D tex, uint index ) { uint width = uint( textureSize( tex, 0 ).x ); uvec2 uv; uv.x = index % width; uv.y = index / width; return texelFetch( tex, ivec2( uv ), 0 ); } vec4 textureSampleBarycoord( sampler2D tex, vec3 barycoord, uvec3 faceIndices ) { return barycoord.x * texelFetch1D( tex, faceIndices.x ) + barycoord.y * texelFetch1D( tex, faceIndices.y ) + barycoord.z * texelFetch1D( tex, faceIndices.z ); } void ndcToCameraRay( vec2 coord, mat4 cameraWorld, mat4 invProjectionMatrix, out vec3 rayOrigin, out vec3 rayDirection ) { // get camera look direction and near plane for camera clipping vec4 lookDirection = cameraWorld * vec4( 0.0, 0.0, - 1.0, 0.0 ); vec4 nearVector = invProjectionMatrix * vec4( 0.0, 0.0, - 1.0, 1.0 ); float near = abs( nearVector.z / nearVector.w ); // get the camera direction and position from camera matrices vec4 origin = cameraWorld * vec4( 0.0, 0.0, 0.0, 1.0 ); vec4 direction = invProjectionMatrix * vec4( coord, 0.5, 1.0 ); direction /= direction.w; direction = cameraWorld * direction - origin; // slide the origin along the ray until it sits at the near clip plane position origin.xyz += direction.xyz * near / dot( direction, lookDirection ); rayOrigin = origin.xyz; rayDirection = direction.xyz; } float intersectsBounds( vec3 rayOrigin, vec3 rayDirection, vec3 boundsMin, vec3 boundsMax ) { // https://www.reddit.com/r/opengl/comments/8ntzz5/fast_glsl_ray_box_intersection/ // https://tavianator.com/2011/ray_box.html vec3 invDir = 1.0 / rayDirection; // find intersection distances for each plane vec3 tMinPlane = invDir * ( boundsMin - rayOrigin ); vec3 tMaxPlane = invDir * ( boundsMax - rayOrigin ); // get the min and max distances from each intersection vec3 tMinHit = min( tMaxPlane, tMinPlane ); vec3 tMaxHit = max( tMaxPlane, tMinPlane ); // get the furthest hit distance vec2 t = max( tMinHit.xx, tMinHit.yz ); float t0 = max( t.x, t.y ); // get the minimum hit distance t = min( tMaxHit.xx, tMaxHit.yz ); float t1 = min( t.x, t.y ); // set distance to 0.0 if the ray starts inside the box float dist = max( t0, 0.0 ); return t1 >= dist ? dist : INFINITY; } bool intersectsTriangle( vec3 rayOrigin, vec3 rayDirection, vec3 a, vec3 b, vec3 c, out vec3 barycoord, out vec3 norm, out float dist, out float side ) { // https://stackoverflow.com/questions/42740765/intersection-between-line-and-triangle-in-3d vec3 edge1 = b - a; vec3 edge2 = c - a; norm = cross( edge1, edge2 ); float det = - dot( rayDirection, norm ); float invdet = 1.0 / det; vec3 AO = rayOrigin - a; vec3 DAO = cross( AO, rayDirection ); vec4 uvt; uvt.x = dot( edge2, DAO ) * invdet; uvt.y = - dot( edge1, DAO ) * invdet; uvt.z = dot( AO, norm ) * invdet; uvt.w = 1.0 - uvt.x - uvt.y; // set the hit information barycoord = uvt.wxy; // arranged in A, B, C order dist = uvt.z; side = sign( det ); norm = side * normalize( norm ); // add an epsilon to avoid misses between triangles uvt += vec4( TRI_INTERSECT_EPSILON ); return all( greaterThanEqual( uvt, vec4( 0.0 ) ) ); } bool intersectTriangles( BVH bvh, vec3 rayOrigin, vec3 rayDirection, uint offset, uint count, inout float minDistance, // output variables out uvec4 faceIndices, out vec3 faceNormal, out vec3 barycoord, out float side, out float dist ) { bool found = false; vec3 localBarycoord, localNormal; float localDist, localSide; for ( uint i = offset, l = offset + count; i < l; i ++ ) { uvec3 indices = uTexelFetch1D( bvh.index, i ).xyz; vec3 a = texelFetch1D( bvh.position, indices.x ).rgb; vec3 b = texelFetch1D( bvh.position, indices.y ).rgb; vec3 c = texelFetch1D( bvh.position, indices.z ).rgb; if ( intersectsTriangle( rayOrigin, rayDirection, a, b, c, localBarycoord, localNormal, localDist, localSide ) && localDist < minDistance ) { found = true; minDistance = localDist; faceIndices = uvec4( indices.xyz, i ); faceNormal = localNormal; side = localSide; barycoord = localBarycoord; dist = localDist; } } return found; } float intersectsBVHNodeBounds( vec3 rayOrigin, vec3 rayDirection, BVH bvh, uint currNodeIndex ) { vec3 boundsMin = texelFetch1D( bvh.bvhBounds, currNodeIndex * 2u + 0u ).xyz; vec3 boundsMax = texelFetch1D( bvh.bvhBounds, currNodeIndex * 2u + 1u ).xyz; return intersectsBounds( rayOrigin, rayDirection, boundsMin, boundsMax ); } bool bvhIntersectFirstHit( BVH bvh, vec3 rayOrigin, vec3 rayDirection, // output variables out uvec4 faceIndices, out vec3 faceNormal, out vec3 barycoord, out float side, out float dist ) { // stack needs to be twice as long as the deepest tree we expect because // we push both the left and right child onto the stack every traversal int ptr = 0; uint stack[ 60 ]; stack[ 0 ] = 0u; float triangleDistance = 1e20; bool found = false; while ( ptr > - 1 && ptr < 60 ) { uint currNodeIndex = stack[ ptr ]; ptr --; // check if we intersect the current bounds float boundsHitDistance = intersectsBVHNodeBounds( rayOrigin, rayDirection, bvh, currNodeIndex ); if ( boundsHitDistance == INFINITY || boundsHitDistance > triangleDistance ) { continue; } uvec2 boundsInfo = uTexelFetch1D( bvh.bvhContents, currNodeIndex ).xy; bool isLeaf = bool( boundsInfo.x & 0xffff0000u ); if ( isLeaf ) { uint count = boundsInfo.x & 0x0000ffffu; uint offset = boundsInfo.y; found = intersectTriangles( bvh, rayOrigin, rayDirection, offset, count, triangleDistance, faceIndices, faceNormal, barycoord, side, dist ) || found; } else { uint leftIndex = currNodeIndex + 1u; uint splitAxis = boundsInfo.x & 0x0000ffffu; uint rightIndex = boundsInfo.y; bool leftToRight = rayDirection[ splitAxis ] >= 0.0; uint c1 = leftToRight ? leftIndex : rightIndex; uint c2 = leftToRight ? rightIndex : leftIndex; // set c2 in the stack so we traverse it later. We need to keep track of a pointer in // the stack while we traverse. The second pointer added is the one that will be // traversed first ptr ++; stack[ ptr ] = c2; ptr ++; stack[ ptr ] = c1; } } return found; } ` ); // ../../node_modules/three-mesh-bvh/src/utils/StaticGeometryGenerator.js var _positionVector = new Vector3(); var _normalVector = new Vector3(); var _tangentVector = new Vector3(); var _tangentVector4 = new Vector4(); var _morphVector = new Vector3(); var _temp = new Vector3(); var _skinIndex = new Vector4(); var _skinWeight = new Vector4(); var _matrix = new Matrix4(); var _boneMatrix = new Matrix4(); function validateAttributes(attr1, attr2) { if (!attr1 && !attr2) { return; } const sameCount = attr1.count === attr2.count; const sameNormalized = attr1.normalized === attr2.normalized; const sameType = attr1.array.constructor === attr2.array.constructor; const sameItemSize = attr1.itemSize === attr2.itemSize; if (!sameCount || !sameNormalized || !sameType || !sameItemSize) { throw new Error(); } } function createAttributeClone(attr, countOverride = null) { const cons = attr.array.constructor; const normalized = attr.normalized; const itemSize = attr.itemSize; const count = countOverride === null ? attr.count : countOverride; return new BufferAttribute(new cons(itemSize * count), itemSize, normalized); } function copyAttributeContents(attr, target, targetOffset = 0) { if (attr.isInterleavedBufferAttribute) { const itemSize = attr.itemSize; for (let i = 0, l = attr.count; i < l; i++) { const io = i + targetOffset; target.setX(io, attr.getX(i)); if (itemSize >= 2) target.setY(io, attr.getY(i)); if (itemSize >= 3) target.setZ(io, attr.getZ(i)); if (itemSize >= 4) target.setW(io, attr.getW(i)); } } else { const array = target.array; const cons = array.constructor; const byteOffset = array.BYTES_PER_ELEMENT * attr.itemSize * targetOffset; const temp5 = new cons(array.buffer, byteOffset, attr.array.length); temp5.set(attr.array); } } function addScaledMatrix(target, matrix, scale) { const targetArray = target.elements; const matrixArray = matrix.elements; for (let i = 0, l = matrixArray.length; i < l; i++) { targetArray[i] += matrixArray[i] * scale; } } function boneNormalTransform(mesh, index, target) { const skeleton = mesh.skeleton; const geometry = mesh.geometry; const bones = skeleton.bones; const boneInverses = skeleton.boneInverses; _skinIndex.fromBufferAttribute(geometry.attributes.skinIndex, index); _skinWeight.fromBufferAttribute(geometry.attributes.skinWeight, index); _matrix.elements.fill(0); for (let i = 0; i < 4; i++) { const weight = _skinWeight.getComponent(i); if (weight !== 0) { const boneIndex = _skinIndex.getComponent(i); _boneMatrix.multiplyMatrices(bones[boneIndex].matrixWorld, boneInverses[boneIndex]); addScaledMatrix(_matrix, _boneMatrix, weight); } } _matrix.multiply(mesh.bindMatrix).premultiply(mesh.bindMatrixInverse); target.transformDirection(_matrix); return target; } function applyMorphTarget(morphData, morphInfluences, morphTargetsRelative, i, target) { _morphVector.set(0, 0, 0); for (let j = 0, jl = morphData.length; j < jl; j++) { const influence = morphInfluences[j]; const morphAttribute = morphData[j]; if (influence === 0) continue; _temp.fromBufferAttribute(morphAttribute, i); if (morphTargetsRelative) { _morphVector.addScaledVector(_temp, influence); } else { _morphVector.addScaledVector(_temp.sub(target), influence); } } target.add(_morphVector); } function mergeBufferGeometries(geometries, options = { useGroups: false, updateIndex: false }, targetGeometry = new BufferGeometry()) { const isIndexed = geometries[0].index !== null; const { useGroups, updateIndex } = options; const attributesUsed = new Set(Object.keys(geometries[0].attributes)); const attributes = {}; let offset = 0; for (let i = 0; i < geometries.length; ++i) { const geometry = geometries[i]; let attributesCount = 0; if (isIndexed !== (geometry.index !== null)) { throw new Error("StaticGeometryGenerator: All geometries must have compatible attributes; make sure index attribute exists among all geometries, or in none of them."); } for (const name in geometry.attributes) { if (!attributesUsed.has(name)) { throw new Error('StaticGeometryGenerator: All geometries must have compatible attributes; make sure "' + name + '" attribute exists among all geometries, or in none of them.'); } if (attributes[name] === void 0) { attributes[name] = []; } attributes[name].push(geometry.attributes[name]); attributesCount++; } if (attributesCount !== attributesUsed.size) { throw new Error("StaticGeometryGenerator: Make sure all geometries have the same number of attributes."); } if (useGroups) { let count; if (isIndexed) { count = geometry.index.count; } else if (geometry.attributes.position !== void 0) { count = geometry.attributes.position.count; } else { throw new Error("StaticGeometryGenerator: The geometry must have either an index or a position attribute"); } targetGeometry.addGroup(offset, count, i); offset += count; } } if (isIndexed) { let forceUpateIndex = false; if (!targetGeometry.index) { let indexCount = 0; for (let i = 0; i < geometries.length; ++i) { indexCount += geometries[i].index.count; } targetGeometry.setIndex(new BufferAttribute(new Uint32Array(indexCount), 1, false)); forceUpateIndex = true; } if (updateIndex || forceUpateIndex) { const targetIndex = targetGeometry.index; let targetOffset = 0; let indexOffset = 0; for (let i = 0; i < geometries.length; ++i) { const geometry = geometries[i]; const index = geometry.index; for (let j = 0; j < index.count; ++j) { targetIndex.setX(targetOffset, index.getX(j) + indexOffset); targetOffset++; } indexOffset += geometry.attributes.position.count; } } } for (const name in attributes) { const attrList = attributes[name]; if (!(name in targetGeometry.attributes)) { let count = 0; for (const key in attrList) { count += attrList[key].count; } targetGeometry.setAttribute(name, createAttributeClone(attributes[name][0], count)); } const targetAttribute = targetGeometry.attributes[name]; let offset2 = 0; for (const key in attrList) { const attr = attrList[key]; copyAttributeContents(attr, targetAttribute, offset2); offset2 += attr.count; } } return targetGeometry; } var StaticGeometryGenerator = class { constructor(meshes) { if (!Array.isArray(meshes)) { meshes = [meshes]; } const finalMeshes = []; meshes.forEach((object) => { object.traverse((c) => { if (c.isMesh) { finalMeshes.push(c); } }); }); this.meshes = finalMeshes; this.useGroups = true; this.applyWorldTransforms = true; this.attributes = ["position", "normal", "tangent", "uv", "uv2"]; this._intermediateGeometry = new Array(finalMeshes.length).fill().map(() => new BufferGeometry()); } getMaterials() { const materials = []; this.meshes.forEach((mesh) => { if (Array.isArray(mesh.material)) { materials.push(...mesh.material); } else { materials.push(mesh.material); } }); return materials; } generate(targetGeometry = new BufferGeometry()) { const { meshes, useGroups, _intermediateGeometry } = this; for (let i = 0, l = meshes.length; i < l; i++) { const mesh = meshes[i]; const geom = _intermediateGeometry[i]; this._convertToStaticGeometry(mesh, geom); } mergeBufferGeometries(_intermediateGeometry, { useGroups }, targetGeometry); for (const key in targetGeometry.attributes) { targetGeometry.attributes[key].needsUpdate = true; } return targetGeometry; } _convertToStaticGeometry(mesh, targetGeometry = new BufferGeometry()) { const geometry = mesh.geometry; const applyWorldTransforms = this.applyWorldTransforms; const includeNormal = this.attributes.includes("normal"); const includeTangent = this.attributes.includes("tangent"); const attributes = geometry.attributes; const targetAttributes = targetGeometry.attributes; if (!targetGeometry.index) { targetGeometry.index = geometry.index; } if (!targetAttributes.position) { targetGeometry.setAttribute("position", createAttributeClone(attributes.position)); } if (includeNormal && !targetAttributes.normal && attributes.normal) { targetGeometry.setAttribute("normal", createAttributeClone(attributes.normal)); } if (includeTangent && !targetAttributes.tangent && attributes.tangent) { targetGeometry.setAttribute("tangent", createAttributeClone(attributes.tangent)); } validateAttributes(geometry.index, targetGeometry.index); validateAttributes(attributes.position, targetAttributes.position); if (includeNormal) { validateAttributes(attributes.normal, targetAttributes.normal); } if (includeTangent) { validateAttributes(attributes.tangent, targetAttributes.tangent); } const position = attributes.position; const normal = includeNormal ? attributes.normal : null; const tangent = includeTangent ? attributes.tangent : null; const morphPosition = geometry.morphAttributes.position; const morphNormal = geometry.morphAttributes.normal; const morphTangent = geometry.morphAttributes.tangent; const morphTargetsRelative = geometry.morphTargetsRelative; const morphInfluences = mesh.morphTargetInfluences; const normalMatrix = new Matrix3(); normalMatrix.getNormalMatrix(mesh.matrixWorld); for (let i = 0, l = attributes.position.count; i < l; i++) { _positionVector.fromBufferAttribute(position, i); if (normal) { _normalVector.fromBufferAttribute(normal, i); } if (tangent) { _tangentVector4.fromBufferAttribute(tangent, i); _tangentVector.fromBufferAttribute(tangent, i); } if (morphInfluences) { if (morphPosition) { applyMorphTarget(morphPosition, morphInfluences, morphTargetsRelative, i, _positionVector); } if (morphNormal) { applyMorphTarget(morphNormal, morphInfluences, morphTargetsRelative, i, _normalVector); } if (morphTangent) { applyMorphTarget(morphTangent, morphInfluences, morphTargetsRelative, i, _tangentVector); } } if (mesh.isSkinnedMesh) { mesh.boneTransform(i, _positionVector); if (normal) { boneNormalTransform(mesh, i, _normalVector); } if (tangent) { boneNormalTransform(mesh, i, _tangentVector); } } if (applyWorldTransforms) { _positionVector.applyMatrix4(mesh.matrixWorld); } targetAttributes.position.setXYZ(i, _positionVector.x, _positionVector.y, _positionVector.z); if (normal) { if (applyWorldTransforms) { _normalVector.applyNormalMatrix(normalMatrix); } targetAttributes.normal.setXYZ(i, _normalVector.x, _normalVector.y, _normalVector.z); } if (tangent) { if (applyWorldTransforms) { _tangentVector.transformDirection(mesh.matrixWorld); } targetAttributes.tangent.setXYZW(i, _tangentVector.x, _tangentVector.y, _tangentVector.z, _tangentVector4.w); } } for (const i in this.attributes) { const key = this.attributes[i]; if (key === "position" || key === "tangent" || key === "normal" || !(key in attributes)) { continue; } if (!targetAttributes[key]) { targetGeometry.setAttribute(key, createAttributeClone(attributes[key])); } validateAttributes(attributes[key], targetAttributes[key]); copyAttributeContents(attributes[key], targetAttributes[key]); } return targetGeometry; } }; export { AVERAGE, CENTER, CONTAINED, ExtendedTriangle, FloatVertexAttributeTexture, INTERSECTED, IntVertexAttributeTexture, MeshBVH, MeshBVHUniformStruct, MeshBVHVisualizer, NOT_INTERSECTED, OrientedBox, SAH, StaticGeometryGenerator, UIntVertexAttributeTexture, VertexAttributeTexture, acceleratedRaycast, computeBoundsTree, disposeBoundsTree, estimateMemoryInBytes, getBVHExtremes, getJSONStructure, getTriangleHitPointInfo, shaderIntersectFunction, shaderStructs, validateBounds }; //# sourceMappingURL=three-mesh-bvh.js.map