diff --git a/OctreeCSG.extended.js b/OctreeCSG/OctreeCSG.extended.js similarity index 100% rename from OctreeCSG.extended.js rename to OctreeCSG/OctreeCSG.extended.js diff --git a/OctreeCSG.js b/OctreeCSG/OctreeCSG.js similarity index 100% rename from OctreeCSG.js rename to OctreeCSG/OctreeCSG.js diff --git a/OctreeCSG.worker.js b/OctreeCSG/OctreeCSG.worker.js similarity index 100% rename from OctreeCSG.worker.js rename to OctreeCSG/OctreeCSG.worker.js diff --git a/test/OctreeCSG/three-triangle-intersection.js b/OctreeCSG/three-triangle-intersection.js similarity index 100% rename from test/OctreeCSG/three-triangle-intersection.js rename to OctreeCSG/three-triangle-intersection.js diff --git a/test/OTCSGDemo.html b/test/OTCSGDemo.html deleted file mode 100644 index 4104b18..0000000 --- a/test/OTCSGDemo.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/test/OTCSGDemo.js b/test/OTCSGDemo.js deleted file mode 100644 index 0bf6cbd..0000000 --- a/test/OTCSGDemo.js +++ /dev/null @@ -1,249 +0,0 @@ - -import * as THREE from 'three'; -import {OrbitControls} from 'threeModules/controls/OrbitControls.js'; -//import {TorusKnotGeometry} from 'threeModules/geometries/TorusKnotGeometry.js'; -import CSG from "./three-csg.js" -import app from "./app3.js" -import OctreeCSG from "OctreeCSG/OctreeCSG.js" -import { computeBoundsTree, disposeBoundsTree, acceleratedRaycast } from './three-mesh-bvh.module.js'; - -const computeBoundsTree_original = THREE.BufferGeometry.prototype.computeBoundsTree; -const disposeBoundsTree_original = THREE.BufferGeometry.prototype.disposeBoundsTree; -const raycast_original = THREE.Mesh.prototype.raycast; -window.OctreeCSG = OctreeCSG; -let {renderer,scene,camera} = app; - -//UI(app); -let tx = app.environment.makeProceduralTexture(256,(u,v)=>{ - let rb = ((Math.random()*128)|0) * (((((u*2)&1)^((v*2)&1))|0)?1:2) - return (rb*256)|(rb*256*256)|(rb*256*256*256)|0x000000ff -}) -tx.repeat.set(2,2); -tx.wrapS = tx.wrapT = THREE.RepeatWrapping - -let mkMat=(color) => new THREE.MeshStandardMaterial({color:color,roughness:1,metalness:0.8,map:tx}); -let rnd=(rng)=>((Math.random()*2)-1)*(rng||1) - -let testMeshes = { - sphere:new THREE.Mesh(new THREE.SphereGeometry(1.2,8,8),mkMat('grey')), - box: new THREE.Mesh(new THREE.BoxGeometry(2,2,2),mkMat('grey')), - torusknot: new THREE.Mesh(new THREE.TorusKnotGeometry(1, .4, 30, 4),mkMat('grey')), -} -let meshNames=Object.keys(testMeshes) -let objA = 0; -let objB = 1; - - -let animating = true -let stepping = false -let logPositionsFlag = false; - -let meshA = testMeshes[meshNames[objA]].clone(); -scene.add(meshA) - -let meshB = testMeshes[meshNames[objB]].clone(); -scene.add(meshB) - - -function doCSGbrute(a,b,op,mat){ - let bspA = CSG.fromMesh( a ); - let bspB = CSG.fromMesh( b ); - let bspC = bspA[op]( bspB ); - let result = CSG.toMesh( bspC, a.matrix ); - result.material = mat; - result.castShadow = result.receiveShadow = true; - result.csgOp = op; - return result; -} -function doCSGoctree(a,b,op,mat){ - let bspA = OctreeCSG.fromMesh( a ); - let bspB = OctreeCSG.fromMesh( b ); - let bspC = OctreeCSG[op]( bspA,bspB ); - let result = OctreeCSG.toMesh( bspC , a.material);//, a.matrix ); - result.material = mat; - result.castShadow = result.receiveShadow = true; - result.csgOp = op; - return result; -} -function doCSGoctreeBVH(a,b,op,mat){ - a.geometry.computeBoundsTree(); - b.geometry.computeBoundsTree(); - let bspA = OctreeCSG.fromMesh( a ); - let bspB = OctreeCSG.fromMesh( b ); - let bspC = OctreeCSG[op]( bspA,bspB ); - let result = OctreeCSG.toMesh( bspC , a.material);//, a.matrix ); - result.material = mat; - result.castShadow = result.receiveShadow = true; - a.geometry.disposeBoundsTree(); - b.geometry.disposeBoundsTree(); - result.csgOp = op; - return result; -} - -let subMaterial = mkMat('red') -let intersectMaterial = mkMat('green') -let unionMaterial = mkMat('blue'); -let results = [] - -let mats=[subMaterial,intersectMaterial,unionMaterial] - -let csgMethods={ - 'brute':doCSGbrute, - 'octree':doCSGoctree, - 'octree + mesh-bvh':doCSGoctreeBVH -} -let csgMethodsNames = Object.keys(csgMethods); - -let curCSGMethod = 1; -let csgMethod = csgMethods[csgMethodsNames[curCSGMethod]] - -let info = document.createElement('span') - -Object.assign(info.style,{ - position: 'absolute', - zIndex: 10, - left: '10px', - top: '10px', - fontFamily: 'Arial, Helvetica, sans-serif', - color: 'white', - background: 'rgba(50,50,50,.5)'}) -document.body.appendChild(info) - -let timeTaken=0; -let heap = 0; -let heapLow = 0; -let heapHigh = 0; -let heapChange = 0; -let mb=v=>(v/1000000)|0 -let updateInfo=()=>{ - let ntris=0; - results.forEach(m=>ntris+=m.geometry.attributes.position.count) - info.innerHTML = `[W] - wireframe
-[Space] - change method
-[Q] - objA:${meshNames[objA]}
-[E] - objB:${meshNames[objB]}
-[A] - animate
-[D] - step
-current method:${csgMethodsNames[curCSGMethod]}
-time taken: ${timeTaken.toFixed(2)}
-triangles: ${ntris}
-heap low (mb) : ${mb(heapLow)}
-heap high (mb): ${mb(heapHigh)}
-heap (mb) : ${mb(heap)}
-used -` -} - -let step = 0; -window.addEventListener("keydown", (e)=>{ -if(e.code=='KeyW'){ - scene.traverse(e=>e.isMesh&&((e.material.length&&(e.material.forEach(m=>m.wireframe=!m.wireframe)))||(e.material.wireframe = !e.material.wireframe))) - mats.forEach(m=>m.wireframe=!m.wireframe) -}else if(e.code=='Space'){ - curCSGMethod = (curCSGMethod + 1) % csgMethodsNames.length; - csgMethod = csgMethods[csgMethodsNames[curCSGMethod]]; - if (curCSGMethod == 2) { // octree + mesh-bvh - THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree; - THREE.BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree; - THREE.Mesh.prototype.raycast = acceleratedRaycast; - meshA.geometry.computeBoundsTree = computeBoundsTree; - meshA.geometry.disposeBoundsTree = disposeBoundsTree; - meshA.raycast = acceleratedRaycast; - meshB.geometry.computeBoundsTree = computeBoundsTree; - meshB.geometry.disposeBoundsTree = disposeBoundsTree; - meshB.raycast = acceleratedRaycast; - } - else { - THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree_original; - THREE.BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree_original; - THREE.Mesh.prototype.raycast = raycast_original; - meshA.geometry.computeBoundsTree = computeBoundsTree_original; - meshA.geometry.disposeBoundsTree = disposeBoundsTree_original; - meshA.raycast = raycast_original; - meshB.geometry.computeBoundsTree = computeBoundsTree_original; - meshB.geometry.disposeBoundsTree = disposeBoundsTree_original; - meshB.raycast = raycast_original; - } - - -}else if(e.code=='KeyQ'){ - objA=(objA+1)%meshNames.length; - meshA.geometry=testMeshes[meshNames[objA]].geometry; -}else if(e.code=='KeyE'){ - objB=(objB+1)%meshNames.length; - meshB.geometry=testMeshes[meshNames[objB]].geometry; -}else if(e.code=='KeyA'){ - animating = true; - stepping = false; -}else if(e.code=='KeyD'){ - animating = false; - stepping = true; - step+=16; - logPositionsFlag = true; -} - -}, false); - -function recompute(){ - heapChange = performance.memory.usedJSHeapSize; - timeTaken = performance.now(); - for(let i=0;i{ - //let time = performance.now() - - meshA.position.x=Math.sin(step*0.001)*2; - meshA.position.z=Math.cos(step*0.0011)*0.5; - if(animating){ - step+=16 - recompute(); - } - else if (stepping) { - recompute(); - console.log("meshA position:", meshA.position); - console.log("meshB position:", meshB.position); - stepping = false; - } - //meshA.position.t=Math.sin(time*-0.0012)*0.5; - // if (logPositionsFlag) { - // console.log("meshA position:", meshA.position); - // console.log("meshB position:", meshB.position); - // logPositionsFlag = false; - // } -}) diff --git a/test/OctreeCSG/OctreeCSG.js b/test/OctreeCSG/OctreeCSG.js deleted file mode 100644 index 32f7095..0000000 --- a/test/OctreeCSG/OctreeCSG.js +++ /dev/null @@ -1,3305 +0,0 @@ -// import * as THREE from 'three'; -// const { Vector2, Vector3, Box3, BackSide, DoubleSide, FrontSide, Matrix3, Matrix4, Ray, Triangle, BufferGeometry, BufferAttribute, Mesh, Raycaster } = THREE; -import { Vector2, Vector3, Box3, BackSide, DoubleSide, FrontSide, Matrix3, Matrix4, Ray, Triangle, BufferGeometry, BufferAttribute, Mesh, Raycaster } from 'three'; -import { triangleIntersectsTriangle, checkTrianglesIntersection } from './three-triangle-intersection.js'; -const _v1 = new Vector3(); -const _v2 = new Vector3(); -const _v3 = new Vector3(); -const tmpInverseMatrix = new Matrix4(); -// import * as BVH from '/js/three-mesh-bvh.module.js'; -// console.log("BVH TEST:", BVH); - -const tv0 = new Vector3(); -const tv1 = new Vector3(); -const _raycaster1 = new Raycaster(); -const _ray = new Ray(); -const _ray2 = new Ray(); -const _rayDirection = new Vector3(0, 0, 1); - -// const _raycastDirections = [ -// new Vector3(0, 0, 1), -// new Vector3(0, 1, 0), -// new Vector3(1, 0, 0) -// ]; -// const _raycastDirectionsCount = _raycastDirections.length; - - -let _octreeID = 0; -let _triangleID = 0; -let _polygonID = 0; -const EPSILON = 1e-5; -const COPLANAR = 0; -const FRONT = 1; -const BACK = 2; -const SPANNING = 3; -let testvar = 0; -// const trianglesMap = new Map(); -//const polygonMaps = new Map(); - -class OctreeCSG { - constructor(box, parent) { - // this.octreeMap = new Map(); - // this.isOctree = true; - // this.triangles = []; - this.polygons = []; - // this.polygonMap; - this.mesh; - this.originalMatrixWorld; - // this.bspNode; - this.box = box; - this.subTrees = []; - this.parent = parent; - this.level = 0; - Object.defineProperties(this, { - id: { - value: _octreeID++ - }, - isOctree: { - value: true - } - }); - - } - clone() { - return new this.constructor().copy(this); - } - - copy(source) { - this.polygons = source.polygons.map(p => p.clone()); - if (source.mesh) { - this.mesh = source.mesh; - } - if (source.originalMatrixWorld) { - this.originalMatrixWorld = source.originalMatrixWorld.clone(); - } - this.box = source.box.clone(); - this.level = source.level; - - for (let i = 0; i < source.subTrees.length; i++) { - let subTree = new this.constructor(undefined, this).copy(source.subTrees[i]); - this.subTrees.push(subTree); - } - - return this; - } - testget() { - return testvar; - } - testset() { - testvar++; - } - isEmpty() { - return this.polygons.length === 0; - } - addPolygon(polygon) { - if (!this.bounds) { - this.bounds = new Box3(); - } - let triangle = polygon.triangle; - this.bounds.min.x = Math.min(this.bounds.min.x, triangle.a.x, triangle.b.x, triangle.c.x); - this.bounds.min.y = Math.min(this.bounds.min.y, triangle.a.y, triangle.b.y, triangle.c.y); - this.bounds.min.z = Math.min(this.bounds.min.z, triangle.a.z, triangle.b.z, triangle.c.z); - this.bounds.max.x = Math.max(this.bounds.max.x, triangle.a.x, triangle.b.x, triangle.c.x); - this.bounds.max.y = Math.max(this.bounds.max.y, triangle.a.y, triangle.b.y, triangle.c.y); - this.bounds.max.z = Math.max(this.bounds.max.z, triangle.a.z, triangle.b.z, triangle.c.z); - - this.polygons.push(polygon); - return this; - } - - calcBox() { - if (!this.bounds) { - this.bounds = new Box3(); - } - this.box = this.bounds.clone(); - - // offset small ammount to account for regular grid - this.box.min.x -= 0.01; - this.box.min.y -= 0.01; - this.box.min.z -= 0.01; - - return this; - - } - - split(level) { - - if (!this.box) return; - - const subTrees = []; - const halfsize = _v2.copy(this.box.max).sub(this.box.min).multiplyScalar(0.5); - for (let x = 0; x < 2; x++) { - for (let y = 0; y < 2; y++) { - for (let z = 0; z < 2; z++) { - const box = new Box3(); - const v = _v1.set(x, y, z); - - box.min.copy(this.box.min).add(v.multiply(halfsize)); - box.max.copy(box.min).add(halfsize); - box.expandByScalar(EPSILON); - subTrees.push(new OctreeCSG(box, this)); - } - } - } - // console.log(`Octree (${this.id}) suggested subTrees:`, subTrees); - // let triangle; - let polygon; - // while (triangle = this.triangles.pop()) { - while (polygon = this.polygons.pop()) { - let triangle = polygon.triangle; - let found = false; - for (let i = 0; i < subTrees.length; i++) { - // let triangleMidPoint = Vector3(); - - if (subTrees[i].box.containsPoint(triangle.midPoint)) { - // if (subTrees[i].box.containsPoint(triangle.getMidpoint(_v1))) { - // if (subTrees[i].box.intersectsTriangle(triangle)) { - - // subTrees[i].triangles.push(triangle); - subTrees[i].polygons.push(polygon); - found = true; - } - - } - if (!found) { - console.error("ERROR: unable to find subtree for:", triangle, triangle.getMidpoint(_v1), this, subTrees); - throw new Error(`Unable to find subtree for triangle at level ${level}`); - } - - } - // if (level >= OctreeCSG.maxLevel) { - // console.log(`Warning: Octree reached max level (${level})`); - // } - for (let i = 0; i < subTrees.length; i++) { - subTrees[i].level = level + 1; - const len = subTrees[i].polygons.length; - - if (len > OctreeCSG.polygonsPerTree && level < OctreeCSG.maxLevel) { - - subTrees[i].split(level + 1); - - } - - // if (len !== 0) { - - this.subTrees.push(subTrees[i]); - - // } - - } - - return this; - - } - - buildTree() { - // this.setPolygonMap(new Map()); - // octree.setPolygonMap(); - this.calcBox(); - this.split(0); - this.processTree(); - // console.log("trianglesMap", trianglesMap); - return this; - - } - processTree() { - // this.octreeMap.set(this.id, this); - if (!this.isEmpty()) { - // console.log("triangles in level", this.level, "Octree ID:", this.id); - // let currentBox = this.box.clone(); - // for (let i = 0; i < this.triangles.length; i++) { - for (let i = 0; i < this.polygons.length; i++) { - // OctreeCSG.addPolygonToMap(this.polygonMap, this.polygons[i], this); - // OctreeCSG.addTriangleToMap(trianglesMap, this.triangles[i], this); - this.box.expandByPoint(this.polygons[i].triangle.a); - this.box.expandByPoint(this.polygons[i].triangle.b); - this.box.expandByPoint(this.polygons[i].triangle.c); - // currentBox.expandByPoint(this.triangles[i].a); - // currentBox.expandByPoint(this.triangles[i].b); - // currentBox.expandByPoint(this.triangles[i].c); - - // if (this.polygons[i].source === "a") { - // this.aPolygons.push(this.polygons[i]); - // } - // else if (this.polygons[i].source === "b") { - // this.bPolygons.push(this.polygons[i]); - // } - } - this.expandParentBox(); - // if (!this.box.equals(currentBox)) { - // console.log("bound box changed in tree id", this.id, this.box, currentBox); - // } - } - for (let i = 0; i < this.subTrees.length; i++) { - // this.subTrees[i].setPolygonMap(this.polygonMap); - this.subTrees[i].processTree(); - } - } - expandParentBox() { - if (this.parent) { - this.parent.box.expandByPoint(this.box.min); - this.parent.box.expandByPoint(this.box.max); - this.parent.expandParentBox(); - } - } - // setPolygonMap(map) { - // this.polygonMap = map; - // } - - // Not used - // getRayTriangles(ray, triangles) { - // // console.log("triangles:", triangles); - // for (let i = 0; i < this.subTrees.length; i++) { - - // const subTree = this.subTrees[i]; - // if (!ray.intersectsBox(subTree.box)) { - // // console.log(i, "ray not intersecting", subTree.box); - // continue; - // } - // // console.log(i, "poly count:", subTree.polygons.length); - // // if (subTree.triangles.length > 0) { - // if (subTree.polygons.length > 0) { - // // for (let j = 0; j < subTree.triangles.length; j++) { - // for (let j = 0; j < subTree.polygons.length; j++) { - - // // if (triangles.indexOf(subTree.triangles[j]) === - 1) triangles.push(subTree.triangles[j]); - // if (triangles.indexOf(subTree.polygons[j].triangle) === - 1) { - // // console.log("adding triangle", subTree.polygons[j].triangle); - // triangles.push(subTree.polygons[j].triangle); - // } - // // else { - // // console.log("skipping triangle", subTree.polygons[j].triangle, "all triangles:", triangles); - // // } - - // } - - // } else { - - // subTree.getRayTriangles(ray, triangles); - - // } - - // } - - // return triangles; - - // } - - - // Not used - // increaseTriangleSize(triangle, targetTriangle = new Triangle()) { - // let EPSILON = 0; - // targetTriangle.copy(triangle); - // targetTriangle.a.x += triangle.a.x < 0 ? -EPSILON : EPSILON; - // targetTriangle.a.y += triangle.a.y < 0 ? -EPSILON : EPSILON; - // targetTriangle.a.z += triangle.a.z < 0 ? -EPSILON : EPSILON; - // targetTriangle.b.x += triangle.b.x < 0 ? -EPSILON : EPSILON; - // targetTriangle.b.y += triangle.b.y < 0 ? -EPSILON : EPSILON; - // targetTriangle.b.z += triangle.b.z < 0 ? -EPSILON : EPSILON; - // targetTriangle.c.x += triangle.c.x < 0 ? -EPSILON : EPSILON; - // targetTriangle.c.y += triangle.c.y < 0 ? -EPSILON : EPSILON; - // targetTriangle.c.z += triangle.c.z < 0 ? -EPSILON : EPSILON; - // return targetTriangle; - // } - getPolygonsOnlyIntersectingPolygon(targetPolygon, polygons = []) { - if (targetPolygon.triangle === undefined) { - console.log("UNDEFINED", targetPolygon); - return polygons; - } - if (this.box.intersectsTriangle(targetPolygon.triangle)) { - if (this.polygons.length > 0) { - polygons.push(...this.polygons.filter(p => p.valid)); - } - for (let i = 0; i < this.subTrees.length; i++) { - this.subTrees[i].getPolygonsOnlyIntersectingPolygon(targetPolygon, polygons); - } - } - - return polygons; - } - - - getPolygonsIntersectingPolygon(targetPolygon, debug = false, polygons = []) { - let found = false; - if (this.polygons.length > 0) { - if (targetPolygon.triangle === undefined) { - console.log("UNDEFINED", targetPolygon); - } - // let targetTriangle = this.increaseTriangleSize(targetPolygon.triangle); - let targetTriangle = targetPolygon.triangle; - // let bvhTriangle1 = new BVH.SeparatingAxisTriangle(targetTriangle.a, targetTriangle.b, targetTriangle.c); - if (this.box.intersectsTriangle(targetTriangle)) { - for (let i = 0; i < this.polygons.length; i++) { - let polygon = this.polygons[i]; - // } - // this.polygons.forEach(polygon => { - if (!polygon.valid || !polygon.intersects) { - continue; - } - if (debug) { - // if (((polygon.triangle.a.z == 5) || (polygon.triangle.b.z == 5) || (polygon.triangle.c.z == 5)) && ((polygon.triangle.a.x >= 1) || (polygon.triangle.b.x >= 1) || (polygon.triangle.c.x >= 1))) { - let additionsObj = { - coplanar: false, - source: new Vector3(), - target: new Vector3() - }; - console.log("Testing intersection with polygon:", targetPolygon.id, targetPolygon, polygon, polygon.triangle); - if ((targetTriangle === undefined) || (polygon.triangle === undefined)) { - console.log("UNDEFINED!!!!!", targetPolygon, polygon); - } - // if (triangleIntersectsTriangle(targetTriangle, polygon.triangle, additionsObj)) { - - - // let bvhTriangle2 = new BVH.SeparatingAxisTriangle(polygon.triangle.a, polygon.triangle.b, polygon.triangle.c); - // console.log("BVH Intersect", bvhTriangle1.intersectsTriangle(bvhTriangle2)); - // if (bvhTriangle1.intersectsTriangle(bvhTriangle2)) { - // console.log("found intersecting polygon", polygon); - if (checkTrianglesIntersection(targetTriangle, polygon.triangle, additionsObj)) { - console.log("intersects", additionsObj.triangleCheck, additionsObj); - polygons.push(polygon); - found = true; - } - // else { - // console.log("nope", additionsObj.triangleCheck); - // } - - } - else { - if ((targetTriangle === undefined) || (polygon.triangle === undefined)) { - console.log("UNDEFINED!!!!!", targetPolygon, polygon); - } - // if (triangleIntersectsTriangle(targetTriangle, polygon.triangle)) { - if (checkTrianglesIntersection(targetTriangle, polygon.triangle)) { - polygons.push(polygon); - } - - } - }; - } - } - debug && console.warn("[getPolygonsIntersectingPolygon] FOUND?", found); - - for (let i = 0; i < this.subTrees.length; i++) { - this.subTrees[i].getPolygonsIntersectingPolygon(targetPolygon, debug, polygons); - } - - return polygons; - } - - - // Testing - populatePolygonWithOctree() { - if (this.polygons.length > 0) { - this.polygons.forEach(p => p.octree = this); - } - for (let i = 0; i < this.subTrees.length; i++) { - this.subTrees[i].populatePolygonWithOctree(); - } - } - getRayPolygons(ray, polygons = []) { - // console.log("[getRayPolygons] checking octree", this, this.polygons.length); - if (this.polygons.length > 0) { - for (let i = 0; i < this.polygons.length; i++) { - if (this.polygons[i].valid) { - if (polygons.indexOf(this.polygons[i]) === -1) { - polygons.push(this.polygons[i]); - } - } - } - } - for (let i = 0; i < this.subTrees.length; i++) { - // if (ray.triangle ? this.subTrees[i].box.intersectsTriangle(ray.triangle) : ray.intersectsBox(this.subTrees[i].box)) { - if (ray.intersectsBox(this.subTrees[i].box)) { - this.subTrees[i].getRayPolygons(ray, polygons); - } - } - - return polygons; - } - - // Testing - rayIntersect(ray, matrixWorld, intersects = []) { - - if (ray.direction.length() === 0) return; - if (matrixWorld) { - tmpInverseMatrix.copy(matrixWorld).invert(); - _ray2.copy(ray).applyMatrix4(tmpInverseMatrix); - } - - // three-mesh-bvh - // const distance = ray.origin.distanceTo( point ); - // 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; - - - // three.js - // _intersectionPointWorld.copy(point); - // _intersectionPointWorld.applyMatrix4(object.matrixWorld); - // const distance = raycaster.ray.origin.distanceTo(_intersectionPointWorld); - // if (distance < raycaster.near || distance > raycaster.far) return null; - // return { - // distance: distance, - // point: _intersectionPointWorld.clone(), - // object: object - // }; - - - - - // const polygons = []; - let polygon, position, distance = 1e100; - - // this.getRayTriangles(ray, triangles); - - // let polygons = this.getRayPolygons(ray); - // let polygons = this.getPolygons(); - let polygons = OctreeCSG.getRayPolys ? this.getRayPolygons(ray) : this.getPolygons(); - - OctreeCSG.debugPoly && console.log("[rayIntersect] polygons", polygons, "OctreeCSG.testSide", OctreeCSG.testSide); - for (let i = 0; i < polygons.length; i++) { - let result; - switch (OctreeCSG.rayIntersectTriangleType) { - case "MollerTrumbore": - result = rayIntersectsTriangle(ray, polygons[i].triangle, _v1); - if (result) { - const newdistance = result.clone().sub(ray.origin).length(); - if (distance > newdistance) { - distance = newdistance; - } - if (distance < 1e100) { - // if (distance !== newdistance) { - // console.log("DISTANCE CHECK:", distance, newdistance); - // } - // intersects.push({ distance: newdistance, polygon: polygons[i], position: result.clone().add(ray.origin) }); - intersects.push({ distance: distance, polygon: polygons[i], position: result.clone().add(ray.origin) }); - } - else { - console.log("BIG DISTANCE:", { distance: distance, polygon: polygons[i], position: result.clone().add(ray.origin) }); - } - } - break; - case "regular": - default: - // ray.direction = polygons[i].vertices[0].normal; - // let result = ray.intersectTriangle(polygons[i].triangle.c, polygons[i].triangle.b, polygons[i].triangle.a, true, _v1); // back - result = ray.intersectTriangle(polygons[i].triangle.a, polygons[i].triangle.b, polygons[i].triangle.c, false, _v1); //double - - - // let result = _ray2.intersectTriangle(polygons[i].triangle.a, polygons[i].triangle.b, polygons[i].triangle.c, false, _v1); //double - if (result) { - _v1.applyMatrix4(matrixWorld); - // distance = ray.origin.distanceTo(_v1); - distance = _v1.distanceTo(ray.origin); - // if (distance > 0 && distance < Infinity) { - if (distance < 0 || distance > Infinity) { - console.warn("[rayIntersect] Failed ray distance check", ray); - } - else { - intersects.push({ distance: distance, polygon: polygons[i], position: _v1.clone() }); - } - - - // const newdistance = result.sub(ray.origin).length(); - // if (distance > newdistance) { - // position = result.clone().add(ray.origin); - // distance = newdistance; - // polygon = polygons[i]; - // } - // if (distance < 1e100) { - // intersects.push({ distance: newdistance, polygon: polygons[i], position: result.clone().add(ray.origin) }); - // } - // else { - // console.log("BIG DISTANCE:", { distance: distance, polygon: polygon, position: position }); - // } - - } - break; - } - - OctreeCSG.debugPoly && console.log("[rayIntersect]", i, result); - // Not required since always using DoubleSide check (?) - /* - if (OctreeCSG.testSide == BackSide) { // backside - // console.log("ray testing back"); - result = ray.intersectTriangle(polygons[i].triangle.c, polygons[i].triangle.b, polygons[i].triangle.a, true, _v1); - } - else if (OctreeCSG.testSide == DoubleSide) { // doubleside - // console.log("ray testing double"); - // console.log("OctreeCSG.testSide !== DoubleSide", OctreeCSG.testSide !== DoubleSide, OctreeCSG.testSide); - result = ray.intersectTriangle(polygons[i].triangle.a, polygons[i].triangle.b, polygons[i].triangle.c, false, _v1); - } - else if (OctreeCSG.testSide == FrontSide) { // frontside - // console.log("ray testing front"); - // console.log("OctreeCSG.testSide !== DoubleSide", OctreeCSG.testSide !== DoubleSide, OctreeCSG.testSide); - result = ray.intersectTriangle(polygons[i].triangle.a, polygons[i].triangle.b, polygons[i].triangle.c, true, _v1); - } - // result = ray.intersectTriangle(triangles[i].a, triangles[i].b, triangles[i].c, false, _v1); - */ - - // const result = ray.intersectTriangle(triangles[i].a, triangles[i].b, triangles[i].c, true, _v1); - - // else { - // console.log(i, "nope", result); - // } - - } - // intersectObject(object, recursive = true, intersects = []) { - // intersectObject(object, this, intersects, recursive); - // intersects.sort(ascSort); - // return intersects; - // } - intersects.length && intersects.sort(raycastIntersectAscSort); - return intersects; - // return distance < 1e100 ? { distance: distance, triangle: triangle, position: position } : false; - - } - - getIntersectingPolygons(polygons = []) { - if (this.polygons.length) { - for (let i = 0; i < this.polygons.length; i++) { - if (this.polygons[i].valid && this.polygons[i].intersects) { - polygons.push(this.polygons[i]); - } - } - } - for (let i = 0; i < this.subTrees.length; i++) { - this.subTrees[i].getIntersectingPolygons(polygons); - } - return polygons; - } - getPolygons(polygons = []) { - if (this.polygons.length) { - for (let i = 0; i < this.polygons.length; i++) { - if (this.polygons[i].valid) { - polygons.push(this.polygons[i]); - } - } - } - for (let i = 0; i < this.subTrees.length; i++) { - this.subTrees[i].getPolygons(polygons); - } - return polygons; - } - getInvalidPolygons(polygons = []) { - polygons.push(...this.polygons.filter(p => !p.valid)); - for (let i = 0; i < this.subTrees.length; i++) { - this.subTrees[i].getInvalidPolygons(polygons); - } - - return polygons; - } - invert() { - if (this.polygons.length > 0) { - this.polygons.forEach(p => p.flip()); - } - for (let i = 0; i < this.subTrees.length; i++) { - this.subTrees[i].invert(); - } - } - getMesh() { - if (this.parent) { - return this.parent.getMesh(); - } - return this.mesh; - } - - replacePolygon(polygon, newPolygons, firstRun = true) { - if (!Array.isArray(newPolygons)) { - newPolygons = [newPolygons]; - } - if (this.polygons.length > 0) { - let polygonIndex = this.polygons.indexOf(polygon); - if (polygonIndex > -1) { - // console.log("replacing polygons in tree id", this.id, "old polygon:", polygon, "new polygons:", newPolygons); - polygon.setInvalid(); - this.polygons.splice(polygonIndex, 1, ...newPolygons); - // polygon.delete(); - } - } - for (let i = 0; i < this.subTrees.length; i++) { - this.subTrees[i].replacePolygon(polygon, newPolygons, false); - } - if (firstRun) { - polygon.delete(); - } - } - - - deletePolygonsByStateRules(rulesArr, debug = false, firstRun = true) { - if (this.polygons.length > 0) { - // let polygonArr = this.polygons.slice(); - let polygonArr = this.polygons.filter(polygon => (polygon.valid == true) && (polygon.intersects == true)); - polygonArr.forEach(polygon => { - let found = false; - for (let j = 0; j < rulesArr.length; j++) { - if (rulesArr[j].array) { - let states = rulesArr[j].rule; - if ((states.includes(polygon.state)) && (((polygon.previousState !== "undecided") && (states.includes(polygon.previousState))) || (polygon.previousState == "undecided"))) { - debug && console.log("deletePolygonsByStates A"); - found = true; - let statesObj = {}; - let mainStatesObj = {}; - states.forEach(state => statesObj[state] = false); - states.forEach(state => mainStatesObj[state] = false); - statesObj[polygon.state] = true; - for (let i = 0; i < polygon.previousStates.length; i++) { - if (!states.includes(polygon.previousStates[i])) { // if previous state not one of provided states (not included in states array), break - debug && console.log("deletePolygonsByStates B", polygon.previousStates[i]); - found = false; - break; - } - else { - statesObj[polygon.previousStates[i]] = true; - } - } - debug && console.log("deletePolygonsByStates C"); - if (found) { - debug && console.log("deletePolygonsByStates D"); - // if (polygon.previousState !== "undecided") { // <- NOT TESTED - for (let state in statesObj) { - if (statesObj[state] === false) { - // if (!mainSatisfied) { - debug && console.log("deletePolygonsByStates D2"); - found = false; - // } - break; - } - } - // } - - if (found) { - break; - } - } - } - } - else { - if (polygon.checkAllStates(rulesArr[j].rule)) { - found = true; - break; - } - } - } - if (found) { - debug && console.log("deletePolygonsByStates E"); - let polygonIndex = this.polygons.indexOf(polygon); - if (polygonIndex > -1) { - debug && console.log("deletePolygonsByStates F", polygon); - polygon.setInvalid(); - this.polygons.splice(polygonIndex, 1); - // polygon.delete(); - } - // else { - // polygon.setInvalid(); - // } - if (firstRun) { - polygon.delete(); - } - } - }); - } - for (let i = 0; i < this.subTrees.length; i++) { - this.subTrees[i].deletePolygonsByStateRules(rulesArr, debug, false); - } - } - - deletePolygonsByIntersection(intersects, firstRun = true) { - if (intersects == undefined) { - return; - } - if (this.polygons.length > 0) { - let polygonArr = this.polygons.slice(); - polygonArr.forEach(polygon => { - if (polygon.valid) { - if (polygon.intersects === intersects) { - let polygonIndex = this.polygons.indexOf(polygon); - if (polygonIndex > -1) { - polygon.setInvalid(); - this.polygons.splice(polygonIndex, 1); - // polygon.delete(); - } - // else { - // polygon.setInvalid(); - // } - if (firstRun) { - polygon.delete(); - } - } - } - }); - } - for (let i = 0; i < this.subTrees.length; i++) { - this.subTrees[i].deletePolygonsByIntersection(intersects, false); - } - } - - isPolygonIntersecting(polygon) { - if (!this.box.intersectsTriangle(polygon.triangle)) { - return false; - } - - // Changing to return true if intersecting with box, if looking only for octrees with polygons that intersects it can lead to incorrectly identifying intersecting polygons - return true; - // if (this.polygons.length > 0) { - // return true; - // } - // let isIntersecting = false; - // if (this.subTrees.length > 0) { - // for (let i = 0; i < this.subTrees.length; i++) { - // isIntersecting = this.subTrees[i].isPolygonIntersecting(polygon); - // if (isIntersecting) { - // break; - // } - // } - // } - // return isIntersecting; - } - markIntesectingPolygons(targetOctree) { - if (this.polygons.length > 0) { - this.polygons.forEach(polygon => { - // polygon.intersects = boundingBox.intersectsTriangle(polygon.triangle); - polygon.intersects = targetOctree.isPolygonIntersecting(polygon); - // polygon.intersects = targetOctree.box.intersectsTriangle(polygon.triangle); - }); - } - for (let i = 0; i < this.subTrees.length; i++) { - this.subTrees[i].markIntesectingPolygons(targetOctree); - } - - } - - resetPolygonsByState(state) { - if (this.polygons.length > 0) { - this.polygons.forEach(polygon => { - if (polygon.valid && polygon.intersects) { - if (polygon.state == state && polygon.previousState == "undecided") { - polygon.state = "undecided"; - polygon.checkAll = true; - } - } - // polygon.reset(); - }); - } - for (let i = 0; i < this.subTrees.length; i++) { - this.subTrees[i].resetPolygonsByState(state); - } - } - resetPolygons() { - if (this.polygons.length > 0) { - this.polygons.forEach(polygon => { - polygon.reset(); - }); - } - for (let i = 0; i < this.subTrees.length; i++) { - this.subTrees[i].resetPolygons(); - } - } - handleIntersectingPolygons(targetOctree, targetOctreeBuffer) { - if (this.polygons.length > 0) { - let polygonStack = this.polygons.filter(polygon => (polygon.valid == true) && (polygon.intersects == true) && (polygon.state == "undecided")); - let currentPolygon = polygonStack.pop(); - while (currentPolygon) { - if (currentPolygon.state !== "undecided") { - continue; - } - if (!currentPolygon.valid) { - continue; - } - - let debugPoly = false; - // let testTriangle = new THREE.Triangle(new THREE.Vector3(0.29171404242515564, -4.110300540924072, 2.832019329071045), new THREE.Vector3(-0.29171404242515564, -4.110300540924072, 2.832019329071045), new THREE.Vector3(0, -4.3809967041015625, 2.4097442626953125)); - // if ((OctreeCSG.returnType == -1) && (currentPolygon.triangle.equals(testTriangle))) { - // debugPoly = true; - // console.warn("STARTING DEBUG"); - // } - OctreeCSG.debugPoly = debugPoly; - let targetPolygons = targetOctree.getPolygonsIntersectingPolygon(currentPolygon, debugPoly); - - if (targetPolygons.length > 0) { - if (debugPoly) { - console.log("BLA POLYGON TARGET COUNT", targetPolygons.length); - } - // let needsBreak = false; - for (let j = 0; j < targetPolygons.length; j++) { - let target = targetPolygons[j]; - if (debugPoly) { - console.log("BLA POLYGON", currentPolygon, target); - } - // console.log("needsBreak", needsBreak); - let splitResults = splitPolygonByPlane(currentPolygon, target.plane); - debugPoly && console.log("splitResults", splitResults) - if (splitResults.length > 1) { - // let newPolygons = []; - for (let i = 0; i < splitResults.length; i++) { - let polygon = splitResults[i].polygon; - polygon.intersects = currentPolygon.intersects; - polygon.splitState1 = splitResults[i].type; - // if (splitResults[i].type == "back") { - polygonStack.push(polygon); - // } - // else { - // polygon.setState(splitResults[i].type); - // } - - } - this.replacePolygon(currentPolygon, splitResults.map(result => result.polygon)); - // needsBreak = true; - break; - } - else { - if (currentPolygon.id !== splitResults[0].polygon.id) { - splitResults[0].polygon.intersects = currentPolygon.intersects; - splitResults[0].polygon.splitState2 = splitResults[0].type; - // if (splitResults[0].type == "back") { - polygonStack.push(splitResults[0].polygon); - // } - // else { - // splitResults[0].polygon.setState(splitResults[0].type); - // } - this.replacePolygon(currentPolygon, splitResults[0].polygon); - break; - } - else { - if ((splitResults[0].type == "coplanar-front") || (splitResults[0].type == "coplanar-back")) { - currentPolygon.setState(splitResults[0].type); - currentPolygon.coplanar = true; - } - } - } - // if (needsBreak) { - // break; - // } - // console.log(j, currentPolygon, target, splitResults); - - // let polyType = getPolygonType(currentPolygon, target.plane); - // // console.log(i, currentPolygon, target, polyType); - // let polyType2 = getRayIntersectionType(currentPolygon, target, aMatrixWorld); - // console.log(i, "getRayIntersectionType", polyType2); - } - } - else { - debugPoly && console.log("[handleIntersectingPolygons] Not intersecting with any target polygons", currentPolygon); - } - - // if (iteration >= 100) { - // break; - // } - // console.log("--------------------"); - currentPolygon = polygonStack.pop(); - } - - // console.log("ASDADASD", this.polygons); - // if (OctreeCSG.useWindingNumber === true && targetOctreeAllPolygons === undefined) { - // console.log("[handleIntersectingPolygons] targetOctreeAllPolygons === undefined"); - // targetOctreeAllPolygons = targetOctree.getPolygons(); - // } - polygonStack = this.polygons.filter(polygon => (polygon.valid == true) && (polygon.intersects == true)); - currentPolygon = polygonStack.pop(); - while (currentPolygon) { - // if (currentPolygon.state !== "undecided") { - // continue; - // } - if (!currentPolygon.valid) { - continue; - } - - let debugPoly = false; - - // let testTriangle = new THREE.Triangle(new THREE.Vector3(0.29171404242515564, -4.110300540924072, 2.832019329071045), new THREE.Vector3(-0.29171404242515564, -4.110300540924072, 2.832019329071045), new THREE.Vector3(0, -4.3809967041015625, 2.4097442626953125)); - // if ((OctreeCSG.returnType == -1) && (currentPolygon.triangle.equals(testTriangle))) { - // debugPoly = true; - // console.warn("STARTING DEBUG"); - // } - OctreeCSG.debugPoly = debugPoly; - let inside = false; - if (targetOctree.box.containsPoint(currentPolygon.triangle.midPoint)) { - if (OctreeCSG.useWindingNumber === true) { - inside = polyInside_WindingNumber_buffer(targetOctreeBuffer, currentPolygon.triangle.midPoint, currentPolygon.coplanar); - } - else { - let point = pointRounding(_v2.copy(currentPolygon.triangle.midPoint)); - // let point = currentPolygon.triangle.midPoint; - - // let point = pointRounding(currentPolygon.triangle.getMidpoint(_v2)); - debugPoly && console.log("point for currentPolygon", point.clone(), currentPolygon); - // let point = currentPolygon.triangle.getMidpoint(_v2); - // _rayDirection.copy(currentPolygon.plane.normal).normalize(); - - - - if (OctreeCSG.useOctreeRay !== true) { - // _ray.origin.copy(point); - _rayDirection.copy(currentPolygon.plane.normal); - // _raycaster1.ray.origin.copy(point); - // _raycaster1.set(point, _rayDirection); - // for (let i = 0; i < _raycastDirectionsCount; i++) { - // _raycaster1.ray.direction.copy(_raycastDirections[i]); - // let intersects = _raycaster1.intersectObject(targetOctree.mesh); - // // console.log(i, "Intersects?", intersects); - // if (debugPoly) { - // console.log("RAY CHECK intersects.length", intersects.length, point, _raycastDirections[i]); - // } - // if (intersects.length) { - - // if (_raycastDirections[i].dot(intersects[0].face.normal) > 0) { - // debugPoly && console.log(i, "Point is inside the object", _raycastDirections[i].dot(intersects[0].face.normal)); - // inside = true; - // break; - // } - // else { - // debugPoly && console.log(i, "Point is outside the object", _raycastDirections[i].dot(intersects[0].face.normal)); - // } - // } - // } - _raycaster1.set(point, _rayDirection); - let intersects = _raycaster1.intersectObject(targetOctree.mesh); - // console.log(i, "Intersects?", intersects); - if (debugPoly) { - console.log("RAY CHECK intersects.length", intersects.length, point, _rayDirection); - } - if (intersects.length) { - - if (_rayDirection.dot(intersects[0].face.normal) > 0) { - debugPoly && console.log("Point is inside the object", _rayDirection.dot(intersects[0].face.normal)); - inside = true; - } - else { - debugPoly && console.log("Point is outside the object", _rayDirection.dot(intersects[0].face.normal)); - } - - } - if (!inside && currentPolygon.coplanar) { - // let coplanarFound = false; - // console.log("POLYGON IS COPLANAR"); - for (let j = 0; j < _wP_EPS_ARR_COUNT; j++) { - // console.warn("DOES IT GET HERE?"); - _raycaster1.ray.origin.copy(point).add(_wP_EPS_ARR[j]); - // let intersects = targetOctree.rayIntersect(_ray, targetOctree.mesh.matrixWorld); - let intersects = _raycaster1.intersectObject(targetOctree.mesh); - // console.log(i, "Intersects?", intersects); - if (debugPoly) { - console.log("RAY CHECK intersects.length", intersects.length, point, _rayDirection); - } - if (intersects.length) { - - if (_rayDirection.dot(intersects[0].face.normal) > 0) { - debugPoly && console.log("Point is inside the object", _rayDirection.dot(intersects[0].face.normal)); - inside = true; - break; - } - else { - debugPoly && console.log("Point is outside the object", _rayDirection.dot(intersects[0].face.normal)); - } - - } - } - // if (coplanarFound) { - // console.log("Found as coplanar", _ray.clone()); - // } - } - } - else { - // let ray = new Ray(point, _rayDirection); - _ray.origin.copy(point); - _rayDirection.copy(currentPolygon.plane.normal); - // _ray.direction.copy(_rayDirection); - _ray.direction.copy(currentPolygon.plane.normal); - // let intersects = targetOctree.rayIntersect(_ray, targetOctree.mesh.matrixWorld); - let intersects = targetOctree.rayIntersect(_ray, targetOctree.originalMatrixWorld); - if (debugPoly) { - console.log("RAY CHECK intersects.length", intersects.length, point, _rayDirection); - } - if (intersects.length) { - if (_rayDirection.dot(intersects[0].polygon.plane.normal) > 0) { - debugPoly && console.log("Point is inside the object", _rayDirection.dot(intersects[0].polygon.plane.normal)); - inside = true; - // break; - } - else { - debugPoly && console.log("Point is outside the object", _rayDirection.dot(intersects[0].polygon.plane.normal)); - } - - } - if (!inside && currentPolygon.coplanar) { - // let coplanarFound = false; - // console.log("POLYGON IS COPLANAR"); - for (let j = 0; j < _wP_EPS_ARR_COUNT; j++) { - // console.warn("DOES IT GET HERE?"); - _ray.origin.copy(point).add(_wP_EPS_ARR[j]); - _rayDirection.copy(currentPolygon.plane.normal); - _ray.direction.copy(currentPolygon.plane.normal); - // let intersects = targetOctree.rayIntersect(_ray, targetOctree.mesh.matrixWorld); - let intersects = targetOctree.rayIntersect(_ray, targetOctree.originalMatrixWorld); - if (debugPoly) { - console.log("RAY CHECK intersects.length", intersects.length, point, _rayDirection); - } - if (intersects.length) { - if (_rayDirection.dot(intersects[0].polygon.plane.normal) > 0) { - debugPoly && console.log("Point is inside the object", _rayDirection.dot(intersects[0].polygon.plane.normal)); - inside = true; - // coplanarFound = true; - break; - } - else { - debugPoly && console.log("Point is outside the object", _rayDirection.dot(intersects[0].polygon.plane.normal)); - } - - } - } - // if (coplanarFound) { - // console.log("Found as coplanar", _ray.clone()); - // } - } - /* - for (let i = 0; i < _raycastDirectionsCount; i++) { - _ray.direction.copy(_raycastDirections[i]); - let intersects = targetOctree.rayIntersect(_ray, targetOctree.mesh.matrixWorld); - // let intersects = targetOctree.rayIntersect(_ray, targetOctree.originalMatrixWorld); - if (debugPoly) { - console.log("RAY CHECK intersects.length", intersects.length, point, _raycastDirections[i]); - } - if (intersects.length) { - if (_raycastDirections[i].dot(intersects[0].polygon.plane.normal) > 0) { - debugPoly && console.log(i, "Point is inside the object", _raycastDirections[i].dot(intersects[0].polygon.plane.normal)); - inside = true; - break; - } - else { - debugPoly && console.log(i, "Point is outside the object", _raycastDirections[i].dot(intersects[0].polygon.plane.normal)); - } - - } - } - */ - - /* - // let ray = new Ray(point, _rayDirection); - let intersects = targetOctree.rayIntersect(ray); - // console.log("octree ray test", intersects); - if (debugPoly) { - console.log("RAY CHECK intersects.length", intersects.length, point, _rayDirection); - } - if (intersects.length) { - for (let i = 0; i < intersects.length; i++) { - if (_rayDirection.dot(intersects[i].polygon.plane.normal) > 0) { - debugPoly && console.log(i, "Point is inside the object", _rayDirection.dot(intersects[i].polygon.plane.normal)); - inside = true; - break; - } - else { - debugPoly && console.log(i, "Point is outside the object", _rayDirection.dot(intersects[i].polygon.plane.normal)); - } - } - } - */ - } - } - } - - if (debugPoly) { - console.log("CHECK INSIDE", inside); - } - if (inside === true) { - currentPolygon.setState("inside"); - } - else { - currentPolygon.setState("outside"); - } - - currentPolygon = polygonStack.pop(); - } - - } - for (let i = 0; i < this.subTrees.length; i++) { - this.subTrees[i].handleIntersectingPolygons(targetOctree, targetOctreeBuffer); - } - } - - handleIntersectingPolygons_reduced(targetOctree, targetOctreeBuffer) { // used in async functions - // async handleIntersectingPolygons_async(targetOctree, targetOctreeBuffer) { - // return new Promise(async (resolve, reject) => { - // try { - if (this.polygons.length > 0) { - // testvar++; - // this.polygons.forEach(polygon => { - // polygon.reset(); - // }); - - // TESTING NEW METHOD - let polygonStack = this.polygons.filter(polygon => (polygon.valid == true) && (polygon.intersects == true) && (polygon.state == "undecided")); - let currentPolygon = polygonStack.pop(); - while (currentPolygon) { - if (currentPolygon.state !== "undecided") { - continue; - } - if (!currentPolygon.valid) { - continue; - } - - let debugPoly = false; - // let testTriangle = new THREE.Triangle(new THREE.Vector3(0.29171404242515564, -4.110300540924072, 2.832019329071045), new THREE.Vector3(-0.29171404242515564, -4.110300540924072, 2.832019329071045), new THREE.Vector3(0, -4.3809967041015625, 2.4097442626953125)); - // if ((OctreeCSG.returnType == -1) && (currentPolygon.triangle.equals(testTriangle))) { - // debugPoly = true; - // console.warn("STARTING DEBUG"); - // } - OctreeCSG.debugPoly = debugPoly; - let targetPolygons = targetOctree.getPolygonsIntersectingPolygon(currentPolygon, debugPoly); - - if (targetPolygons.length > 0) { - if (debugPoly) { - console.log("BLA POLYGON TARGET COUNT", targetPolygons.length); - } - // let needsBreak = false; - for (let j = 0; j < targetPolygons.length; j++) { - let target = targetPolygons[j]; - if (debugPoly) { - console.log("BLA POLYGON", currentPolygon, target); - } - // console.log("needsBreak", needsBreak); - let splitResults = splitPolygonByPlane(currentPolygon, target.plane); - debugPoly && console.log("splitResults", splitResults) - if (splitResults.length > 1) { - // let newPolygons = []; - for (let i = 0; i < splitResults.length; i++) { - let polygon = splitResults[i].polygon; - polygon.intersects = currentPolygon.intersects; - polygon.splitState1 = splitResults[i].type; - polygonStack.push(polygon); - } - this.replacePolygon(currentPolygon, splitResults.map(result => result.polygon)); - break; - } - else { - if (currentPolygon.id !== splitResults[0].polygon.id) { - splitResults[0].polygon.intersects = currentPolygon.intersects; - splitResults[0].polygon.splitState2 = splitResults[0].type; - polygonStack.push(splitResults[0].polygon); - this.replacePolygon(currentPolygon, splitResults[0].polygon); - break; - } - else { - if ((splitResults[0].type == "coplanar-front") || (splitResults[0].type == "coplanar-back")) { - currentPolygon.setState(splitResults[0].type); - currentPolygon.coplanar = true; - } - } - } - } - } - else { - debugPoly && console.log("[handleIntersectingPolygons] Not intersecting with any target polygons", currentPolygon); - } - - currentPolygon = polygonStack.pop(); - } - - /* - polygonStack = this.polygons.filter(polygon => (polygon.valid == true) && (polygon.intersects == true)); - let runningWebWorkers = []; - currentPolygon = polygonStack.pop(); - while (currentPolygon) { - // console.warn("Checking loop polygon id", currentPolygon.id); - if (!currentPolygon.valid) { - continue; - } - - let debugPoly = false; - - // let testTriangle = new THREE.Triangle(new THREE.Vector3(0.29171404242515564, -4.110300540924072, 2.832019329071045), new THREE.Vector3(-0.29171404242515564, -4.110300540924072, 2.832019329071045), new THREE.Vector3(0, -4.3809967041015625, 2.4097442626953125)); - // if ((OctreeCSG.returnType == -1) && (currentPolygon.triangle.equals(testTriangle))) { - // debugPoly = true; - // console.warn("STARTING DEBUG"); - // } - OctreeCSG.debugPoly = debugPoly; - let inside = false; - if (targetOctree.box.containsPoint(currentPolygon.triangle.midPoint)) { - // if (OctreeCSG.useWindingNumber === true) { - // let responses = []; - // // let result1 = OctreeCSG.testWorker(1); - // // let result2 = OctreeCSG.testWorker(2); - let worker = getAvailableWorker(); - while (!worker) { - // console.log("Waiting for worker"); - await sleep(1); - worker = getAvailableWorker(); - } - - worker.checkWindingNumber({ - type: 'windingNumber', - point: currentPolygon.triangle.midPoint, - coplanar: currentPolygon.coplanar, - polygonID: currentPolygon.id, - triangles: targetOctreeBuffer - }, currentPolygon).then(worker => { - // console.log("Worker finished", worker.id); - let workerIndex = runningWebWorkers.indexOf(worker); - if (workerIndex > -1) { - runningWebWorkers.splice(workerIndex, 1); - } - }); - runningWebWorkers.push(worker); - - } - else { - currentPolygon.setState("outside"); - } - - // if (debugPoly) { - // console.log("CHECK INSIDE", inside); - // } - // if (inside === true) { - // currentPolygon.setState("inside"); - // } - // else { - // currentPolygon.setState("outside"); - // } - - currentPolygon = polygonStack.pop(); - } - // console.log("START WAITING", runningWebWorkers.length); - while (runningWebWorkers.length) { - // console.log("Waiting to finish"); - await sleep(1); - } - // console.log("FINISHED WAITING", runningWebWorkers.length); - */ - - } - for (let i = 0; i < this.subTrees.length; i++) { - // await this.subTrees[i].handleIntersectingPolygons_async(targetOctree, targetOctreeBuffer); - this.subTrees[i].handleIntersectingPolygons_reduced(targetOctree, targetOctreeBuffer); - } - // resolve(); - // } - // catch (e) { - // reject(e); - // } - // }); - } - - delete() { - if (this.polygons.length > 0) { - this.polygons.forEach(p => p.delete()); - this.polygons.length = 0; - } - if (this.subTrees.length) { - for (let i = 0; i < this.subTrees.length; i++) { - this.subTrees[i].delete(false); - } - this.subTrees.length = 0; - } - this.mesh = undefined; - this.originalMatrixWorld = undefined; - this.box = undefined; - this.parent = undefined; - } - getPolygonCallback(cbFunc) { - if (this.polygons.length > 0) { - for (let i = 0; i < this.polygons.length; i++) { - if (this.polygons[i].valid) { - cbFunc(this.polygons[i]); - } - } - } - for (let i = 0; i < this.subTrees.length; i++) { - this.subTrees[i].getPolygonCallback(cbFunc); - } - } -} - - -function raycastIntersectAscSort(a, b) { - return a.distance - b.distance; -} - -function pointRounding(point, num = 15) { - point.x = +point.x.toFixed(num); - point.y = +point.y.toFixed(num); - point.z = +point.z.toFixed(num); - return point; -} - -function splitPolygonByPlane(polygon, plane, result = []) { - let returnPolygon = { - polygon: polygon, - type: "undecided" - }; - let polygonType = 0; - let types = []; - for (let i = 0; i < polygon.vertices.length; i++) { - let t = plane.normal.dot(polygon.vertices[i].pos) - plane.w; - let type = (t < -EPSILON) ? BACK : (t > EPSILON) ? FRONT : COPLANAR; - polygonType |= type; - types.push(type); - } - switch (polygonType) { - case COPLANAR: - returnPolygon.type = plane.normal.dot(polygon.plane.normal) > 0 ? "coplanar-front" : "coplanar-back"; - result.push(returnPolygon); - break; - case FRONT: - returnPolygon.type = "front"; - result.push(returnPolygon); - break; - case BACK: - returnPolygon.type = "back"; - result.push(returnPolygon); - break; - case SPANNING: - let f = []; - let b = []; - for (let i = 0; i < polygon.vertices.length; i++) { - let j = (i + 1) % polygon.vertices.length; - let ti = types[i]; - let tj = types[j]; - let vi = polygon.vertices[i]; - let vj = polygon.vertices[j]; - if (ti != BACK) { - f.push(vi); - } - if (ti != FRONT) { - b.push(ti != BACK ? vi.clone() : vi); - } - if ((ti | tj) == SPANNING) { - let t = (plane.w - plane.normal.dot(vi.pos)) / plane.normal.dot(tv0.copy(vj.pos).sub(vi.pos)); - let v = vi.interpolate(vj, t); - f.push(v); - b.push(v.clone()); - } - } - if (f.length >= 3) { - if (f.length > 3) { - let newPolys = splitPolygonArr(f); - for (let npI = 0; npI < newPolys.length; npI++) { - result.push({ - polygon: new Polygon(newPolys[npI], polygon.shared), - type: "front" - }); - } - } - else { - result.push({ - polygon: new Polygon(f, polygon.shared), - type: "front" - }); - } - } - if (b.length >= 3) { - if (b.length > 3) { - let newPolys = splitPolygonArr(b); - for (let npI = 0; npI < newPolys.length; npI++) { - result.push({ - polygon: new Polygon(newPolys[npI], polygon.shared), - type: "back" - }); - } - } - else { - result.push({ - polygon: new Polygon(b, polygon.shared), - type: "back" - }); - } - } - break; - } - if (result.length == 0) { - result.push(returnPolygon); - } - return result; -} - -function splitPolygonArr(arr) { - let resultArr = []; - - - if (arr.length > 4) { - console.warn("[splitPolygonArr] arr.length > 4", arr.length); - for (let j = 3; j <= arr.length; j++) { - let result = []; - result.push(arr[0].clone()); - result.push(arr[j - 2].clone()); - result.push(arr[j - 1].clone()); - resultArr.push(result); - } - } - else { - if (arr[0].pos.distanceTo(arr[2].pos) <= arr[1].pos.distanceTo(arr[3].pos)) { - resultArr.push([arr[0].clone(), arr[1].clone(), arr[2].clone()], - [arr[0].clone(), arr[2].clone(), arr[3].clone()]); - } - else { - resultArr.push([arr[0].clone(), arr[1].clone(), arr[3].clone()], - [arr[1].clone(), arr[2].clone(), arr[3].clone()]); - } - return resultArr; - - } - - return resultArr; -} - -/* -Union: -1. Delete all polygons in A that are: - a. inside and coplanar-back - b. inside -2. Delete all polygons in B that are: - a. inside and coplanar-back - b. inside and coplanar-front - c. inside -*/ -OctreeCSG.union = function (octreeA, octreeB, buildTargetOctree = true) { - let octree = new OctreeCSG(); - - if (octreeA.box.intersectsBox(octreeB.box)) { - let currentMeshSideA; - let currentMeshSideB; - if (octreeA.mesh) { - currentMeshSideA = octreeA.mesh.material.side; - octreeA.mesh.material.side = OctreeCSG.testSide; - } - if (octreeB.mesh) { - currentMeshSideB = octreeB.mesh.material.side; - octreeB.mesh.material.side = OctreeCSG.testSide; - } - - octreeA.resetPolygons(); - octreeB.resetPolygons(); - - octreeA.markIntesectingPolygons(octreeB); - octreeB.markIntesectingPolygons(octreeA); - - handleIntersectingOctrees(octreeA, octreeB); - octreeA.deletePolygonsByStateRules([ - { - array: true, - rule: ["inside", "coplanar-back"] - }, - { - array: false, - rule: "inside" - } - ]); - - octreeB.deletePolygonsByStateRules([ - { - array: true, - rule: ["inside", "coplanar-back"] - }, - { - array: true, - rule: ["inside", "coplanar-front"] - }, - { - array: false, - rule: "inside" - } - ]); - - if (OctreeCSG.returnType == 0) { - octreeA.getPolygonCallback(octree.addPolygon.bind(octree)); - octreeB.getPolygonCallback(octree.addPolygon.bind(octree)); - } - else if (OctreeCSG.returnType == -1) { - console.log("OctreeA"); - let polys_test = octreeA.getPolygons(); - let limit = Math.min(polys_test.length, 50000); - console.log(`[octreeA] polys_test`, polys_test.length, limit); - let count = 0; - for (let i = 0; i < limit; i++) { - if (polys_test[i].intersects) { - let t = polys_test[i].triangle; - // if ((t.a.x <= 1) && (t.b.x <= 1) && (t.c.x <= 1)) { - // if ((t.a.x >= -4) && (t.b.x >= -4) && (t.c.x >= -4)) { - // if ((t.a.y == -1) && (t.b.y == -1) && (t.c.y == -1)) { - // if ((t.a.z <= 4) && (t.b.z <= 4) && (t.c.z <= 4)) { - // if ((t.a.z > -5) && (t.b.z > -5) && (t.c.z > -5)) { - // console.log("AAAA", i, t, polys_test[i]); - octree.addPolygon(polys_test[i]); - count++; - // } - // } - // } - // } - // } - } - // else { - // octree.addPolygon(polys_test[i]); - // } - } - console.log("AAAA ADDED COUNT", count); - } - else { - console.log("OctreeB"); - let polys_test = octreeB.getPolygons(); - let limit = Math.min(polys_test.length, 50000); - console.log(`[octreeB] polys_test`, polys_test.length, limit); - let count = 0; - for (let i = 0; i < limit; i++) { - if (polys_test[i].intersects) { - // console.log(i, polys_test[i]); - let t = polys_test[i].triangle; - // if ((t.a.x <= 1) && (t.b.x <= 1) && (t.c.x <= 1)) { - // if ((t.a.x >= -2) && (t.b.x >= -2) && (t.c.x >= -2)) { - // if ((t.a.y >= 3) && (t.b.y >= 3) && (t.c.y >= 3)) { - // if ((t.a.z <= 1) && (t.b.z <= 1) && (t.c.z <= 1)) { - // if ((t.a.z >= -2) && (t.b.z >= -2) && (t.c.z >= -2)) { - // if (polys_test[i].checkAllStates("back")) { - - - // console.log("BBBB", i, t, polys_test[i]); - octree.addPolygon(polys_test[i]); - count++; - // } - // } - // } - // } - } - // else { - // octree.addPolygon(polys_test[i]); - // } - } - console.log("BBBB ADDED COUNT", count); - } - - buildTargetOctree && octree.buildTree(); - if (octreeA.mesh) { - if (octreeA.mesh.material.side !== currentMeshSideA) { - octreeA.mesh.material.side = currentMeshSideA; - } - } - if (octreeB.mesh) { - if (octreeB.mesh.material.side !== currentMeshSideB) { - octreeB.mesh.material.side = currentMeshSideB; - } - } - - } - else { - octreeA.getPolygonCallback(octree.addPolygon.bind(octree)); - octreeB.getPolygonCallback(octree.addPolygon.bind(octree)); - buildTargetOctree && octree.buildTree(); - } - - return octree; -} - -/* -Subtract: -1. Delete all polygons in A that are: - a. inside and coplanar-back - b. inside and coplanar-front - c. inside -2. Delete all polygons in B that are: - a. outside and coplanar-back - b. outside and coplanar-front - c. inside and coplanar-front - d. outside -*/ -OctreeCSG.subtract = function (octreeA, octreeB, buildTargetOctree = true) { - let octree = new OctreeCSG(); - if (octreeA.box.intersectsBox(octreeB.box)) { - let currentMeshSideA; - let currentMeshSideB; - if (octreeA.mesh) { - currentMeshSideA = octreeA.mesh.material.side; - octreeA.mesh.material.side = OctreeCSG.testSide; - } - if (octreeB.mesh) { - currentMeshSideB = octreeB.mesh.material.side; - octreeB.mesh.material.side = OctreeCSG.testSide; - } - - octreeA.resetPolygons(); - octreeB.resetPolygons(); - octreeA.markIntesectingPolygons(octreeB); - octreeB.markIntesectingPolygons(octreeA); - - - handleIntersectingOctrees(octreeA, octreeB); - - octreeA.deletePolygonsByStateRules([ - { - array: true, - rule: ["inside", "coplanar-back"] - }, - { - array: true, - rule: ["inside", "coplanar-front"] - }, - { - array: false, - rule: "inside" - } - ]); - octreeB.deletePolygonsByStateRules([ - { - array: true, - rule: ["outside", "coplanar-back"] - }, - { - array: true, - rule: ["outside", "coplanar-front"] - }, - { - array: true, - rule: ["inside", "coplanar-front"] - }, - { - array: false, - rule: "outside" - } - ]); - - - octreeB.deletePolygonsByIntersection(false); - - - octreeB.invert(); - - - if (OctreeCSG.returnType == 0) { - octreeA.getPolygonCallback(octree.addPolygon.bind(octree)); - octreeB.getPolygonCallback(octree.addPolygon.bind(octree)); - } - else if (OctreeCSG.returnType == -1) { - console.log("OctreeA"); - let polys_test = octreeA.getPolygons(); - let limit = Math.min(polys_test.length, 50000); - console.log(`[octreeA] polys_test`, polys_test.length, limit); - for (let i = 0; i < limit; i++) { - if (polys_test[i].intersects) { - let t = polys_test[i].triangle; - if (((t.a.y < -3) && (t.b.y < -3) && (t.c.y < -3))) { - // if (((t.a.x >= 0.8) && (t.b.x >= 0.8) && (t.c.x >= 0.8))) { - console.log("AAAA", i, t, polys_test[i]); - octree.addPolygon(polys_test[i]); - } - } - // else { - // octree.addPolygon(polys_test[i]); - // } - } - } - else { - console.log("OctreeB"); - let polys_test = octreeB.getPolygons(); - let limit = Math.min(polys_test.length, 50000); - console.log(`[octreeB] polys_test`, polys_test.length, limit); - for (let i = 0; i < limit; i++) { - if (polys_test[i].intersects) { - let t = polys_test[i].triangle; - // if ((t.a.x <= 1) && (t.b.x <= 1) && (t.c.x <= 1)) { - // if (((t.a.y === -5) && (t.b.y === -5) && (t.c.y === -5))) { - // console.log("BBBB", i, t, polys_test[i]); - octree.addPolygon(polys_test[i]); - // } - } - // else { - // octree.addPolygon(polys_test[i]); - // } - } - } - - if (octreeA.mesh) { - if (octreeA.mesh.material.side !== currentMeshSideA) { - octreeA.mesh.material.side = currentMeshSideA; - } - } - if (octreeB.mesh) { - if (octreeB.mesh.material.side !== currentMeshSideB) { - octreeB.mesh.material.side = currentMeshSideB; - } - } - } - else { - octreeA.getPolygonCallback(octree.addPolygon.bind(octree)); - } - - buildTargetOctree && octree.buildTree(); - // octree.invert(); - return octree; -} - -/* -Intersect: -1. Delete all polygons in A that are: - a. inside and coplanar-back - b. outside and coplanar-front - c. outside and coplanar-back - d. outside -2. Delete all polygons in B that are: - a. inside and coplanar-front - b. inside and coplanar-back - c. outside and coplanar-front - d. outside and coplanar-back - e. outside -*/ -OctreeCSG.intersect = function (octreeA, octreeB, buildTargetOctree = true) { - let octree = new OctreeCSG(); - if (octreeA.box.intersectsBox(octreeB.box)) { - let currentMeshSideA; - let currentMeshSideB; - if (octreeA.mesh) { - currentMeshSideA = octreeA.mesh.material.side; - octreeA.mesh.material.side = OctreeCSG.testSide; - } - if (octreeB.mesh) { - currentMeshSideB = octreeB.mesh.material.side; - octreeB.mesh.material.side = OctreeCSG.testSide; - } - - octreeA.resetPolygons(); - octreeB.resetPolygons(); - - octreeA.markIntesectingPolygons(octreeB); - octreeB.markIntesectingPolygons(octreeA); - - handleIntersectingOctrees(octreeA, octreeB); - - octreeA.deletePolygonsByStateRules([ - { - array: true, - rule: ["inside", "coplanar-back"] - }, - { - array: true, - rule: ["outside", "coplanar-front"] - }, - { - array: true, - rule: ["outside", "coplanar-back"] - }, - { - array: false, - rule: "outside" - } - ]); - - octreeB.deletePolygonsByStateRules([ - { - array: true, - rule: ["inside", "coplanar-front"] - }, - { - array: true, - rule: ["inside", "coplanar-back"] - }, - { - array: true, - rule: ["outside", "coplanar-front"] - }, - { - array: true, - rule: ["outside", "coplanar-back"] - }, - { - array: false, - rule: "outside" - } - ]); - octreeA.deletePolygonsByIntersection(false); - octreeB.deletePolygonsByIntersection(false); - - if (OctreeCSG.returnType == 0) { - octreeA.getPolygonCallback(octree.addPolygon.bind(octree)); - octreeB.getPolygonCallback(octree.addPolygon.bind(octree)); - } - else if (OctreeCSG.returnType == -1) { - console.log("OctreeA"); - let polys_test = octreeA.getPolygons(); - let limit = Math.min(polys_test.length, 50000); - console.log(`[octreeA] polys_test`, polys_test.length, limit); - for (let i = 0; i < limit; i++) { - if (polys_test[i].intersects) { - let t = polys_test[i].triangle; - // if (((t.a.y < -3) && (t.b.y < -3) && (t.c.y < -3))) { - // if (((t.a.x >= 0.8) && (t.b.x >= 0.8) && (t.c.x >= 0.8))) { - // console.log("AAAA", i, t, polys_test[i]); - octree.addPolygon(polys_test[i]); - // } - } - // else { - // octree.addPolygon(polys_test[i]); - // } - } - } - else { - console.log("OctreeB"); - let polys_test = octreeB.getPolygons(); - let limit = Math.min(polys_test.length, 50000); - console.log(`[octreeB] polys_test`, polys_test.length, limit); - for (let i = 0; i < limit; i++) { - if (polys_test[i].intersects) { - let t = polys_test[i].triangle; - // if ((t.a.x <= 1) && (t.b.x <= 1) && (t.c.x <= 1)) { - // if (((t.a.y === -5) && (t.b.y === -5) && (t.c.y === -5))) { - // console.log("BBBB", i, t, polys_test[i]); - octree.addPolygon(polys_test[i]); - // } - } - // else { - // octree.addPolygon(polys_test[i]); - // } - } - } - - // let polys_test = octreeB.getPolygons(); - // let limit = Math.min(polys_test.length, 50); - // for (let i = 0; i < limit; i++) { - // console.log(i, polys_test[i]); - // octree.addPolygon(polys_test[i]); - // } - - if (octreeA.mesh) { - if (octreeA.mesh.material.side !== currentMeshSideA) { - octreeA.mesh.material.side = currentMeshSideA; - } - } - if (octreeB.mesh) { - if (octreeB.mesh.material.side !== currentMeshSideB) { - octreeB.mesh.material.side = currentMeshSideB; - } - } - } - // else { - // octreeA.getPolygonCallback(octree.addPolygon.bind(octree)); - // } - buildTargetOctree && octree.buildTree(); - // octree.invert(); - return octree; -} - -OctreeCSG.operation = function (obj, returnOctrees = false, buildTargetOctree = true, options = { objCounter: 0 }, firstRun = true) { - // console.log("OctreeCSG.operation", obj); - let octreeA, octreeB, resultOctree, material; - if (obj.material) { - material = obj.material; - } - if (obj.objA) { - octreeA = handleObjectForOp(obj.objA, returnOctrees, buildTargetOctree, options); - if (returnOctrees == true) { - obj.objA = octreeA.original; - octreeA = octreeA.result; - } - } - if (obj.objB) { - octreeB = handleObjectForOp(obj.objB, returnOctrees, buildTargetOctree, options); - if (returnOctrees == true) { - obj.objB = octreeB.original; - octreeB = octreeB.result; - } - } - switch (obj.op) { - case 'union': - resultOctree = OctreeCSG.union(octreeA, octreeB, buildTargetOctree); - break; - case 'subtract': - resultOctree = OctreeCSG.subtract(octreeA, octreeB, buildTargetOctree); - break; - case 'intersect': - resultOctree = OctreeCSG.intersect(octreeA, octreeB, buildTargetOctree); - break; - } - if (firstRun && material) { - let mesh = OctreeCSG.toMesh(resultOctree, material); - return returnOctrees ? { result: mesh, operationTree: obj } : mesh; - } - if (firstRun && returnOctrees) { - return { result: resultOctree, operationTree: obj }; - } - return resultOctree; -} - -// Work in progress -function handleObjectForOp(obj, returnOctrees, buildTargetOctree, options) { - let returnObj; - if (obj.isMesh) { - returnObj = OctreeCSG.fromMesh(obj, options.objCounter++); - if (returnOctrees) { - returnObj = { result: returnObj, original: returnObj.clone() }; - } - } - else if (obj.isOctree) { - returnObj = obj; - if (returnOctrees) { - returnObj = { result: obj, original: obj.clone() }; - } - } - else if (obj.op) { - returnObj = OctreeCSG.operation(obj, returnOctrees, buildTargetOctree, options, false); - if (returnOctrees) { - returnObj = { result: returnObj, original: obj }; - } - } - - return returnObj; -} - -/* -// Work in progress -OctreeCSG.unionArray = function (objArr, buildTargetOctree = true) { - // console.log("OctreeCSG.getRayPolys", OctreeCSG.getRayPolys); - // console.log("OctreeCSG.useOctreeRay", OctreeCSG.useOctreeRay); - // let polys = []; - let octrees = []; - for (let i = 0; i < objArr.length; i++) { - let tempOctree = OctreeCSG.fromMesh(objArr[i]); - tempOctree.octreeIndex = i; - octrees.push(tempOctree); - } - let octree = new OctreeCSG(); - - - - - // let aPolygons = octreeA.getPolygons(); - // let bPolygons = octreeB.getPolygons(); - // let filterResults; - if (octreeA.box.intersectsBox(octreeB.box)) { - let trianglesSet = new Set(); - let currentMeshSideA; - let currentMeshSideB; - if (octreeA.mesh) { - currentMeshSideA = octreeA.mesh.material.side; - octreeA.mesh.material.side = OctreeCSG.testSide; - } - if (octreeB.mesh) { - currentMeshSideB = octreeB.mesh.material.side; - octreeB.mesh.material.side = OctreeCSG.testSide; - } - - octreeA.resetPolygons(); - octreeB.resetPolygons(); - - octreeA.markIntesectingPolygons(octreeB); - octreeB.markIntesectingPolygons(octreeA); - - - handleIntersectingOctrees(octreeA, octreeB); - - octreeA.deletePolygonsByStateRules([ - { - array: true, - rule: ["inside", "coplanar-back"] - }, - { - array: false, - rule: "inside" - } - ]); - - // } - - octreeB.deletePolygonsByStateRules([ - { - array: true, - rule: ["inside", "coplanar-back"] - }, - { - array: true, - rule: ["inside", "coplanar-front"] - }, - { - array: false, - rule: "inside" - } - ]); - - octreeA.getPolygonCallback(octree.addPolygon.bind(octree)); - octreeB.getPolygonCallback(octree.addPolygon.bind(octree)); - - - buildTargetOctree && octree.buildTree(); - if (octreeA.mesh) { - if (octreeA.mesh.material.side !== currentMeshSideA) { - octreeA.mesh.material.side = currentMeshSideA; - } - } - if (octreeB.mesh) { - if (octreeB.mesh.material.side !== currentMeshSideB) { - octreeB.mesh.material.side = currentMeshSideB; - } - } - - } - else { - octreeA.getPolygonCallback(octree.addPolygon.bind(octree)); - octreeB.getPolygonCallback(octree.addPolygon.bind(octree)); - buildTargetOctree && octree.buildTree(); - } - - return octree; -} -*/ - -OctreeCSG.isUniqueTriangle = function (triangle, set, map) { - const hash1 = `{${triangle.a.x},${triangle.a.y},${triangle.a.z}}-{${triangle.b.x},${triangle.b.y},${triangle.b.z}}-{${triangle.c.x},${triangle.c.y},${triangle.c.z}}`; - - if (set.has(hash1) === true) { - return false; - } - else { - set.add(hash1); - if (map) { - map.set(triangle, triangle); - } - return true; - } -} - -const nbuf3 = (ct) => { - return { - top: 0, - array: new Float32Array(ct), - write: function (v) { - this.array[this.top++] = v.x; - this.array[this.top++] = v.y; - this.array[this.top++] = v.z; - } - } -} -const nbuf2 = (ct) => { - return { - top: 0, - array: new Float32Array(ct), - write: function (v) { - this.array[this.top++] = v.x; - this.array[this.top++] = v.y; - } - } -} -const _normal1 = new Vector3(); -const tmpm3 = new Matrix3(); -const ttvv0 = new Vector3() - -OctreeCSG.toGeometry = function (octree) { - let polygons = octree.getPolygons(); - let validPolygons = []; - let trianglesSet = new Set(); - let duplicateCount = 0; - - let triangleCount = 0; - polygons.forEach(polygon => { - if (OctreeCSG.isUniqueTriangle(polygon.triangle, trianglesSet)) { - triangleCount += (polygon.vertices.length - 2); - validPolygons.push(polygon); - } - // else { - // duplicateCount++; - // let a = triangleMap.get(polygon.triangle); - // console.log("DUPLICATE!!", polygon.id == a.polygon.id); - // } - }); - trianglesSet.clear(); - trianglesSet = undefined; - - let positions = nbuf3(triangleCount * 3 * 3); - let normals = nbuf3(triangleCount * 3 * 3); - let uvs; - let colors; - let groups = []; - let defaultGroup = []; - - validPolygons.forEach(polygon => { - let vertices = polygon.vertices; - let verticesLen = vertices.length; - if (polygon.shared !== undefined) { - if (!groups[polygon.shared]) { - groups[polygon.shared] = []; - } - } - if (verticesLen > 0) { - if (vertices[0].uv !== undefined) { - !uvs && (uvs = nbuf2(triangleCount * 2 * 3)); - } - if (vertices[0].color !== undefined) { - !colors && (colors = nbuf3(triangleCount * 3 * 3)); - } - } - for (let i = 3; i <= verticesLen; i++) { - (polygon.shared === undefined ? defaultGroup : groups[polygon.shared]).push(positions.top / 3, (positions.top / 3) + 1, (positions.top / 3) + 2); - positions.write(vertices[0].pos); - positions.write(vertices[i - 2].pos); - positions.write(vertices[i - 1].pos); - normals.write(vertices[0].normal); - normals.write(vertices[i - 2].normal); - normals.write(vertices[i - 1].normal); - if (uvs !== undefined) { - uvs.write(vertices[0].uv); - uvs.write(vertices[i - 2].uv); - uvs.write(vertices[i - 1].uv); - } - if (colors !== undefined) { - colors.write(vertices[0].color); - colors.write(vertices[i - 2].color); - colors.write(vertices[i - 1].color); - } - } - }); - - let geometry = new BufferGeometry(); - geometry.setAttribute('position', new BufferAttribute(positions.array, 3)); - geometry.setAttribute('normal', new BufferAttribute(normals.array, 3)); - uvs && geometry.setAttribute('uv', new BufferAttribute(uvs.array, 2)); - colors && geometry.setAttribute('color', new BufferAttribute(colors.array, 3)); - - if (groups.length > 0) { - let index = []; - let groupBase = 0; - for (let i = 0; i < groups.length; i++) { - if (groups[i] === undefined) { - groups[i] = []; - } - geometry.addGroup(groupBase, groups[i].length, i); - groupBase += groups[i].length; - index = index.concat(groups[i]); - } - if (defaultGroup.length) { - geometry.addGroup(groupBase, defaultGroup.length, groups.length); - index = index.concat(defaultGroup); - } - geometry.setIndex(index); - } - // console.log("duplicateCount", duplicateCount); - return geometry; -} - -OctreeCSG.toMesh = function (octree, toMaterial) { - let geometry = OctreeCSG.toGeometry(octree); - // geometry = BufferGeometryUtils.mergeVertices(geometry); - // geometry = geometry.toNonIndexed(); - return new Mesh(geometry, toMaterial); -} - -OctreeCSG.fromMesh = function (obj, objectIndex) { - let octree = new OctreeCSG(); - octree.originalMatrixWorld = obj.matrixWorld.clone(); - obj.updateWorldMatrix(true, true); - // obj.updateMatrixWorld(); - // obj.updateMatrix(); - let geometry = obj.geometry; - tmpm3.getNormalMatrix(obj.matrix); - let posattr = geometry.attributes.position; - let normalattr = geometry.attributes.normal; - let uvattr = geometry.attributes.uv; - let colorattr = geometry.attributes.color; - let groups = geometry.groups; - let index; - if (geometry.index) - index = geometry.index.array; - else { - index = new Array((posattr.array.length / posattr.itemSize) | 0); - for (let i = 0; i < index.length; i++) - index[i] = i; - } - // let triCount = (index.length / 3) | 0; - let polys = []; - // polys = new Array(triCount) - for (let i = 0, pli = 0, l = index.length; i < l; i += 3, pli++) { - let vertices = []; - for (let j = 0; j < 3; j++) { - let vi = index[i + j]; - let vp = vi * 3; - let vt = vi * 2; - let pos = new Vector3(posattr.array[vp], posattr.array[vp + 1], posattr.array[vp + 2]); - let normal = new Vector3(normalattr.array[vp], normalattr.array[vp + 1], normalattr.array[vp + 2]); - pos.applyMatrix4(obj.matrix); - normal.applyMatrix3(tmpm3); - - vertices.push(new Vertex(pos, normal, uvattr && { // uv - x: uvattr.array[vt], - y: uvattr.array[vt + 1] - }, colorattr && { x: colorattr.array[vt], y: colorattr.array[vt + 1], z: colorattr.array[vt + 2] })); - } - if ((objectIndex === undefined) && groups && groups.length > 0) { - let polygon; - for (let group of groups) { - if ((index[i] >= group.start) && (index[i] < (group.start + group.count))) { - polygon = new Polygon(vertices, group.materialIndex); - } - } - if (polygon) { - polys.push(polygon); - } - - } - else { - polys.push(new Polygon(vertices, objectIndex)); - } - } - - for (let i = 0; i < polys.length; i++) { - if (isValidTriangle(polys[i].triangle)) { - if (isNaN(polys[i].plane.normal.x)) { - console.warn("polygon", i, "is NaN!!!!"); - } - - octree.addPolygon(polys[i]); - } - else { - // console.log("polygon", i, "has two points at same place", polys[i]); - polys[i].delete(); - } - } - // octree.addTriangle(newTriangle(v1, v2, v3)); - - - octree.buildTree(); - // return CSG.fromPolygons(polys.filter(p => !isNaN(p.plane.normal.x))); - octree.mesh = obj; - return octree; - -}; - -function isValidTriangle(triangle) { - if (triangle.a.equals(triangle.b)) return false; - if (triangle.a.equals(triangle.c)) return false; - if (triangle.b.equals(triangle.c)) return false; - return true; -} - -// OctreeCSG.meshToBuffers = function (obj, objectIndex) { -// obj.updateWorldMatrix(true, true); -// // let octree = new OctreeCSG(); -// let geometry = obj.geometry; -// tmpm3.getNormalMatrix(obj.matrix); -// let posattr = geometry.attributes.position; -// let normalattr = geometry.attributes.normal; -// let uvattr = geometry.attributes.uv; -// let colorattr = geometry.attributes.color; -// let groups = geometry.groups; -// let index; -// if (geometry.index) -// index = geometry.index.array; -// else { -// index = new Array((posattr.array.length / posattr.itemSize) | 0); -// for (let i = 0; i < index.length; i++) -// index[i] = i; -// } -// // let triCount = (index.length / 3) | 0; -// let polys = []; -// // polys = new Array(triCount) -// for (let i = 0, pli = 0, l = index.length; i < l; i += 3, pli++) { -// let vertices = []; -// for (let j = 0; j < 3; j++) { -// let vi = index[i + j] -// let vp = vi * 3; -// let vt = vi * 2; -// let pos = new Vector3(posattr.array[vp], posattr.array[vp + 1], posattr.array[vp + 2]); -// let normal = new Vector3(normalattr.array[vp], normalattr.array[vp + 1], normalattr.array[vp + 2]); -// pos.applyMatrix4(obj.matrix); -// normal.applyMatrix3(tmpm3); -// // v.applyMatrix4(obj.matrixWorld); -// // vertices.push(v); -// // v2.applyMatrix4(obj.matrixWorld); -// // v3.applyMatrix4(obj.matrixWorld); -// vertices.push(new Vertex(pos, normal, uvattr && { // uv -// x: uvattr.array[vt], -// y: uvattr.array[vt + 1] -// }, colorattr && { x: colorattr.array[vt], y: colorattr.array[vt + 1], z: colorattr.array[vt + 2] })); -// } -// if ((objectIndex === undefined) && groups && groups.length > 0) { -// let polygon; -// for (let group of groups) { -// if ((index[i] >= group.start) && (index[i] < (group.start + group.count))) { -// polygon = new Polygon(vertices, group.materialIndex); -// } -// } -// if (polygon) { -// polys.push(polygon); -// } - -// } -// else { -// polys.push(new Polygon(vertices, objectIndex)); -// } -// } -// return polys; -// // for (let i = 0; i < polys.length; i++) { -// // octree.addPolygon(polys[i]); -// // } -// // // octree.addTriangle(newTriangle(v1, v2, v3)); - -// // octree.buildTree(); -// // // return CSG.fromPolygons(polys.filter(p => !isNaN(p.plane.normal.x))); -// // return octree; - -// }; - -OctreeCSG.meshToPolygons = function (obj, objectIndex) { - obj.updateWorldMatrix(true, true); - // let octree = new OctreeCSG(); - let geometry = obj.geometry; - tmpm3.getNormalMatrix(obj.matrix); - let posattr = geometry.attributes.position; - let normalattr = geometry.attributes.normal; - let uvattr = geometry.attributes.uv; - let colorattr = geometry.attributes.color; - let groups = geometry.groups; - let index; - if (geometry.index) - index = geometry.index.array; - else { - index = new Array((posattr.array.length / posattr.itemSize) | 0); - for (let i = 0; i < index.length; i++) - index[i] = i; - } - // let triCount = (index.length / 3) | 0; - let polys = []; - // polys = new Array(triCount) - for (let i = 0, pli = 0, l = index.length; i < l; i += 3, pli++) { - let vertices = []; - for (let j = 0; j < 3; j++) { - let vi = index[i + j] - let vp = vi * 3; - let vt = vi * 2; - let pos = new Vector3(posattr.array[vp], posattr.array[vp + 1], posattr.array[vp + 2]); - let normal = new Vector3(normalattr.array[vp], normalattr.array[vp + 1], normalattr.array[vp + 2]); - pos.applyMatrix4(obj.matrix); - normal.applyMatrix3(tmpm3); - // v.applyMatrix4(obj.matrixWorld); - // vertices.push(v); - // v2.applyMatrix4(obj.matrixWorld); - // v3.applyMatrix4(obj.matrixWorld); - vertices.push(new Vertex(pos, normal, uvattr && { // uv - x: uvattr.array[vt], - y: uvattr.array[vt + 1] - }, colorattr && { x: colorattr.array[vt], y: colorattr.array[vt + 1], z: colorattr.array[vt + 2] })); - } - if ((objectIndex === undefined) && groups && groups.length > 0) { - let polygon; - for (let group of groups) { - if ((index[i] >= group.start) && (index[i] < (group.start + group.count))) { - polygon = new Polygon(vertices, group.materialIndex); - } - } - if (polygon) { - polys.push(polygon); - } - - } - else { - polys.push(new Polygon(vertices, objectIndex)); - } - } - return polys; - // for (let i = 0; i < polys.length; i++) { - // octree.addPolygon(polys[i]); - // } - // // octree.addTriangle(newTriangle(v1, v2, v3)); - - // octree.buildTree(); - // // return CSG.fromPolygons(polys.filter(p => !isNaN(p.plane.normal.x))); - // return octree; - -}; - - - - - - -// OctreeCSG.addPolygonToMap = function (map, polygon, value) { -// let mapValue = map.get(polygon) || []; -// mapValue.push(value); -// map.set(polygon, mapValue); -// } - - - -// class Vertex - -class Vertex { - - constructor(pos, normal, uv, color) { - this.pos = new Vector3().copy(pos); - this.normal = new Vector3().copy(normal); - uv && (this.uv = new Vector2().copy(uv)); - color && (this.color = new Vector3().copy(color)); - } - - clone() { - return new Vertex(this.pos.clone(), this.normal.clone(), this.uv && this.uv.clone(), this.color && this.color.clone()); - } - - // Invert all orientation-specific data (e.g. vertex normal). Called when the - // orientation of a polygon is flipped. - flip() { - this.normal.negate(); - } - delete() { - this.pos = undefined; - this.normal = undefined; - this.uv && (this.uv = undefined); - this.color && (this.color = undefined); - } - // Create a new vertex between this vertex and `other` by linearly - // interpolating all properties using a parameter of `t`. Subclasses should - // override this to interpolate additional properties. - interpolate(other, t) { - return new Vertex(this.pos.clone().lerp(other.pos, t), this.normal.clone().lerp(other.normal, t), this.uv && other.uv && this.uv.clone().lerp(other.uv, t), this.color && other.color && this.color.clone().lerp(other.color, t)); - } -} - -// class Plane - -class Plane { - constructor(normal, w) { - this.normal = normal; - this.w = w; - // this.constant; - } - - clone() { - return new Plane(this.normal.clone(), this.w); - } - - flip() { - this.normal.negate(); - this.w = -this.w; - } - delete() { - this.normal = undefined; - this.w = undefined; - } - - equals(p) { - if (this.normal.equals(p.normal) && this.w === p.w) { - return true; - } - return false; - } - // distanceToPoint(point) { - // return this.normal.dot(point) - this.constant; - // } - -} - -Plane.fromPoints = function (a, b, c) { - let n = tv0.copy(b).sub(a).cross(tv1.copy(c).sub(a)).normalize().clone(); - return new Plane(n, n.dot(a)); -} - - -// class Polygon - -class Polygon { - constructor(vertices, shared) { - this.vertices = vertices.map(v => v.clone()); - this.shared = shared; - this.plane = Plane.fromPoints(this.vertices[0].pos, this.vertices[1].pos, this.vertices[2].pos); - this.triangle = new Triangle(this.vertices[0].pos, this.vertices[1].pos, this.vertices[2].pos); - this.triangle.midPoint = this.triangle.getMidpoint(new Vector3()); - - // this.triangle.polygon = this; - // this.plane.constant = this.plane.normal.dot(this.triangle.midPoint); - // this.box = new Box3(); - // this.box.expandByPoint(this.triangle.a); - // this.box.expandByPoint(this.triangle.b); - // this.box.expandByPoint(this.triangle.c); - // this.box.expandByScalar(EPSILON); - - // this.source = "new"; - this.intersects = false; - this.state = "undecided"; - this.previousState = "undecided"; - this.previousStates = []; - this.valid = true; - this.coplanar = false; - // this.original = true; - Object.defineProperty(this, 'id', { - value: _polygonID++ - }); - } - reset() { - this.intersects = false; - this.state = "undecided"; - this.previousState = "undecided"; - this.previousStates.length = 0; - this.valid = true; - } - setState(state, keepState) { - if (this.state === keepState) { - return; - } - this.previousState = this.state; - this.state !== "undecided" && this.previousStates.push(this.state); - this.state = state; - } - checkAllStates(state) { - if ((this.state !== state) || ((this.previousState !== state) && (this.previousState !== "undecided"))) { - // if ( || ) { - return false; - } - for (let i = 0; i < this.previousStates.length; i++) { - if (this.previousStates[i] !== state) { - return false; - } - } - return true; - } - setInvalid() { - this.valid = false; - } - setValid() { - this.valid = true; - } - clone() { - let polygon = new Polygon(this.vertices.map(v => v.clone()), this.shared); - polygon.intersects = this.intersects; - polygon.valid = this.valid; - return polygon; - } - flip() { - this.vertices.reverse().forEach(v => v.flip()); - // _v3.copy(this.triangle.a); - // this.triangle.a.copy(this.triangle.c); - // this.triangle.c.copy(_v3); - let tmp = this.triangle.a; - this.triangle.a = this.triangle.c; - this.triangle.c = tmp; - this.plane.flip(); - } - delete() { - this.vertices.forEach(v => v.delete()); - this.vertices.length = 0; - this.plane.delete(); - this.plane = undefined; - this.triangle = undefined; - this.shared = undefined; - this.setInvalid(); - } -} - - - - -//// -// Winding Number algorithm adapted from https://github.com/grame-cncm/faust/blob/master-dev/tools/physicalModeling/mesh2faust/vega/libraries/windingNumber/windingNumber.cpp -const _wV1 = new Vector3(); -const _wV2 = new Vector3(); -const _wV3 = new Vector3(); -const _wP = new Vector3(); -const _wP_EPS_ARR = [ - new Vector3(EPSILON, 0, 0), - new Vector3(0, EPSILON, 0), - new Vector3(0, 0, EPSILON), - new Vector3(-EPSILON, 0, 0), - new Vector3(0, -EPSILON, 0), - new Vector3(0, 0, -EPSILON) -]; -const _wP_EPS_ARR_COUNT = _wP_EPS_ARR.length; -const _matrix3 = new Matrix3(); -const wNPI = 4 * Math.PI; - -/* -// Replaced with buffer functions below -function calcWindingNumber(polygons, point) { - let wN = 0; - for (let i = 0; i < polygons.length; i++) { - let pT = polygons[i].triangle; - _wV1.subVectors(pT.a, point); - _wV2.subVectors(pT.b, point); - _wV3.subVectors(pT.c, point); - let lenA = _wV1.length(); - let lenB = _wV2.length(); - let lenC = _wV3.length(); - _matrix3.set(_wV1.x, _wV1.y, _wV1.z, _wV2.x, _wV2.y, _wV2.z, _wV3.x, _wV3.y, _wV3.z); - let omega = 2 * Math.atan2(_matrix3.determinant(), (lenA * lenB * lenC + _wV1.dot(_wV2) * lenC + _wV2.dot(_wV3) * lenA + _wV3.dot(_wV1) * lenB)); - wN += omega; - } - - wN = Math.round(wN / wNPI); - return wN; -} -function polyInside_WindingNumber(polygons, polygon, boundingBox) { - let result = false; - let point = polygon.triangle.midPoint; - _wP.copy(point); - let wN = calcWindingNumber(polygons, _wP); - if (wN === 0) { - if (polygon.coplanar) { - for (let j = 0; j < _wP_EPS_ARR_COUNT; j++) { - _wP.copy(point).add(_wP_EPS_ARR[j]); - wN = calcWindingNumber(polygons, _wP); - if (wN !== 0) { - result = true; - break; - } - } - } - } - else { - result = true; - } - - return result; - -} -*/ - - -function returnXYZ(arr, index) { - return { x: arr[index], y: arr[index + 1], z: arr[index + 2] }; -} -function calcWindingNumber_buffer(trianglesArr, point) { - let wN = 0; - for (let i = 0; i < trianglesArr.length; i += 9) { - _wV1.subVectors(returnXYZ(trianglesArr, i), point); - _wV2.subVectors(returnXYZ(trianglesArr, i + 3), point); - _wV3.subVectors(returnXYZ(trianglesArr, i + 6), point); - let lenA = _wV1.length(); - let lenB = _wV2.length(); - let lenC = _wV3.length(); - _matrix3.set(_wV1.x, _wV1.y, _wV1.z, _wV2.x, _wV2.y, _wV2.z, _wV3.x, _wV3.y, _wV3.z); - let omega = 2 * Math.atan2(_matrix3.determinant(), (lenA * lenB * lenC + _wV1.dot(_wV2) * lenC + _wV2.dot(_wV3) * lenA + _wV3.dot(_wV1) * lenB)); - wN += omega; - } - wN = Math.round(wN / wNPI); - return wN; -} -function polyInside_WindingNumber_buffer(trianglesArr, point, coplanar) { - let result = false; - _wP.copy(point); - let wN = calcWindingNumber_buffer(trianglesArr, _wP); - if (wN === 0) { - if (coplanar) { - for (let j = 0; j < _wP_EPS_ARR_COUNT; j++) { - _wP.copy(point).add(_wP_EPS_ARR[j]); - wN = calcWindingNumber_buffer(trianglesArr, _wP); - if (wN !== 0) { - result = true; - break; - } - } - } - } - else { - result = true; - } - - return result; - -} - -///// - - - -function handleIntersectingOctrees(octreeA, octreeB) { - let octreeA_clone = octreeA.clone(); - let octreeA_buffer; - let octreeB_buffer; - if (OctreeCSG.useWindingNumber === true) { - octreeA_buffer = prepareTriangleBuffer(octreeA_clone.getPolygons()); - octreeB_buffer = prepareTriangleBuffer(octreeB.getPolygons()); - } - octreeA.handleIntersectingPolygons(octreeB, octreeB_buffer); - octreeB.handleIntersectingPolygons(octreeA_clone, octreeA_buffer); - octreeA_clone.delete(); - octreeA_clone = undefined; - if (octreeA_buffer !== undefined) { - octreeA_buffer = undefined; - octreeB_buffer = undefined; - } -} - -OctreeCSG.subtract_async = async function (octreeA, octreeB, buildTargetOctree = true) { - return new Promise(async (resolve, reject) => { - try { - if (workerPool.length < OctreeCSG.maxWebWorkers) { - OctreeCSG.createWorkers(); - } - let octree = new OctreeCSG(); - if (octreeA.box.intersectsBox(octreeB.box)) { - let currentMeshSideA; - let currentMeshSideB; - if (octreeA.mesh) { - currentMeshSideA = octreeA.mesh.material.side; - octreeA.mesh.material.side = OctreeCSG.testSide; - } - if (octreeB.mesh) { - currentMeshSideB = octreeB.mesh.material.side; - octreeB.mesh.material.side = OctreeCSG.testSide; - } - - octreeA.resetPolygons(); - octreeB.resetPolygons(); - octreeA.markIntesectingPolygons(octreeB); - octreeB.markIntesectingPolygons(octreeA); - let before = performance.now(); - console.log("[OctreeCSG.subtract_async] before", performance.now()); - // console.log("before sleep"); - // await sleep(1000); - // console.log("after sleep"); - await handleIntersectingOctrees_async(octreeA, octreeB); - console.log("[OctreeCSG.subtract_async] after", performance.now()); - - octreeA.deletePolygonsByStateRules([ - { - array: true, - rule: ["inside", "coplanar-back"] - }, - { - array: true, - rule: ["inside", "coplanar-front"] - }, - { - array: false, - rule: "inside" - } - ]); - octreeB.deletePolygonsByStateRules([ - { - array: true, - rule: ["outside", "coplanar-back"] - }, - { - array: true, - rule: ["outside", "coplanar-front"] - }, - { - array: true, - rule: ["inside", "coplanar-front"] - }, - { - array: false, - rule: "outside" - } - ]); - - - octreeB.deletePolygonsByIntersection(false); - - - octreeB.invert(); - - if (OctreeCSG.returnType == 0) { - octreeA.getPolygonCallback(octree.addPolygon.bind(octree)); - octreeB.getPolygonCallback(octree.addPolygon.bind(octree)); - } - else if (OctreeCSG.returnType == -1) { - console.log("OctreeA"); - let polys_test = octreeA.getPolygons(); - let limit = Math.min(polys_test.length, 50000); - console.log(`[octreeA] polys_test`, polys_test.length, limit); - for (let i = 0; i < limit; i++) { - if (polys_test[i].intersects) { - let t = polys_test[i].triangle; - // if (((t.a.y < -3) && (t.b.y < -3) && (t.c.y < -3))) { - // if (((t.a.x >= 0.8) && (t.b.x >= 0.8) && (t.c.x >= 0.8))) { - // console.log("AAAA", i, t, polys_test[i]); - octree.addPolygon(polys_test[i]); - // } - } - // else { - // octree.addPolygon(polys_test[i]); - // } - } - } - else { - console.log("OctreeB"); - let polys_test = octreeB.getPolygons(); - let limit = Math.min(polys_test.length, 50000); - console.log(`[octreeB] polys_test`, polys_test.length, limit); - for (let i = 0; i < limit; i++) { - if (polys_test[i].intersects) { - let t = polys_test[i].triangle; - // if ((t.a.x <= 1) && (t.b.x <= 1) && (t.c.x <= 1)) { - // if (((t.a.y === -5) && (t.b.y === -5) && (t.c.y === -5))) { - // console.log("BBBB", i, t, polys_test[i]); - octree.addPolygon(polys_test[i]); - // } - } - // else { - // octree.addPolygon(polys_test[i]); - // } - } - } - - if (octreeA.mesh) { - if (octreeA.mesh.material.side !== currentMeshSideA) { - octreeA.mesh.material.side = currentMeshSideA; - } - } - if (octreeB.mesh) { - if (octreeB.mesh.material.side !== currentMeshSideB) { - octreeB.mesh.material.side = currentMeshSideB; - } - } - } - else { - octreeA.getPolygonCallback(octree.addPolygon.bind(octree)); - } - - buildTargetOctree && octree.buildTree(); - // octree.invert(); - resolve(octree); - } - catch (e) { - reject(e); - } - }); -} - -async function handleIntersectingOctrees_async(octreeA, octreeB) { - return new Promise(async (resolve, reject) => { - try { - const original_useWindingNumber = OctreeCSG.useWindingNumber; - OctreeCSG.useWindingNumber = true; - let octreeA_clone = octreeA.clone(); - // let octreeA_polygons; - // let octreeB_polygons; - let octreeA_buffer; - let octreeB_buffer; - if (OctreeCSG.useWindingNumber === true) { - octreeA_buffer = prepareTriangleBuffer(octreeA_clone.getPolygons()); - octreeB_buffer = prepareTriangleBuffer(octreeB.getPolygons()); - } - // console.log("[handleIntersectingOctrees_async] before"); - // await octreeA.handleIntersectingPolygons_async(octreeB, octreeB_buffer); - octreeA.handleIntersectingPolygons_reduced(octreeB, octreeB_buffer); - // console.log("[handleIntersectingOctrees_async] before 2"); - await handleInsideOutsidePolygons_async(octreeA, octreeB, octreeB_buffer); - // console.log("[handleIntersectingOctrees_async] before 3"); - // await octreeB.handleIntersectingPolygons_async(octreeA_clone, octreeA_buffer); - octreeB.handleIntersectingPolygons_reduced(octreeA_clone, octreeA_buffer); - // console.log("[handleIntersectingOctrees_async] before 4"); - await handleInsideOutsidePolygons_async(octreeB, octreeA_clone, octreeA_buffer); - // console.log("[handleIntersectingOctrees_async] after"); - octreeA_clone.delete(); - octreeA_clone = undefined; - - if (octreeA_buffer !== undefined) { - octreeA_buffer = undefined; - octreeB_buffer = undefined; - } - OctreeCSG.useWindingNumber = original_useWindingNumber; - resolve(); - } - catch (e) { - reject(e) - } - }); -} - -async function handleInsideOutsidePolygons_async(octree, targetOctree, targetOctreeBuffer) { - return new Promise(async (resolve, reject) => { - try { - // polygonStack = this.polygons.filter(polygon => (polygon.valid == true) && (polygon.intersects == true)); - let polygonStack = octree.getIntersectingPolygons(); - let runningWebWorkers = []; - let currentPolygon = polygonStack.pop(); - while (currentPolygon) { - // console.warn("Checking loop polygon id", currentPolygon.id); - if (!currentPolygon.valid) { - continue; - } - - let debugPoly = false; - - // let testTriangle = new THREE.Triangle(new THREE.Vector3(0.29171404242515564, -4.110300540924072, 2.832019329071045), new THREE.Vector3(-0.29171404242515564, -4.110300540924072, 2.832019329071045), new THREE.Vector3(0, -4.3809967041015625, 2.4097442626953125)); - // if ((OctreeCSG.returnType == -1) && (currentPolygon.triangle.equals(testTriangle))) { - // debugPoly = true; - // console.warn("STARTING DEBUG"); - // } - OctreeCSG.debugPoly = debugPoly; - let inside = false; - if (targetOctree.box.containsPoint(currentPolygon.triangle.midPoint)) { - // if (OctreeCSG.useWindingNumber === true) { - // let responses = []; - // // let result1 = OctreeCSG.testWorker(1); - // // let result2 = OctreeCSG.testWorker(2); - let worker = getAvailableWorker(); - while (!worker) { - // console.log("Waiting for worker"); - await sleep(1); - worker = getAvailableWorker(); - } - - worker.checkWindingNumber({ - type: 'windingNumber', - point: currentPolygon.triangle.midPoint, - coplanar: currentPolygon.coplanar, - polygonID: currentPolygon.id, - triangles: targetOctreeBuffer - }, currentPolygon).then(worker => { - // console.log("Worker finished", worker.id); - let workerIndex = runningWebWorkers.indexOf(worker); - if (workerIndex > -1) { - runningWebWorkers.splice(workerIndex, 1); - } - }); - runningWebWorkers.push(worker); - - } - else { - currentPolygon.setState("outside"); - } - - // if (debugPoly) { - // console.log("CHECK INSIDE", inside); - // } - // if (inside === true) { - // currentPolygon.setState("inside"); - // } - // else { - // currentPolygon.setState("outside"); - // } - - currentPolygon = polygonStack.pop(); - } - // console.log("START WAITING", runningWebWorkers.length); - while (runningWebWorkers.length) { - // console.log("Waiting to finish"); - await sleep(1); - } - resolve(); - } - catch (e) { - reject(e); - } - }); -} - -// OctreeCSG.prepareTriangleBuffer = function (polygons) { -// return prepareTriangleBuffer(polygons); -// } - -// {message: data, data: buff} -// OctreeCSG.runWorker = async function (data, transferables) { - -function prepareTriangleBuffer(polygons) { - let numOfTriangles = polygons.length; - // let buffer = new ArrayBuffer(numOfTriangles * 3 * 3 * 4); - // let array = new Float32Array(buffer); - let array = new Float32Array(numOfTriangles * 3 * 3); - let bufferIndex = 0; - for (let i = 0; i < numOfTriangles; i++) { - let triangle = polygons[i].triangle; - array[bufferIndex++] = triangle.a.x; - array[bufferIndex++] = triangle.a.y; - array[bufferIndex++] = triangle.a.z; - array[bufferIndex++] = triangle.b.x; - array[bufferIndex++] = triangle.b.y; - array[bufferIndex++] = triangle.b.z; - array[bufferIndex++] = triangle.c.x; - array[bufferIndex++] = triangle.c.y; - array[bufferIndex++] = triangle.c.z; - } - // return buffer; - return array; -} -OctreeCSG.prepareTriangleBuffer = prepareTriangleBuffer; -const workerPool = []; -OctreeCSG.useWebWorkers = false; -OctreeCSG.useWebWorkersSync = true; -OctreeCSG.maxWebWorkers = navigator.hardwareConcurrency || 4; -OctreeCSG.createWorkers = function () { - let max = OctreeCSG.maxWebWorkers - workerPool.length; - for (let i = 0; i < max; i++) { - OctreeCSG.createWorker(); - } -} -OctreeCSG.getWorkerPool = function () { // FOR TESTING ONLY - WILL BE DELETED BEFORE PROD - return workerPool; -} -function getAvailableWorker() { - for (let i = 0; i < workerPool.length; i++) { - if (!workerPool[i].running) { - return workerPool[i]; - } - } - return; -} -OctreeCSG.createWorker = function () { - let worker = new GenerateWebWorker(); - workerPool.push(worker); - return worker; -} -OctreeCSG.testWorker2 = function (data) { - console.log("OctreeCSG.testWorker2"); - let result = OctreeCSG.testWorker4(data); - console.log("OctreeCSG.testWorker2", result); - return result; - // // let worker = new Worker('./js/OctreeCSG/OctreeCSG.worker.js'); - // let worker = new Worker(new URL('./OctreeCSG.worker.js', import.meta.url), { type: 'module' }); - // worker.onerror = (e) => { - // console.log(e); - // } - // worker.onmessage = (e) => { - // console.log("INC DATA:", e.data); - // } - // worker.postMessage("A"); - -} -OctreeCSG.testWorker4 = function (data) { - console.log("OctreeCSG.testWorker4"); - let result = OctreeCSG.testWorker3(data); - console.log("OctreeCSG.testWorker4", result); - return result; -} -async function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} -OctreeCSG.testWorker3 = async function (data) { - console.log("OctreeCSG.testWorker3"); - let responses = []; - // let result1 = OctreeCSG.testWorker(1); - // let result2 = OctreeCSG.testWorker(2); - let worker = getAvailableWorker(); - if (!worker) { - console.warn("no available workers"); - return; - } - console.log("testing worker"); - worker.sendMessage(data).then(data => responses.push(data)); - let worker2 = getAvailableWorker(); - if (!worker2) { - console.warn("no available workers"); - return; - } - console.log("testing worker 2"); - worker2.sendMessage(data).then(data => responses.push(data)); - while (responses.length < 2) { - console.log("responses not received", responses.length, performance.now()); - await sleep(500); - } - console.log("got response:", responses); - return responses; -} -// OctreeCSG.sendToWorker = async function (data) { -OctreeCSG.testWorker = async function (data) { - console.log("OctreeCSG.testWorker"); - let worker = getAvailableWorker(); - if (!worker) { - console.warn("no available workers"); - return; - } - console.log("testing worker"); - let result = await worker.sendMessage(data); - console.log("got response:", result); - // worker.sendMessage(data).then(workerCB, (msg) => { - // console.log("ERR", msg); - // }); - return result; -} -OctreeCSG.runWorker = async function (data, transferables) { - let worker = getAvailableWorker(); - if (!worker) { - console.warn("no available workers"); - return; - } - // console.log("testing worker"); - let result = await worker.sendMessage(data, transferables); - // console.log("got response:", result); - // worker.sendMessage(data).then(workerCB, (msg) => { - // console.log("ERR", msg); - // }); - return result; -} -function workerCB() { - console.log("CALLBACK", arguments); -} - -let webWorker_ID = 0; -class GenerateWebWorker { - constructor() { - this.running = false; - this.worker = new Worker(new URL('./OctreeCSG.worker.js', import.meta.url), { type: 'module' }); - this.worker.onerror = (e) => { - if (e.message) { - throw new Error(`[OctreeCSG] GenerateWebWorker: Could not create a web worker with the error "${e.message}"`); - } - else { - throw new Error(`[OctreeCSG] GenerateWebWorker: Could not create a web worker, no error message was provided.`); - } - } - this.id = webWorker_ID++; - } - checkWindingNumber(data, currentPolygon) { - // worker.checkWindingNumber({ - // type: windingNumber, - // point: currentPolygon.triangle.midPoint, - // coplanar: currentPolygon.coplanar, - // polygonID: currentPolygon.id, - // triangles: targetOctreeBuffer - // }, currentPolygon) - if (this.running) { - throw new Error(`[GenerateWebWorker] checkWindingNumber: Worker is already running`); - } - if (this.worker === null) { - throw new Error(`[GenerateWebWorker] checkWindingNumber: Worker has beein disposed`); - } - this.running = true; - const { worker } = this; - return new Promise((resolve, reject) => { - try { - worker.onerror = (e) => { - reject(new Error(`[GenerateWebWorker] checkWindingNumber: ${e.message}`)); - this.running = false; - worker.onmessage = null; - } - worker.onmessage = (e) => { - const { data } = e; - if (data.error) { - reject(new Error(data.error)); - worker.onmessage = null; - } - if ((data.type === 'windingNumber') && currentPolygon) { - if (data.result === true) { - currentPolygon.setState("inside"); - } - else { - currentPolygon.setState("outside"); - } - resolve(this); - } - else { - resolve(data); - } - this.running = false; - worker.onmessage = null; - } - // console.log("GOT HERE?", worker); - // let numOfObjects = 1; - // let buff = new ArrayBuffer(numOfObjects * 4); - // let test = new Float32Array(buff); - // test[0] = 7; - // {message: data, data: buff} - worker.postMessage(data); - } - catch (e) { - reject(e); - worker.onmessage = null; - } - - }); - } - sendMessage(data, transferables, currentPolygon) { - if (this.running) { - throw new Error(`[GenerateWebWorker] sendMessage: Worker is already running`); - } - if (this.worker === null) { - throw new Error(`[GenerateWebWorker] sendMessage: Worker has beein disposed`); - } - this.running = true; - const { worker } = this; - return new Promise((resolve, reject) => { - try { - worker.onerror = (e) => { - reject(new Error(`[GenerateWebWorker] sendMessage: ${e.message}`)); - // reject(e); - this.running = false; - worker.onmessage = null; - } - worker.onmessage = (e) => { - // console.log("INC DATA:", e); - const { data } = e; - if (data.error) { - reject(new Error(data.error)); - worker.onmessage = null; - } - resolve(data); - this.running = false; - worker.onmessage = null; - } - // console.log("GOT HERE?", worker); - // let numOfObjects = 1; - // let buff = new ArrayBuffer(numOfObjects * 4); - // let test = new Float32Array(buff); - // test[0] = 7; - // {message: data, data: buff} - worker.postMessage(data, transferables); - } - catch (e) { - reject(e); - worker.onmessage = null; - } - - }); - } - dispose() { - if (this.worker) { - this.worker.terminate(); - this.worker = undefined; - let workerIndex = workerPool.indexOf(this); - if (workerIndex > -1) { - workerPool.splice(workerIndex, 1); - } - } - } -} - - - -//////// -// https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm -const edge1 = new Vector3(); -const edge2 = new Vector3(); -const h = new Vector3(); -const s = new Vector3(); -const q = new Vector3(); -function rayIntersectsTriangle(ray, triangle, target = new Vector3()) { - - - const EPSILON = 0.0000001; - edge1.subVectors(triangle.b, triangle.a); - edge2.subVectors(triangle.c, triangle.a); - h.crossVectors(ray.direction, edge2); - let a = edge1.dot(h); - if (a > -EPSILON && a < EPSILON) { - return null; // Ray is parallel to the triangle - } - let f = 1 / a; - s.subVectors(ray.origin, triangle.a); - let u = f * s.dot(h); - if (u < 0 || u > 1) { - return null; - } - q.crossVectors(s, edge1); - let v = f * ray.direction.dot(q); - if (v < 0 || u + v > 1) { - return null; - } - // Check where intersection is - let t = f * edge2.dot(q); - if (t > EPSILON) { - return target.copy(ray.direction).multiplyScalar(t).add(ray.origin); - } - // else { - return null; - // } -} -OctreeCSG.rayIntersectsTriangle = rayIntersectsTriangle; -//////// -OctreeCSG.returnType = 0; - -OctreeCSG.testSide = DoubleSide; -OctreeCSG.useOctreeRay = true; -OctreeCSG.getRayPolys = true; -OctreeCSG.useWindingNumber = false; -OctreeCSG.rayIntersectTriangleType = "MollerTrumbore"; // "regular" (three.js' ray.intersectTriangle; "MollerTrumbore" (Moller Trumbore algorithm); - - -OctreeCSG.debugPoly = false; -OctreeCSG.useWindingNumberTurbo = false; -OctreeCSG.useGDTest = false; - -//// - - - -// TODO: test max level 10 and (min) polys per tree 100 or 200 -OctreeCSG.maxLevel = 16; -OctreeCSG.polygonsPerTree = 100; - -OctreeCSG.Polygon = Polygon; -export default OctreeCSG; \ No newline at end of file diff --git a/test/OctreeCSG/OctreeCSG.worker.js b/test/OctreeCSG/OctreeCSG.worker.js deleted file mode 100644 index 5f46637..0000000 --- a/test/OctreeCSG/OctreeCSG.worker.js +++ /dev/null @@ -1,107 +0,0 @@ -import * as THREE from '../threejs/three.module.js'; -// console.log("GOT HERE"); -onmessage = function (e) { - // let randLimit = Math.round(Math.random() * 1000000000); - // console.log("[WORKER]", randLimit, e); - // let worker_data = { - // type: 'windingNumber', - // point: point, - // triangles: buffer - // } - const { type, point, coplanar, polygonID, triangles } = e.data; - let trianglesArr = new Float32Array(triangles); - // console.log("[WORKER] Checking Polygon ID:", polygonID, point); - if (type === 'windingNumber') { - postMessage({ - type, - result: polyInside_WindingNumber_buffer(trianglesArr, point, coplanar) - }); - } - else { - let a = 0; - // for (let i = 0; i < randLimit; i++) { - // a++; - // } - postMessage("[From Worker] Aloha " + a); - } -} - -//// -const EPSILON = 1e-5; -// Winding Number algorithm adapted from https://github.com/grame-cncm/faust/blob/master-dev/tools/physicalModeling/mesh2faust/vega/libraries/windingNumber/windingNumber.cpp -const _wV1 = new THREE.Vector3(); -const _wV2 = new THREE.Vector3(); -const _wV3 = new THREE.Vector3(); -const _wP = new THREE.Vector3(); -const _wP_EPS_ARR = [ - new THREE.Vector3(EPSILON, 0, 0), - new THREE.Vector3(0, EPSILON, 0), - new THREE.Vector3(0, 0, EPSILON), - new THREE.Vector3(-EPSILON, 0, 0), - new THREE.Vector3(0, -EPSILON, 0), - new THREE.Vector3(0, 0, -EPSILON) -]; -const _wP_EPS_ARR_COUNT = _wP_EPS_ARR.length; -const _matrix3 = new THREE.Matrix3(); -const wNPI = 4 * Math.PI; - -// function calcDet(a, b, c) { -// return (-a.z * b.y * c.x + -// a.y * b.z * c.x + -// a.z * b.x * c.y + -// a.x * b.z * c.y + -// a.y * b.x * c.z + -// a.x * b.y * c.z ); -// } -function returnXYZ(arr, index) { - return { x: arr[index], y: arr[index + 1], z: arr[index + 2] }; -} -function calcWindingNumber_buffer(trianglesArr, point) { - let wN = 0; - for (let i = 0; i < trianglesArr.length; i += 9) { - _wV1.subVectors(returnXYZ(trianglesArr, i), point); - _wV2.subVectors(returnXYZ(trianglesArr, i + 3), point); - _wV3.subVectors(returnXYZ(trianglesArr, i + 6), point); - let lenA = _wV1.length(); - let lenB = _wV2.length(); - let lenC = _wV3.length(); - _matrix3.set(_wV1.x, _wV1.y, _wV1.z, _wV2.x, _wV2.y, _wV2.z, _wV3.x, _wV3.y, _wV3.z); - let omega = 2 * Math.atan2(_matrix3.determinant(), (lenA * lenB * lenC + _wV1.dot(_wV2) * lenC + _wV2.dot(_wV3) * lenA + _wV3.dot(_wV1) * lenB)); - wN += omega; - } - wN = Math.round(wN / wNPI); - return wN; -} -function polyInside_WindingNumber_buffer(trianglesArr, point, coplanar) { - let result = false; - _wP.copy(point); - let wN = calcWindingNumber_buffer(trianglesArr, _wP); - let coplanarFound = false; - if (wN === 0) { - if (coplanar) { - // console.log("POLYGON IS COPLANAR"); - for (let j = 0; j < _wP_EPS_ARR_COUNT; j++) { - // console.warn("DOES IT GET HERE?"); - _wP.copy(point).add(_wP_EPS_ARR[j]); - wN = calcWindingNumber_buffer(trianglesArr, _wP); - if (wN !== 0) { - // console.warn("GOT HERE"); - result = true; - coplanarFound = true; - break; - } - } - } - } - else { - result = true; - } - // if (result && polygon.coplanar) { - // console.log(`[polyInside_WindingNumber] coplanar polygon found ${coplanarFound ? "IN" : "NOT IN"} coplanar test`); - // } - - return result; - -} - -// export {}; \ No newline at end of file diff --git a/test/app3.css b/test/app3.css deleted file mode 100644 index 6f78b3e..0000000 --- a/test/app3.css +++ /dev/null @@ -1,25 +0,0 @@ -body { - margin: 0; - overflow: hidden; -} - -canvas { - display: block; -} - -button { - background: black; - opacity: .5; - border: none; - color: white; -} - -#mainDiv { - position: absolute; - z-index: 10; - left: 10px; - top: 50px; - font-family: Arial, Helvetica, sans-serif; - color: white; - background: rgba(50,50,50,.5); -} diff --git a/test/app3.js b/test/app3.js deleted file mode 100644 index bf74889..0000000 --- a/test/app3.js +++ /dev/null @@ -1,329 +0,0 @@ -import*as THREE from "three"; -import {OrbitControls} from "threeModules/controls/OrbitControls.js"; -import {TransformControls} from "threeModules/controls/TransformControls.js"; - -//import*as THREE from "https://threejs.org/build/three.module.js"; - -//import { ConvexHull } from "../three.js-dev/examples/jsm/math/ConvexHull.js"; -//import GridMaterial from "./grid-material.js"; -import Environment from "./cool-env.js" - -class App3 { - - constructor() { - let camera, scene, renderer, ocontrols; - - renderer = new THREE.WebGLRenderer({ - antialias: true, - alpha: true - }); - renderer.setClearColor(0x101010); - renderer.outputEncoding = THREE.sRGBEncoding; - //renderer.shadowMap.type = THREE.VSMShadowMap; - renderer.shadowMap.type = THREE.PCFSoftShadowMap; - renderer.shadowMap.enabled = true; - document.body.appendChild(renderer.domElement); - - scene = new THREE.Scene(); - - let aspect = window.innerWidth / window.innerHeight; - camera = this.camera = new THREE.PerspectiveCamera(75,aspect,0.1,1000); - scene.add(camera); - - - let environment = this.environment = new Environment(renderer,scene,camera) - - var raycaster = new THREE.Raycaster(); - var mouse = new THREE.Vector2(); - - let lastSavedPosition = new THREE.Vector3(0,1.5,2) - - ocontrols = this.orbitControls = new OrbitControls(camera,renderer.domElement); - ocontrols.enabled = true; - ocontrols.minZoom = ocontrols.minDistance = 1; - try { - camera.position.copy(JSON.parse(localStorage.cameraPosition)) - ocontrols.target.copy(JSON.parse(localStorage.controlsTarget)) - } catch { - camera.position.copy(lastSavedPosition); - ocontrols.target.set(0, 0, 0) - } - // camera.lookAt(0, 0, 0); - let frontMaterial = Environment.mkMat('yellow') - frontMaterial.transparent = true; - frontMaterial.opacity = .25; - - let transformControls = this.transformControls = new TransformControls(camera,renderer.domElement); - transformControls.translationSnap = 0.05; - transformControls.rotationSnap = Math.PI / 16; - scene.add(transformControls); - /* - let gridmat = Environment.mkMat(0x404040) - gridmat.transparent = true; - let grid = GridMaterial.makeGrid(gridmat) - scene.add(grid); -*/ - - let selectionMaterial = Environment.mkMat(0x404040); - //grid.material.clone(); - //new GridMaterial(frontMaterial.clone()); - selectionMaterial.color.set('blue'); - selectionMaterial.emissive.set(0x202020) - selectionMaterial.transparent = true - selectionMaterial.opacity = .5 - - let transformGroup = this.transformGroup = new THREE.Group(); - scene.add(transformGroup); - transformControls.attach(transformGroup); - - let tv30 = new THREE.Vector3(); - class Elements { - constructor() { - this.selected = {}; - this.selection = []; - this.elements = []; - } - get selectedCount() { - return this.selection.length; - } - forEach(fn) { - this.elements.slice(0).forEach(fn); - } - forSelected(fn) { - this.selection.slice(0).forEach(fn); - } - setMaterial(m, mat) { - if (!m.userData.saveMaterial && m.userData.material !== m.material) - m.userData.saveMaterial = m.material; - m.material = mat; - } - clearSelection() { - this.forSelected((e)=>{ - scene.attach(e); - if (e.userData.saveMaterial) - e.material = e.userData.saveMaterial - } - ) - this.selected = {}; - this.selection = []; - } - - deselect(idx) { - let e = this.selected[idx]; - if (e) { - delete this.selected[idx]; - scene.attach(e); - this.selection = [] - this.forEach((e,i)=>this.selected[i] && this.selection.push(e) && ((e.userData.saveMaterial) && (e.material = e.userData.saveMaterial))) - this.update(); - } - } - - update() { - if (this.selectedCount) { - if (this.lastSelectedId != this.selection[0].uuid) { - this.lastSelectedId = this.selection[0].uuid - if (!this.selectionChangedEvent) - this.selectionChangedEvent = new Event('selectionChanged') - this.selectionChangedEvent.app = this; - document.dispatchEvent(this.selectionChangedEvent) - } - this.forSelected(e=>scene.attach(e)) - transformGroup.position.set(0, 0, 0); - this.forSelected(e=>transformGroup.position.add(e.position)); - transformGroup.position.multiplyScalar(1 / this.selectedCount); - transformGroup.updateMatrixWorld() - this.forSelected(e=>transformGroup.attach(e)) - - } - } - select(idx) { - let e = this.elements[idx]; - this.selected[idx] = e; - this.selection.push(e); - this.setMaterial(e, selectionMaterial); - transformGroup.attach(e); - this.update(); - } - set(e) { - this.forEach(s=>s.parent.remove(s)); - this.elements = e.slice(0); - this.selection = []; - - this.forEach((s,i)=>{ - scene.attach(s); - if (this.selected[i]) - this.select(i); - } - ); - this.update(); - } - } - - let elements = new Elements(); - - let wasDragged = false; - - let transpMat = (color,opacity)=>{ - let m = Environment.mkMat(color) - if ((m.opacity = opacity) === 1) - m.transparent = true; - return m - } - - let materials = this.materials = [transpMat('gray', 1.), transpMat('red', .7), transpMat('green', .7), transpMat('purple', .7), transpMat('teal', .7), transpMat('orange', .7), ] - - transformControls.addEventListener("dragging-changed", event=>{ - ocontrols.enabled = !event.value; - wasDragged = event.value; - if (!wasDragged) {//console.log("Dragging"); - } else {//console.log("Drag"); - //setElements(fc.update()) - } - } - ); - - this.scene = scene; - this.elements = elements; - - this.mouseWorld = new THREE.Vector3(0,0,0) - this.smoothMouseWorld = new THREE.Vector3(0,0,0) - - this.mouse = { - mouseWorld: this.mouseWorld, - smoothMouseWorld: this.smoothMouseWorld, - buttons: 0 - } - - let groundProxy = new THREE.Mesh(new THREE.PlaneBufferGeometry(1000,1000)) - groundProxy.rotation.x = Math.PI * -.5 - groundProxy.updateMatrixWorld() - - let v0 = new THREE.Vector3(); - - let mouseChangeEvent = new Event('mouseChange') - let mouseEvent = event=>{ - mouse.x = (event.clientX / window.innerWidth) * 2 - 1; - mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; - raycaster.setFromCamera(mouse, camera); - // calculate objects intersecting the picking ray - var intersects = raycaster.intersectObjects(elements.elements); - this.mouse.buttons = event.buttons; - // scene.children ); - if (!intersects.length) { - if ((!event.buttons) && !(event.ctrlKey || event.shiftKey || event.altKey)) { - ocontrols.enabled = true; - transformControls.enabled = false; - } - let gndintersects = raycaster.intersectObjects([groundProxy]); - if (gndintersects.length) { - this.mouseWorld.copy(gndintersects[0].point) - return - } - } - if (event.type === "pointerdown") { - if (event.target !== renderer.domElement) - return; - if (wasDragged) - return; - - if (intersects.length) { - ocontrols.enabled = false; - transformControls.enabled = true; - - if (!event.shiftKey) - elements.clearSelection() - let o = intersects[0].object; - elements.forEach((e,i)=>e === o && ((!elements.selected[i]) ? elements.select(i) : elements.deselect(i))); - } else if (!wasDragged) { - if (event.buttons === 1) - elements.clearSelection(); - } - } else if (event.type === "pointerup") {//updateCSG() - } else if (event.type === "pointermove") {} - - mouseChangeEvent.event = event; - document.dispatchEvent(mouseChangeEvent) - - transformControls.enabled = transformControls.visible = elements.selectedCount ? true : false; - } - ; - - window.addEventListener("keyup", ()=>transformControls.setMode("translate"), false); - window.addEventListener("pointermove", mouseEvent, false); - window.addEventListener("pointerdown", mouseEvent, false); - window.addEventListener("pointerup", mouseEvent, false); - - let resizeFn = event=>{ - let width = window.innerWidth; - let height = window.innerHeight; - camera.aspect = width / height; - camera.updateProjectionMatrix(); - - renderer.setSize(width, height); - if (environment && environment.composer) - environment.resize(width, height) - } - ; - - resizeFn(); - window.addEventListener("resize", resizeFn, false) - - let clamp = (v,n,p)=>v < n ? n : v > p ? p : v - let clampPoint = (pt,mdist)=>{ - pt.set(clamp(pt.x, -mdist, mdist), clamp(pt.y, -mdist, mdist), clamp(pt.z, -mdist, mdist)) - } - - let constrainView = ()=>{ - - if (ocontrols.target.y < 1) { - camera.position.y += 1 - ocontrols.target.y; - ocontrols.target.y += 1 - ocontrols.target.y; - } - if (camera.position.y < 1) { - ocontrols.target.y += 1 - camera.position.y; - camera.position.y += 1 - camera.position.y; - } - ocontrols.maxDistance = 1000; - if (ocontrols.target.y < 1) { - //camera.position.y += 1-ocontrols.target.y; - ocontrols.target.y += 1 - ocontrols.target.y; - } - //ocontrols.target.set(0,0,0) - clampPoint(ocontrols.target, 1000) - clampPoint(camera.position, 1000) - //clampPoint(camera.position,100) - } - - let beforeRenderEvent = new Event('beforeRender') - let afterRenderEvent = new Event('afterRender') - renderer.setAnimationLoop(()=>{ - this.smoothMouseWorld.add(v0.copy(this.mouseWorld).sub(this.smoothMouseWorld).multiplyScalar(0.1)) - // Mouse smoothing... - ocontrols.update(); - if (!lastSavedPosition.equals(camera.position)) { - lastSavedPosition.copy(camera.position) - localStorage.cameraPosition = JSON.stringify(camera.position) - localStorage.controlsTarget = JSON.stringify(ocontrols.target) - } - - constrainView() - - document.dispatchEvent(beforeRenderEvent) - if (environment && environment.composer && false) - environment.composer.render(); - else - renderer.render(scene, camera); - document.dispatchEvent(afterRenderEvent) - - } - ); - - this.renderer = renderer; - let initEvt = new Event('init') - initEvt.app = this; - document.dispatchEvent(initEvt); - } -} - -export default new App3(); diff --git a/test/cool-env.js b/test/cool-env.js deleted file mode 100644 index ba6d927..0000000 --- a/test/cool-env.js +++ /dev/null @@ -1,219 +0,0 @@ - -import*as THREE from "three"; -//import { CSS3DRenderer } from "../../../three.js-dev/examples/jsm/renderers/CSS3DRenderer.js"; - -import {HDRCubeTextureLoader} from "threeModules/loaders/HDRCubeTextureLoader.js"; -import {RGBELoader} from "threeModules/loaders/RGBELoader.js"; -//import {RoughnessMipmapper} from 'threeModules/utils/RoughnessMipmapper.js'; -//import {PMREMGenerator} from "../three.js-dev/examples/jsm/pmrem/PMREMGenerator.js"; -//import {PMREMCubeUVPacker} from "../three.js-dev/examples/jsm/pmrem/PMREMCubeUVPacker.js"; - -import {EffectComposer} from "threeModules/postprocessing/EffectComposer.js"; -import {RenderPass} from "threeModules/postprocessing/RenderPass.js"; -import {ShaderPass} from "threeModules/postprocessing/ShaderPass.js"; -import {CopyShader} from "threeModules/shaders/CopyShader.js"; -import {LuminosityHighPassShader} from "threeModules/shaders/LuminosityHighPassShader.js"; -import {UnrealBloomPass} from "threeModules/postprocessing/UnrealBloomPass.js"; -import {FXAAShader} from "threeModules/shaders/FXAAShader.js"; - -import {SSAOShader} from "threeModules/shaders/SSAOShader.js"; -import {SSAOPass} from "threeModules/postprocessing/SSAOPass.js"; - -import {SimplexNoise} from "threeModules/math/SimplexNoise.js"; - -class Environment { - constructor(renderer, scene, camera) { - let ssaoPass; - let fxaaPass; - let self = this; - function setupPostProcessing() { - var bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth,window.innerHeight),1.5,0.4,0.85); - bloomPass.threshold = 0.99; - //0.85; 0,1.5,0 - bloomPass.strength = 1.2; - bloomPass.radius = 0.0; - //0.02; - - //renderer.toneMapping = THREE.ACESFilmicToneMapping; - //renderer.toneMapping = THREE.ReinhardToneMapping; - renderer.toneMapping = THREE.LinearToneMapping; - //renderer.toneMapping = THREE.CineonToneMapping; - renderer.toneMappingExposure = .8; - //0.5;//2.3; - - var renderScene = new RenderPass(scene,camera); - - let composer = new EffectComposer(renderer); - let width = window.innerWidth; - let height = window.innerHeight; - - composer.addPass(renderScene); - - fxaaPass = new ShaderPass(FXAAShader); - - renderer.setPixelRatio(1); - - var pixelRatio = renderer.getPixelRatio(); - - let copyPass = new ShaderPass(THREE.CopyShader); - - ssaoPass = new SSAOPass(scene,camera,width,height); - ssaoPass.minDistance = 0.005; - ssaoPass.maxDistance = 0.28; - ssaoPass.kernelRadius = 10.1; - - self.resize = (width,height)=>{ - - composer.setSize(width, height); - - fxaaPass.material.uniforms["resolution"].value.x = 1 / (width * pixelRatio); - fxaaPass.material.uniforms["resolution"].value.y = 1 / (height * pixelRatio); - ssaoPass.setSize(width, height) - - } - self.resize(window.innerWidth, window.innerHeight); - //bloomPass.renderToScreen = false; - - composer.addPass(fxaaPass); - - //ssaoPass.clear = false; - //composer.addPass( ssaoPass ); - - //composer.addPass( copyPass ); - - composer.addPass(bloomPass); - - //renderer.toneMapping = THREE.ReinhardToneMapping; - return composer; - } - - let composer = this.composer = setupPostProcessing(); - - // use of RoughnessMipmapper is optional - //var roughnessMipmapper = new RoughnessMipmapper(renderer); - - function loadHDREquirect(path) { - var pmremGenerator = new THREE.PMREMGenerator(renderer); - pmremGenerator.compileEquirectangularShader(); - new RGBELoader()//.setDataType(THREE.UnsignedByteType)// .setPath( '../three.js-dev/examples/textures/equirectangular/' ) - // .load( 'royal_esplanade_1k.hdr', - .setPath('') - .load( 'https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr',//'./venice_sunset_1k.hdr', - //.load('../assets/san_giuseppe_bridge_4k.hdr', - function(texture) { - var envMap = pmremGenerator.fromEquirectangular(texture).texture; - scene.background = envMap; - scene.environment = envMap; - texture.dispose(); - pmremGenerator.dispose(); - }) - - } - - function loadHDRCubeMap(dir) { - var hdrCubeRenderTarget; - var hdrCubeMap; - var NhdrUrls = ["px.hdr", "nx.hdr", "py.hdr", "ny.hdr", "pz.hdr", "nz.hdr"]; - var hdrUrls = ["https://cdn.glitch.com/02b1773f-db1a-411a-bc71-ff25644e8e51%2Fpx.hdr?v=1594535462236", "https://cdn.glitch.com/02b1773f-db1a-411a-bc71-ff25644e8e51%2Fnx.hdr?v=1594535462924", "https://cdn.glitch.com/02b1773f-db1a-411a-bc71-ff25644e8e51%2Fpy.hdr?v=1594535455937", "https://cdn.glitch.com/02b1773f-db1a-411a-bc71-ff25644e8e51%2Fny.hdr?v=1594535464928", "https://cdn.glitch.com/02b1773f-db1a-411a-bc71-ff25644e8e51%2Fpz.hdr?v=1594535459665", "https://cdn.glitch.com/02b1773f-db1a-411a-bc71-ff25644e8e51%2Fnz.hdr?v=1594535458938"]; - dir = dir || ""; - //"san_guiseppe_bridge"; - hdrCubeMap = new HDRCubeTextureLoader().setDataType(THREE.UnsignedByteType).load(hdrUrls, function() { - var pmremGenerator = new THREE.PMREMGenerator(renderer); - - hdrCubeRenderTarget = pmremGenerator.fromCubemap(hdrCubeMap); - pmremGenerator.dispose(); - - hdrCubeMap.magFilter = THREE.LinearFilter; - hdrCubeMap.needsUpdate = true; - - scene.background = hdrCubeMap; - - var newEnvMap = hdrCubeRenderTarget ? hdrCubeRenderTarget.texture : null; - - scene.environment = newEnvMap - }); - return { - cubeMap: hdrCubeMap, - cubeRenderTarget: hdrCubeRenderTarget - }; - } - - let hdr = loadHDREquirect(); - //loadHDR(); - - function mkCanvas(dim) { - var canvas = document.createElement("canvas"); - canvas.width = canvas.height = dim; - return canvas; - } - this.mkCanvas = mkCanvas; - function makeProceduralTexture(dim, fn) { - var canv = mkCanvas(dim); - var ctx = canv.getContext("2d"); - var pix = ctx.getImageData(0, 0, dim, dim); - var u32view = new DataView(pix.data.buffer); - var idx = -4; - for (var j = 0; j < dim; j++) - for (var i = 0; i < dim; i++) - u32view.setUint32((idx += 4), fn(j / dim, i / dim) | 0); - ctx.putImageData(pix, 0, 0); - var tex = new THREE.Texture(canv); - tex.needsUpdate = true; - return tex; - } - var tx = makeProceduralTexture(1024, (u,v)=>{ - var rb = ((Math.random() * 128) | 0) * ((((u * 2) & 1) ^ ((v * 2) & 1)) | 0 ? 1 : 2); - return ((rb * 256) | (rb * 256 * 256) | (rb * 256 * 256 * 256) | 0x000000ff); - } - ); - tx.repeat.set(2, 2); - tx.wrapS = tx.wrapT = THREE.RepeatWrapping; - this.makeProceduralTexture = makeProceduralTexture - - let mkMat = (color='white')=>new THREE.MeshStandardMaterial({ - color: color, - roughness: 0.51, - metalness: 0.7, - roughnessMap: tx - }); - - this.mkMat = Environment.mkMat = mkMat; - - let rnd = rng=>(Math.random() * 2 - 1) * (rng || 1); - - - let light1 = new THREE.DirectionalLight(); - light1.position.set(2.8, 12, -15); - light1.position.set(10, 12, 10); - light1.castShadow = true; - var setShadowSize = (sz,mapSz)=>{ - light1.shadow.camera.left = sz; - light1.shadow.camera.bottom = sz; - light1.shadow.camera.right = -sz; - light1.shadow.camera.top = -sz; - if (mapSz) { - light1.shadow.mapSize.set(mapSz, mapSz); - } - } - ; - setShadowSize(20, 2048); - scene.add(light1); - light1.shadow.bias = -.0001 - - //light1.shadow.bias=-0.0001 - let ground = new THREE.Mesh(new THREE.BoxGeometry(2000,1,2000),mkMat("grey")); - scene.add(ground); - ground.position.y -= 2.; - ground.name = "ground"; - ground.receiveShadow = true; - ground.material.roughnessMap = ground.material.roughnessMap.clone(); - ground.material.roughnessMap.repeat.set(80, 80); - ground.material.roughnessMap.needsUpdate = true; - ground.material.color.set(0x101010) - ground.material.metalness = 0.2; - ground.material.roughness = .9; - - } -} - -export default Environment; diff --git a/test/csg-lib.js b/test/csg-lib.js deleted file mode 100644 index c9fb043..0000000 --- a/test/csg-lib.js +++ /dev/null @@ -1,482 +0,0 @@ - -// ## License -// -// Copyright (c) 2011 Evan Wallace (http://madebyevan.com/), under the MIT license. -// THREE.js rework by thrax - -// # class CSG -// Holds a binary space partition tree representing a 3D solid. Two solids can -// be combined using the `union()`, `subtract()`, and `intersect()` methods. - - -class CSG { - constructor() { - this.polygons = []; - } - clone() { - let csg = new CSG(); - csg.polygons = this.polygons.map(p=>p.clone()) - return csg; - } - - toPolygons() { - return this.polygons; - } - - union(csg) { - let a = new Node(this.clone().polygons); - let b = new Node(csg.clone().polygons); - a.clipTo(b); - b.clipTo(a); - b.invert(); - b.clipTo(a); - b.invert(); - a.build(b.allPolygons()); - return CSG.fromPolygons(a.allPolygons()); - } - - subtract(csg) { - let a = new Node(this.clone().polygons); - let b = new Node(csg.clone().polygons); - a.invert(); - a.clipTo(b); - b.clipTo(a); - b.invert(); - b.clipTo(a); - b.invert(); - a.build(b.allPolygons()); - a.invert(); - return CSG.fromPolygons(a.allPolygons()); - } - - intersect(csg) { - let a = new Node(this.clone().polygons); - let b = new Node(csg.clone().polygons); - a.invert(); - b.clipTo(a); - b.invert(); - a.clipTo(b); - b.clipTo(a); - a.build(b.allPolygons()); - a.invert(); - return CSG.fromPolygons(a.allPolygons()); - } - - // Return a new CSG solid with solid and empty space switched. This solid is - // not modified. - inverse() { - let csg = this.clone(); - csg.polygons.forEach(p=>p.flip()); - return csg; - } -} - -// Construct a CSG solid from a list of `Polygon` instances. -CSG.fromPolygons=function(polygons) { - let csg = new CSG(); - csg.polygons = polygons; - return csg; -} - -// # class Vector - -// Represents a 3D vector. -// -// Example usage: -// -// new CSG.Vector(1, 2, 3); - - - -class Vector { - constructor(x=0, y=0, z=0) { - this.x=x; - this.y=y; - this.z=z; - } - copy(v){ - this.x=v.x; - this.y=v.y; - this.z=v.z; - return this - } - clone() { - return new Vector(this.x,this.y,this.z) - } - negate() { - this.x*=-1; - this.y*=-1; - this.z*=-1; - return this - } - add(a) { - this.x+=a.x - this.y+=a.y - this.z+=a.z - return this; - } - sub(a) { - this.x-=a.x - this.y-=a.y - this.z-=a.z - return this - } - times(a) { - this.x*=a - this.y*=a - this.z*=a - return this - } - dividedBy(a) { - this.x/=a - this.y/=a - this.z/=a - return this - } - lerp(a, t) { - return this.add(tv0.copy(a).sub(this).times(t)) - } - unit() { - return this.dividedBy(this.length()) - } - length(){ - return Math.sqrt((this.x**2)+(this.y**2)+(this.z**2)) - } - normalize(){ - return this.unit() - } - cross(b) { - let a = this; - const ax = a.x, ay = a.y, az = a.z; - const bx = b.x, by = b.y, bz = b.z; - - this.x = ay * bz - az * by; - this.y = az * bx - ax * bz; - this.z = ax * by - ay * bx; - - return this; - } - dot(b){ - return (this.x*b.x)+(this.y*b.y)+(this.z*b.z) - } -} - -//Temporaries used to avoid internal allocation.. -let tv0=new Vector() -let tv1=new Vector() - - -// # class Vertex - -// Represents a vertex of a polygon. Use your own vertex class instead of this -// one to provide additional features like texture coordinates and vertex -// colors. Custom vertex classes need to provide a `pos` property and `clone()`, -// `flip()`, and `interpolate()` methods that behave analogous to the ones -// defined by `CSG.Vertex`. This class provides `normal` so convenience -// functions like `CSG.sphere()` can return a smooth vertex normal, but `normal` -// is not used anywhere else. - -class Vertex { - - constructor(pos, normal, uv, color) { - this.pos = new Vector().copy(pos); - this.normal = new Vector().copy(normal); - uv && (this.uv = new Vector().copy(uv)) && (this.uv.z=0); - color && (this.color = new Vector().copy(color)); - } - - clone() { - return new Vertex(this.pos,this.normal,this.uv,this.color); - } - - // Invert all orientation-specific data (e.g. vertex normal). Called when the - // orientation of a polygon is flipped. - flip() { - this.normal.negate(); - } - - // Create a new vertex between this vertex and `other` by linearly - // interpolating all properties using a parameter of `t`. Subclasses should - // override this to interpolate additional properties. - interpolate(other, t) { - return new Vertex(this.pos.clone().lerp(other.pos, t),this.normal.clone().lerp(other.normal, t),this.uv&&other.uv&&this.uv.clone().lerp(other.uv, t), this.color&&other.color&&this.color.clone().lerp(other.color,t)) - } -} -; -// # class Plane - -// Represents a plane in 3D space. - -class Plane { - constructor(normal, w) { - this.normal = normal; - this.w = w; - } - - clone() { - return new Plane(this.normal.clone(),this.w); - } - - flip() { - this.normal.negate(); - this.w = -this.w; - } - - // Split `polygon` by this plane if needed, then put the polygon or polygon - // fragments in the appropriate lists. Coplanar polygons go into either - // `coplanarFront` or `coplanarBack` depending on their orientation with - // respect to this plane. Polygons in front or in back of this plane go into - // either `front` or `back`. - splitPolygon(polygon, coplanarFront, coplanarBack, front, back) { - const COPLANAR = 0; - const FRONT = 1; - const BACK = 2; - const SPANNING = 3; - - // Classify each point as well as the entire polygon into one of the above - // four classes. - let polygonType = 0; - let types = []; - for (let i = 0; i < polygon.vertices.length; i++) { - let t = this.normal.dot(polygon.vertices[i].pos) - this.w; - let type = (t < -Plane.EPSILON) ? BACK : (t > Plane.EPSILON) ? FRONT : COPLANAR; - polygonType |= type; - types.push(type); - } - - // Put the polygon in the correct list, splitting it when necessary. - switch (polygonType) { - case COPLANAR: - (this.normal.dot(polygon.plane.normal) > 0 ? coplanarFront : coplanarBack).push(polygon); - break; - case FRONT: - front.push(polygon); - break; - case BACK: - back.push(polygon); - break; - case SPANNING: - let f = [] - , b = []; - for (let i = 0; i < polygon.vertices.length; i++) { - let j = (i + 1) % polygon.vertices.length; - let ti = types[i] - , tj = types[j]; - let vi = polygon.vertices[i] - , vj = polygon.vertices[j]; - if (ti != BACK) - f.push(vi); - if (ti != FRONT) - b.push(ti != BACK ? vi.clone() : vi); - if ((ti | tj) == SPANNING) { - let t = (this.w - this.normal.dot(vi.pos)) / this.normal.dot(tv0.copy(vj.pos).sub(vi.pos)); - let v = vi.interpolate(vj, t); - f.push(v); - b.push(v.clone()); - } - } - if (f.length >= 3) - front.push(new Polygon(f,polygon.shared)); - if (b.length >= 3) - back.push(new Polygon(b,polygon.shared)); - break; - } - } - -} - -// `Plane.EPSILON` is the tolerance used by `splitPolygon()` to decide if a -// point is on the plane. -Plane.EPSILON = 1e-5; - -Plane.fromPoints = function(a, b, c) { - let n = tv0.copy(b).sub(a).cross(tv1.copy(c).sub(a)).normalize() - return new Plane(n.clone(),n.dot(a)); -} - - -// # class Polygon - -// Represents a convex polygon. The vertices used to initialize a polygon must -// be coplanar and form a convex loop. They do not have to be `Vertex` -// instances but they must behave similarly (duck typing can be used for -// customization). -// -// Each convex polygon has a `shared` property, which is shared between all -// polygons that are clones of each other or were split from the same polygon. -// This can be used to define per-polygon properties (such as surface color). - -class Polygon { - constructor(vertices, shared) { - this.vertices = vertices; - this.shared = shared; - this.plane = Plane.fromPoints(vertices[0].pos, vertices[1].pos, vertices[2].pos); - } - clone() { - return new Polygon(this.vertices.map(v=>v.clone()),this.shared); - } - flip() { - this.vertices.reverse().forEach(v=>v.flip()) - this.plane.flip(); - } -} - -// # class Node - -// Holds a node in a BSP tree. A BSP tree is built from a collection of polygons -// by picking a polygon to split along. That polygon (and all other coplanar -// polygons) are added directly to that node and the other polygons are added to -// the front and/or back subtrees. This is not a leafy BSP tree since there is -// no distinction between internal and leaf nodes. - -class Node { - constructor(polygons) { - this.plane = null; - this.front = null; - this.back = null; - this.polygons = []; - if (polygons) - this.build(polygons); - } - clone() { - let node = new Node(); - node.plane = this.plane && this.plane.clone(); - node.front = this.front && this.front.clone(); - node.back = this.back && this.back.clone(); - node.polygons = this.polygons.map(p=>p.clone()); - return node; - } - - // Convert solid space to empty space and empty space to solid space. - invert() { - for (let i = 0; i < this.polygons.length; i++) - this.polygons[i].flip(); - - this.plane && this.plane.flip(); - this.front && this.front.invert(); - this.back && this.back.invert(); - let temp = this.front; - this.front = this.back; - this.back = temp; - } - - // Recursively remove all polygons in `polygons` that are inside this BSP - // tree. - clipPolygons(polygons) { - if (!this.plane) - return polygons.slice(); - let front = [] - , back = []; - - for (let i = 0; i < polygons.length; i++) { - this.plane.splitPolygon(polygons[i], front, back, front, back); - } - if (this.front) - front = this.front.clipPolygons(front); - if (this.back) - back = this.back.clipPolygons(back); - else - back = []; - //return front; - return front.concat(back); - } - - // Remove all polygons in this BSP tree that are inside the other BSP tree - // `bsp`. - clipTo(bsp) { - this.polygons = bsp.clipPolygons(this.polygons); - if (this.front) - this.front.clipTo(bsp); - if (this.back) - this.back.clipTo(bsp); - } - - // Return a list of all polygons in this BSP tree. - allPolygons() { - let polygons = this.polygons.slice(); - if (this.front) - polygons = polygons.concat(this.front.allPolygons()); - if (this.back) - polygons = polygons.concat(this.back.allPolygons()); - return polygons; - } - - // Build a BSP tree out of `polygons`. When called on an existing tree, the - // new polygons are filtered down to the bottom of the tree and become new - // nodes there. Each set of polygons is partitioned using the first polygon - // (no heuristic is used to pick a good split). - build(polygons) { - if (!polygons.length) - return; - if (!this.plane) - this.plane = polygons[0].plane.clone(); - let front = [] - , back = []; - for (let i = 0; i < polygons.length; i++) { - this.plane.splitPolygon(polygons[i], this.polygons, this.polygons, front, back); - } - if (front.length) { - if (!this.front) - this.front = new Node(); - this.front.build(front); - } - if (back.length) { - if (!this.back) - this.back = new Node(); - this.back.build(back); - } - } -} - -// Inflate/deserialize a vanilla struct into a CSG structure webworker. -CSG.fromJSON=function(json){ - return CSG.fromPolygons(json.polygons.map(p=>new Polygon(p.vertices.map(v=> new Vertex(v.pos,v.normal,v.uv)),p.shared))) -} - -export {CSG,Vertex,Vector,Polygon,Plane} - - - -// Return a new CSG solid representing space in either this solid or in the -// solid `csg`. Neither this solid nor the solid `csg` are modified. -// -// A.union(B) -// -// +-------+ +-------+ -// | | | | -// | A | | | -// | +--+----+ = | +----+ -// +----+--+ | +----+ | -// | B | | | -// | | | | -// +-------+ +-------+ -// -// Return a new CSG solid representing space in this solid but not in the -// solid `csg`. Neither this solid nor the solid `csg` are modified. -// -// A.subtract(B) -// -// +-------+ +-------+ -// | | | | -// | A | | | -// | +--+----+ = | +--+ -// +----+--+ | +----+ -// | B | -// | | -// +-------+ -// -// Return a new CSG solid representing space both this solid and in the -// solid `csg`. Neither this solid nor the solid `csg` are modified. -// -// A.intersect(B) -// -// +-------+ -// | | -// | A | -// | +--+----+ = +--+ -// +----+--+ | +--+ -// | B | -// | | -// +-------+ -// - diff --git a/test/csg-worker.js b/test/csg-worker.js deleted file mode 100644 index a76ad2c..0000000 --- a/test/csg-worker.js +++ /dev/null @@ -1,76 +0,0 @@ -import {CSG} from "./csg-lib.js" - - -let gWorkersStarted = false; -let gWorker; -let gWorkerUrl; - -let taskId = 0; -let tasks={} -let spawnWorker=()=>{ - const worker = new Worker(gWorkerUrl) - - worker.onmessage = function(e) { - let rslt = JSON.parse(e.data) - let task = tasks[rslt.taskId] - delete tasks[rslt.taskId] - task.resolve(CSG.fromJSON(rslt.result)) - //console.log('Message received from worker'); - gWorker.busy = false; - } - return gWorker = {worker,busy:false}; -} - -let getWorker=()=>{ - if(!gWorkersStarted){ - gWorkersStarted = true; - return fetch('../csg-lib.js').then(function(response) { - return response.text().then(function(text) { - text = text.slice(0, text.lastIndexOf('export')); - const code = text + ` - self.onmessage=(message)=>{ - let task = JSON.parse(message.data) - //console.log("Got task:"+task.op+' '+task.taskId) - postMessage(JSON.stringify({ - taskId:task.taskId, - result : CSG.fromJSON(task.a)[task.op](CSG.fromJSON(task.b)) - })) - } - console.log('CSG worker started!')` - const blob = new Blob([code],{ - type: 'application/javascript' - }) - gWorkerUrl = URL.createObjectURL(blob); - - - }).then(()=>{ - return spawnWorker() - }) - }); - } - if(gWorker && (!gWorker.busy)){ - gWorker.busy = true; - - return {then:(fn)=>{return fn(gWorker);}} - } - return{ - then:function(){return this} - } -} - -CSG.doAsync=(a,op,b)=>{ - return getWorker().then((worker)=>{ - let task={a,op,b,taskId} - tasks[taskId]=task; - taskId++; - task.result = new Promise((resolve,reject)=>{ - task.resolve = resolve; - //console.log("posting to worker:") - worker.busy = true; - worker.worker.postMessage(JSON.stringify(task)) - }) - return task.result - }) -} - -export default {} \ No newline at end of file diff --git a/test/three-csg.js b/test/three-csg.js deleted file mode 100644 index afc0f87..0000000 --- a/test/three-csg.js +++ /dev/null @@ -1,219 +0,0 @@ -"use strict" - -import*as THREE from "three"; - - -let { BufferGeometry, Vector3, Vector2} = THREE; -import {CSG, Vertex, Vector, Polygon} from "./csg-lib.js" -//import {Geometry} from "../three.js-dev/examples/jsm/deprecated/Geometry.js"; - -CSG.fromGeometry = function(geom,objectIndex) { - let polys = [] - if (geom.isGeometry) { - let fs = geom.faces; - let vs = geom.vertices; - let fm = ['a', 'b', 'c'] - for (let i = 0; i < fs.length; i++) { - let f = fs[i]; - let vertices = [] - for (let j = 0; j < 3; j++) - vertices.push(new Vertex(vs[f[fm[j]]],f.vertexNormals[j],geom.faceVertexUvs[0][i][j])) - polys.push(new Polygon(vertices, objectIndex)) - } - } else if (geom.isBufferGeometry) { - let vertices, normals, uvs - let posattr = geom.attributes.position - let normalattr = geom.attributes.normal - let uvattr = geom.attributes.uv - let colorattr = geom.attributes.color - let index; - if (geom.index) - index = geom.index.array; - else { - index = new Array((posattr.array.length / posattr.itemSize) | 0); - for (let i = 0; i < index.length; i++) - index[i] = i - } - let triCount = (index.length / 3) | 0 - polys = new Array(triCount) - for (let i = 0, pli = 0, l = index.length; i < l; i += 3, - pli++) { - let vertices = new Array(3) - for (let j = 0; j < 3; j++) { - let vi = index[i + j] - let vp = vi * 3; - let vt = vi * 2; - let x = posattr.array[vp] - let y = posattr.array[vp + 1] - let z = posattr.array[vp + 2] - let nx = normalattr.array[vp] - let ny = normalattr.array[vp + 1] - let nz = normalattr.array[vp + 2] - //let u = uvattr.array[vt] - //let v = uvattr.array[vt + 1] - vertices[j] = new Vertex({ - x, - y, - z - },{ - x: nx, - y: ny, - z: nz - },uvattr&&{ - x: uvattr.array[vt], - y: uvattr.array[vt+1], - z: 0 - },colorattr&&{x:colorattr.array[vt],y:colorattr.array[vt+1],z:colorattr.array[vt+2]}); - } - polys[pli] = new Polygon(vertices,objectIndex) - } - } else - console.error("Unsupported CSG input type:" + geom.type) - return CSG.fromPolygons(polys) -} - -let ttvv0 = new THREE.Vector3() -let tmpm3 = new THREE.Matrix3(); -CSG.fromMesh = function(mesh,objectIndex) { - let csg = CSG.fromGeometry(mesh.geometry,objectIndex) - tmpm3.getNormalMatrix(mesh.matrix); - for (let i = 0; i < csg.polygons.length; i++) { - let p = csg.polygons[i] - for (let j = 0; j < p.vertices.length; j++) { - let v = p.vertices[j] - v.pos.copy(ttvv0.copy(v.pos).applyMatrix4(mesh.matrix)); - v.normal.copy(ttvv0.copy(v.normal).applyMatrix3(tmpm3)) - } - } - return csg; -} - -let nbuf3=(ct)=>{ - return{ - top:0, - array:new Float32Array(ct), - write:function(v){(this.array[this.top++]=v.x);(this.array[this.top++]=v.y);(this.array[this.top++]=v.z);} - } -} -let nbuf2=(ct)=>{ - return{ - top:0, - array:new Float32Array(ct), - write:function(v){(this.array[this.top++]=v.x);(this.array[this.top++]=v.y)} - } -} - -CSG.toGeometry = function(csg, buffered=true) { - let ps = csg.polygons; - let geom; - let g2; - if(!buffered) //Old geometry path... - { - geom = new Geometry(); - let vs = geom.vertices; - let fvuv = geom.faceVertexUvs[0] - for (let i = 0; i < ps.length; i++) { - let p = ps[i] - let pvs = p.vertices; - let v0 = vs.length; - let pvlen = pvs.length - - for (let j = 0; j < pvlen; j++) - vs.push(new THREE.Vector3().copy(pvs[j].pos)) - - for (let j = 3; j <= pvlen; j++) { - let fc = new THREE.Face3(); - let fuv = [] - fvuv.push(fuv) - let fnml = fc.vertexNormals; - fc.a = v0; - fc.b = v0 + j - 2; - fc.c = v0 + j - 1; - - fnml.push(new THREE.Vector3().copy(pvs[0].normal)) - fnml.push(new THREE.Vector3().copy(pvs[j - 2].normal)) - fnml.push(new THREE.Vector3().copy(pvs[j - 1].normal)) - fuv.push(new THREE.Vector3().copy(pvs[0].uv)) - fuv.push(new THREE.Vector3().copy(pvs[j - 2].uv)) - fuv.push(new THREE.Vector3().copy(pvs[j - 1].uv)) - - fc.normal = new THREE.Vector3().copy(p.plane.normal) - geom.faces.push(fc) - } - } - geom = new THREE.BufferGeometry().fromGeometry(geom) - geom.verticesNeedUpdate = geom.elementsNeedUpdate = geom.normalsNeedUpdate = true; - }else { //BufferGeometry path - let triCount = 0; - ps.forEach(p=>triCount += (p.vertices.length - 2)) - geom = new THREE.BufferGeometry() - - let vertices = nbuf3(triCount * 3 * 3) - let normals = nbuf3(triCount * 3 * 3) - let uvs; // = nbuf2(triCount * 2 * 3) - let colors; - let grps=[] - ps.forEach(p=>{ - let pvs = p.vertices - let pvlen = pvs.length - if(p.shared!==undefined){ - if(!grps[p.shared])grps[p.shared]=[] - } - if(pvlen){ - if(pvs[0].color!==undefined){ - if(!colors)colors = nbuf3(triCount*3*3); - } - if(pvs[0].uv!==undefined){ - if(!uvs)uvs = nbuf2(triCount * 2 * 3) - } - } - for (let j = 3; j <= pvlen; j++) { - (p.shared!==undefined) && (grps[p.shared].push(vertices.top/3,(vertices.top/3)+1,(vertices.top/3)+2)); - vertices.write(pvs[0].pos) - vertices.write(pvs[j-2].pos) - vertices.write(pvs[j-1].pos) - normals.write(pvs[0].normal) - normals.write(pvs[j-2].normal) - normals.write(pvs[j-1].normal); - uvs&&(pvs[0].uv)&&(uvs.write(pvs[0].uv)||uvs.write(pvs[j-2].uv)||uvs.write(pvs[j-1].uv)); - colors&&(colors.write(pvs[0].color)||colors.write(pvs[j-2].color)||colors.write(pvs[j-1].color)) - } - } - ) - geom.setAttribute('position', new THREE.BufferAttribute(vertices.array,3)); - geom.setAttribute('normal', new THREE.BufferAttribute(normals.array,3)); - uvs && geom.setAttribute('uv', new THREE.BufferAttribute(uvs.array,2)); - colors && geom.setAttribute('color', new THREE.BufferAttribute(colors.array,3)); - if(grps.length){ - let index = [] - let gbase=0; - for(let gi=0;gi splitDist ) { - - splitDist = dist; - splitDimIdx = i; - - } - - } - - return splitDimIdx; - -} - -// copys bounds a into bounds b -function copyBounds( source, target ) { - - target.set( source ); - -} - -// sets bounds target to the union of bounds a and b -function unionBounds( a, b, target ) { - - let aVal, bVal; - for ( let d = 0; d < 3; d ++ ) { - - const d3 = d + 3; - - // set the minimum values - aVal = a[ d ]; - bVal = b[ d ]; - target[ d ] = aVal < bVal ? aVal : bVal; - - // set the max values - aVal = a[ d3 ]; - bVal = b[ d3 ]; - target[ d3 ] = aVal > bVal ? aVal : bVal; - - } - -} - -// expands the given bounds by the provided triangle bounds -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; - - } - - } - -} - -// compute bounds surface area -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 ); - -} - -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; - - } - - } - -} - -// Computes the set of { offset, count } ranges which need independent BVH roots. Each -// region in the geometry index that belongs to a different set of material groups requires -// a separate BVH root, so that triangles indices belonging to one group never get swapped -// with triangle indices belongs to another group. For example, if the groups were like this: -// -// [-------------------------------------------------------------] -// |__________________| -// g0 = [0, 20] |______________________||_____________________| -// g1 = [16, 40] g2 = [41, 60] -// -// we would need four BVH roots: [0, 15], [16, 20], [21, 40], [41, 60]. -function getRootIndexRanges( geo ) { - - if ( ! geo.groups || ! geo.groups.length ) { - - return [ { offset: 0, count: geo.index.count / 3 } ]; - - } - - const ranges = []; - const rangeBoundaries = new Set(); - for ( const group of geo.groups ) { - - rangeBoundaries.add( group.start ); - rangeBoundaries.add( group.start + group.count ); - - } - - // note that if you don't pass in a comparator, it sorts them lexicographically as strings :-( - 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; - -} - -// computes the union of the bounds of all of the given triangles and puts the resulting box in target. If -// centroidTarget is provided then a bounding box is computed for the centroids of the triangles, as well. -// These are computed together to avoid redundant accesses to bounds array. -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; - - } - -} - -// A stand alone function for retrieving the centroid bounds. -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; - -} - - -// reorders `tris` such that for `count` elements after `offset`, elements on the left side of the split -// will be on the left and elements on the right side of the split will be on the right. returns the index -// of the first element on the right side, or offset + count if there are no elements on the right side. -function partition( index, triangleBounds, offset, count, split ) { - - let left = offset; - let right = offset + count - 1; - const pos = split.pos; - const axisOffset = split.axis * 2; - - // hoare partitioning, see e.g. https://en.wikipedia.org/wiki/Quicksort#Hoare_partition_scheme - while ( true ) { - - while ( left <= right && triangleBounds[ left * 6 + axisOffset ] < pos ) { - - left ++; - - } - - - // if a triangle center lies on the partition plane it is considered to be on the right side - while ( left <= right && triangleBounds[ right * 6 + axisOffset ] >= pos ) { - - right --; - - } - - if ( left < right ) { - - // we need to swap all of the information associated with the triangles at index - // left and right; that's the verts in the geometry index, the bounds, - // and perhaps the SAH planes - - 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; - - } - - } - -} - -const BIN_COUNT = 32; -const binsSort = ( a, b ) => a.candidate - b.candidate; -const sahBins = new Array( BIN_COUNT ).fill().map( () => { - - return { - - count: 0, - bounds: new Float32Array( 6 ), - rightCacheBounds: new Float32Array( 6 ), - leftCacheBounds: new Float32Array( 6 ), - candidate: 0, - - }; - -} ); -const leftBounds = new Float32Array( 6 ); - -function getOptimalSplit( nodeBoundingData, centroidBoundingData, triangleBounds, offset, count, strategy ) { - - let axis = - 1; - let pos = 0; - - // Center - 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; - - // iterate over all axes - 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 we have fewer triangles than we're planning to split then just check all - // the triangle positions because it will be faster. - if ( count < BIN_COUNT / 4 ) { - - // initialize the bin candidates - const truncatedBins = [ ...sahBins ]; - truncatedBins.length = count; - - // set the candidates - 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 ); - - // remove redundant splits - 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 --; - - } - - } - - // find the appropriate bin for each triangle and expand the bounds. - 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 ++; - - } - - } - - } - - // expand all the bounds - for ( let bi = 0; bi < splitCount; bi ++ ) { - - const bin = truncatedBins[ bi ]; - const leftCount = bin.count; - const rightCount = count - bin.count; - - // check the cost of this split - const leftBounds = bin.leftCacheBounds; - const rightBounds = bin.rightCacheBounds; - - let leftProb = 0; - if ( leftCount !== 0 ) { - - leftProb = computeSurfaceArea( leftBounds ) / 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 { - - // reset the bins - 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; - - } - - } - - // iterate over all center positions - for ( let c = cStart; c < cEnd; c += 6 ) { - - const triCenter = triangleBounds[ c + 2 * a ]; - const relativeCenter = triCenter - axisLeft; - - // in the partition function if the centroid lies on the split plane then it is - // considered to be on the right side of the split - let binIndex = ~ ~ ( relativeCenter / binWidth ); - if ( binIndex >= BIN_COUNT ) binIndex = BIN_COUNT - 1; - - const bin = sahBins[ binIndex ]; - bin.count ++; - - expandByTriangleBounds( c, triangleBounds, bin.bounds ); - - } - - // cache the unioned bounds from right to left so we don't have to regenerate them each time - 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; - - // dont do anything with the bounds if the new bounds have no triangles - if ( binCount !== 0 ) { - - if ( leftCount === 0 ) { - - copyBounds( bounds, leftBounds ); - - } else { - - unionBounds( bounds, leftBounds, leftBounds ); - - } - - } - - leftCount += binCount; - - // check the cost of this split - 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 }; - -} - -// returns the average coordinate on the specified axis of the all the provided triangles -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; - -} - -// precomputes the bounding box for each triangle; required for quickly calculating tree splits. -// result is an array of size tris.length * 6 where triangle i maps to a -// [x_center, x_delta, y_center, y_delta, z_center, z_delta] tuple starting at index i * 6, -// representing the center and half-extent in each dimension of triangle i -function computeTriangleBounds( geo, fullBounds ) { - - const posAttr = geo.attributes.position; - const posArr = posAttr.array; - const index = geo.index.array; - const triCount = index.length / 3; - const triangleBounds = new Float32Array( triCount * 6 ); - - // support for an interleaved position buffer - const bufferOffset = posAttr.offset || 0; - let stride = 3; - if ( posAttr.isInterleavedBufferAttribute ) { - - stride = posAttr.data.stride; - - } - - for ( let tri = 0; tri < triCount; tri ++ ) { - - const tri3 = tri * 3; - const tri6 = tri * 6; - const ai = index[ tri3 + 0 ] * stride + bufferOffset; - const bi = index[ tri3 + 1 ] * stride + bufferOffset; - const ci = index[ tri3 + 2 ] * stride + bufferOffset; - - for ( let el = 0; el < 3; el ++ ) { - - const a = posArr[ ai + el ]; - const b = posArr[ bi + el ]; - const 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; - - // Increase the bounds size by float32 epsilon to avoid precision errors when - // converting to 32 bit float. Scale the epsilon by the size of the numbers being - // worked with. - 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 ); - - } - - } - - // either recursively splits the given node, creating left and right subtrees for it, or makes it a leaf node, - // recording the offset and count of its triangles and writing them into the reordered geometry index. - 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 ); - - } - - } - - // early out if we've met our capacity - if ( count <= maxLeafTris || depth >= maxDepth ) { - - triggerProgress( offset ); - node.offset = offset; - node.count = count; - return node; - - } - - // Find where to split the volume - const split = getOptimalSplit( node.boundingData, centroidBoundingData, triangleBounds, offset, count, strategy ); - if ( split.axis === - 1 ) { - - triggerProgress( offset ); - node.offset = offset; - node.count = count; - return node; - - } - - const splitOffset = partition( indexArray, triangleBounds, offset, count, split ); - - // create the two new child nodes - if ( splitOffset === offset || splitOffset === offset + count ) { - - triggerProgress( offset ); - node.offset = offset; - node.count = count; - - } else { - - node.splitAxis = split.axis; - - // create the left child and compute its bounding box - 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 ); - - // repeat for right - 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 ); - - // Compute the full bounds of the geometry at the same time as triangle bounds because - // we'll need it for the root bounds in the case with no groups and it should be fast here. - // We can't use the geometrying bounding box if it's available because it may be out of date. - 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 ) { - - // boundingData : 6 float32 - // right / offset : 1 uint32 - // splitAxis / isLeaf + count : 1 uint32 / 2 uint16 - 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; - - } - - } - -} - -class SeparatingAxisBounds { - - 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; - - }; - -} )(); - -const areIntersecting = ( function () { - - const cacheSatBounds = new SeparatingAxisBounds(); - return function areIntersecting( 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; - - // check axes of the first shape - 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; - - } - - // check axes of the second shape - 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; - - } - - }; - -} )(); - -const closestPointLineToLine = ( function () { - - // https://github.com/juj/MathGeoLib/blob/master/src/Geometry/Line.cpp#L56 - const dir1 = new Vector3(); - const dir2 = new Vector3(); - const v02 = new Vector3(); - return function closestPointLineToLine( 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, l2.start ); - dir2.subVectors( l2.end, l2.start ); - - // float d0232 = v02.Dot(v32); - const d0232 = v02.dot( v32 ); - - // float d3210 = v32.Dot(v10); - const d3210 = v32.dot( v10 ); - - // float d3232 = v32.Dot(v32); - const d3232 = v32.dot( v32 ); - - // float d0210 = v02.Dot(v10); - const d0210 = v02.dot( v10 ); - - // float d1010 = v10.Dot(v10); - const d1010 = v10.dot( v10 ); - - // float denom = d1010*d3232 - d3210*d3210; - 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; - - }; - -} )(); - -const closestPointsSegmentToSegment = ( function () { - - // https://github.com/juj/MathGeoLib/blob/master/src/Geometry/LineSegment.cpp#L187 - const paramResult = new Vector2(); - const temp1 = new Vector3(); - const temp2 = new Vector3(); - return function closestPointsSegmentToSegment( 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 ) { - - // Only d2 is out of bounds. - if ( d2 < 0 ) { - - l2.at( 0, target2 ); - - } else { - - l2.at( 1, target2 ); - - } - - l1.closestPointToPoint( target2, true, target1 ); - return; - - } else if ( d2 >= 0 && d2 <= 1 ) { - - // Only d is out of bounds. - if ( d < 0 ) { - - l1.at( 0, target1 ); - - } else { - - l1.at( 1, target1 ); - - } - - l2.closestPointToPoint( target1, true, target2 ); - return; - - } else { - - // Both u and u2 are out of bounds. - 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 = temp1; - const closestPoint2 = temp2; - l1.closestPointToPoint( p2, true, temp1 ); - l2.closestPointToPoint( p, true, temp2 ); - - if ( closestPoint.distanceToSquared( p2 ) <= closestPoint2.distanceToSquared( p ) ) { - - target1.copy( closestPoint ); - target2.copy( p2 ); - return; - - } else { - - target1.copy( p ); - target2.copy( closestPoint2 ); - return; - - } - - } - - }; - -} )(); - - -const sphereIntersectTriangle = ( function () { - - // https://stackoverflow.com/questions/34043955/detect-collision-between-sphere-and-triangle-in-three-js - const closestPointTemp = new Vector3(); - const projectedPointTemp = new Vector3(); - const planeTemp = new Plane(); - const lineTemp = new Line3(); - return function sphereIntersectTriangle( sphere, triangle ) { - - const { radius, center } = sphere; - const { a, b, c } = triangle; - - // phase 1 - 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; - - // phase 2 - 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; - - }; - -} )(); - -class SeparatingAxisTriangle extends Triangle { - - constructor( ...args ) { - - super( ...args ); - - this.isSeparatingAxisTriangle = 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 = false; - - } - - 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; - - } - -} - -SeparatingAxisTriangle.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; - - // check the triangle edges - 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 ); - - } - - } - - // check end points - 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 ); - - }; - -} )(); - -SeparatingAxisTriangle.prototype.intersectsTriangle = ( function () { - - const saTri2 = new SeparatingAxisTriangle(); - 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(); - - // TODO: If the triangles are coplanar and intersecting the target is nonsensical. It should at least - // be a line contained by both triangles if not a different special case somehow represented in the return result. - return function intersectsTriangle( other, target = null ) { - - if ( this.needsUpdate ) { - - this.update(); - - } - - if ( ! other.isSeparatingAxisTriangle ) { - - saTri2.copy( other ); - saTri2.update(); - other = saTri2; - - } else if ( other.needsUpdate ) { - - other.update(); - - } - - 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; - - } - - // check crossed axes - 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 ) { - - const plane1 = this.plane; - const plane2 = other.plane; - - if ( Math.abs( plane1.normal.dot( plane2.normal ) ) > 1.0 - 1e-10 ) { - - // TODO find two points that intersect on the edges and make that the result - console.warn( 'SeparatingAxisTriangle.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 ); - - } else { - - // find the edge that intersects the other triangle plane - const points1 = this.points; - let found1 = false; - for ( let i = 0; i < 3; i ++ ) { - - const p1 = points1[ i ]; - const p2 = points1[ ( i + 1 ) % 3 ]; - - edge.start.copy( p1 ); - edge.end.copy( p2 ); - - if ( plane2.intersectLine( edge, found1 ? edge1.start : edge1.end ) ) { - - if ( found1 ) { - - break; - - } - - found1 = true; - - } - - } - - // find the other triangles edge that intersects this plane - const points2 = other.points; - let found2 = false; - for ( let i = 0; i < 3; i ++ ) { - - const p1 = points2[ i ]; - const p2 = points2[ ( i + 1 ) % 3 ]; - - edge.start.copy( p1 ); - edge.end.copy( p2 ); - - if ( plane1.intersectLine( edge, found2 ? edge2.start : edge2.end ) ) { - - if ( found2 ) { - - break; - - } - - found2 = true; - - } - - } - - // find swap the second edge so both lines are running the same direction - edge1.delta( dir1 ); - edge2.delta( dir2 ); - - - if ( dir1.dot( dir2 ) < 0 ) { - - let tmp = edge2.start; - edge2.start = edge2.end; - edge2.end = tmp; - - } - - 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; - - }; - -} )(); - - -SeparatingAxisTriangle.prototype.distanceToPoint = ( function () { - - const target = new Vector3(); - return function distanceToPoint( point ) { - - this.closestPointToPoint( point, target ); - return point.distanceTo( target ); - - }; - -} )(); - - -SeparatingAxisTriangle.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; - - // check all point distances - 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 ); - - }; - -} )(); - -class OrientedBox extends Box3 { - - constructor( ...args ) { - - super( ...args ); - - this.isOrientedBox = true; - 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; - - } - - set( min, max, matrix ) { - - super.set( min, max ); - this.matrix = matrix; - this.needsUpdate = true; - - } - - copy( other ) { - - super.copy( other ); - this.matrix.copy( other.matrix ); - this.needsUpdate = true; - - } - -} - -OrientedBox.prototype.update = ( 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 ) { - - // TODO: should this be doing SAT against the AABB? - 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 SeparatingAxisTriangle(); - 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.isSeparatingAxisTriangle ) { - - 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; - - } - - // check crossed axes - 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 = ( 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 xyzFields = [ '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(); - - // early out if we find a value below threshold - 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; - - - // iterate over every edge and compare distances - let closestDistanceSq = Infinity; - - // check over all these points - 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 ); - - } - - } - - // generate and check all line segment distances - 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; - - // get obb line segments - 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 ); - - - // get aabb line segments - const f1 = xyzFields[ i ]; - const f2 = xyzFields[ nextIndex ]; - const f3 = xyzFields[ 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 ++; - - } - - } - - } - - // check all the other boxes point - 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 ); - - }; - -} )(); - -// Ripped and modified From THREE.js Mesh raycast -// https://github.com/mrdoob/three.js/blob/0aa87c999fe61e216c1133fba7a95772b503eddf/src/objects/Mesh.js#L115 -const vA = /* @__PURE__ */ new Vector3(); -const vB = /* @__PURE__ */ new Vector3(); -const vC = /* @__PURE__ */ new Vector3(); - -const uvA = /* @__PURE__ */ new Vector2(); -const uvB = /* @__PURE__ */ new Vector2(); -const uvC = /* @__PURE__ */ new Vector2(); - -const intersectionPoint = /* @__PURE__ */ new Vector3(); -function checkIntersection( ray, pA, pB, pC, point, side ) { - - let intersect; - if ( side === BackSide ) { - - intersect = ray.intersectTriangle( pC, pB, pA, true, point ); - - } else { - - intersect = ray.intersectTriangle( pA, pB, pC, side !== DoubleSide, point ); - - } - - if ( intersect === null ) return null; - - const distance = ray.origin.distanceTo( point ); - - return { - - distance: distance, - point: point.clone(), - - }; - -} - -function checkBufferGeometryIntersection( ray, position, uv, a, b, c, side ) { - - vA.fromBufferAttribute( position, a ); - vB.fromBufferAttribute( position, b ); - vC.fromBufferAttribute( position, c ); - - const intersection = checkIntersection( ray, 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: a, - b: b, - c: c, - normal: new Vector3(), - materialIndex: 0 - }; - - Triangle.getNormal( vA, vB, vC, face.normal ); - - intersection.face = face; - intersection.faceIndex = a; - - } - - return intersection; - -} - -// https://github.com/mrdoob/three.js/blob/0aa87c999fe61e216c1133fba7a95772b503eddf/src/objects/Mesh.js#L258 -function intersectTri( geo, side, ray, 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( ray, geo.attributes.position, geo.attributes.uv, a, b, c, side ); - - if ( intersection ) { - - intersection.faceIndex = tri; - if ( intersections ) intersections.push( intersection ); - return intersection; - - } - - return null; - -} - -function intersectTris( geo, side, ray, offset, count, intersections ) { - - for ( let i = offset, end = offset + count; i < end; i ++ ) { - - intersectTri( geo, side, ray, i, intersections ); - - } - -} - -function intersectClosestTri( geo, side, ray, offset, count ) { - - let dist = Infinity; - let res = null; - for ( let i = offset, end = offset + count; i < end; i ++ ) { - - const intersection = intersectTri( geo, side, ray, i ); - if ( intersection && intersection.distance < dist ) { - - res = intersection; - dist = intersection.distance; - - } - - } - - return res; - -} - -// converts the given BVH raycast intersection to align with the three.js raycast -// structure (include object, world space distance and point). -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; - - } - -} - -// sets the vertices of triangle `tri` with the 3 vertices after i -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; - -} - -const tempV1 = /* @__PURE__ */ new Vector3(); -const tempV2 = /* @__PURE__ */ new Vector3(); -const tempV3 = /* @__PURE__ */ new Vector3(); -const tempUV1 = /* @__PURE__ */ new Vector2(); -const tempUV2 = /* @__PURE__ */ new Vector2(); -const tempUV3 = /* @__PURE__ */ 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 ); - - // find the associated material index - 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; - - } - - } - - // extract uvs - 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 ); - - } - - // adjust the provided target or create a new one - 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: a, - b: b, - c: c, - materialIndex: materialIndex, - normal: Triangle.getNormal( tempV1, tempV2, tempV3, new Vector3() ) - }, - uv: uv - }; - - } - -} - -class PrimitivePool { - - 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 ); - - } - -} - -function IS_LEAF( n16, uint16Array ) { - - return uint16Array[ n16 + 15 ] === 0xFFFF; - -} - -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; - -} - -const boundingBox$1 = new Box3(); -const boxIntersection = new Vector3(); -const xyzFields = [ 'x', 'y', 'z' ]; - -function raycast( nodeIndex32, geometry, side, ray, 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, ray, offset, count, intersects ); - - } else { - - const leftIndex = LEFT_NODE( nodeIndex32 ); - if ( intersectRay( leftIndex, float32Array, ray, boxIntersection ) ) { - - raycast( leftIndex, geometry, side, ray, intersects ); - - } - - const rightIndex = RIGHT_NODE( nodeIndex32, uint32Array ); - if ( intersectRay( rightIndex, float32Array, ray, boxIntersection ) ) { - - raycast( rightIndex, geometry, side, ray, intersects ); - - } - - } - -} - -function raycastFirst( nodeIndex32, geometry, side, ray ) { - - 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, ray, offset, count ); - - } else { - - // consider the position of the split plane with respect to the oncoming ray; whichever direction - // the ray is coming from, look for an intersection among that side of the tree first - const splitAxis = SPLIT_AXIS( nodeIndex32, uint32Array ); - const xyzAxis = xyzFields[ splitAxis ]; - const rayDir = ray.direction[ xyzAxis ]; - const leftToRight = rayDir >= 0; - - // c1 is the child to check first - 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, ray, boxIntersection ); - const c1Result = c1Intersection ? raycastFirst( c1, geometry, side, ray ) : null; - - // if we got an intersection in the first node and it's closer than the second node's bounding - // box, we don't need to consider the second node because it couldn't possibly be a better result - if ( c1Result ) { - - // check if the point is within the second bounds - // "point" is in the local frame of the bvh - const point = c1Result.point[ xyzAxis ]; - const isOutside = leftToRight ? - point <= float32Array[ c2 + splitAxis ] : // min bounding data - point >= float32Array[ c2 + splitAxis + 3 ]; // max bounding data - - if ( isOutside ) { - - return c1Result; - - } - - } - - // either there was no intersection in the first node, or there could still be a closer - // intersection in the second, so check the second node and then take the better of the two - const c2Intersection = intersectRay( c2, float32Array, ray, boxIntersection ); - const c2Result = c2Intersection ? raycastFirst( c2, geometry, side, ray ) : null; - - if ( c1Result && c2Result ) { - - return c1Result.distance <= c2Result.distance ? c1Result : c2Result; - - } else { - - return c1Result || c2Result || null; - - } - - } - -} - -const shapecast = ( function () { - - let _box1, _box2; - const boxStack = []; - const boxPool = new PrimitivePool( () => new Box3() ); - - return function shapecast( ...args ) { - - _box1 = boxPool.getPrimitive(); - _box2 = boxPool.getPrimitive(); - boxStack.push( _box1, _box2 ); - - const result = shapecastTraverse( ...args ); - - boxPool.releasePrimitive( _box1 ); - boxPool.releasePrimitive( _box2 ); - boxStack.pop(); - boxStack.pop(); - - const length = boxStack.length; - if ( length > 0 ) { - - _box2 = boxStack[ length - 1 ]; - _box1 = boxStack[ length - 2 ]; - - } - - return result; - - }; - - function shapecastTraverse( - nodeIndex32, - geometry, - intersectsBoundsFunc, - intersectsRangeFunc, - nodeScoreFunc = null, - nodeIndexByteOffset = 0, // offset for unique node identifier - depth = 0 - ) { - - // Define these inside the function so it has access to the local variables needed - // when converting to the buffer equivalents - function getLeftOffset( nodeIndex32 ) { - - let nodeIndex16 = nodeIndex32 * 2, uint16Array = _uint16Array, uint32Array = _uint32Array; - - // traverse until we find a leaf - while ( ! IS_LEAF( nodeIndex16, uint16Array ) ) { - - nodeIndex32 = LEFT_NODE( nodeIndex32 ); - nodeIndex16 = nodeIndex32 * 2; - - } - - return OFFSET( nodeIndex32, uint32Array ); - - } - - function getRightEndOffset( nodeIndex32 ) { - - let nodeIndex16 = nodeIndex32 * 2, uint16Array = _uint16Array, uint32Array = _uint32Array; - - // traverse until we find a leaf - while ( ! IS_LEAF( nodeIndex16, uint16Array ) ) { - - // adjust offset to point to the right node - nodeIndex32 = RIGHT_NODE( nodeIndex32, uint32Array ); - nodeIndex16 = nodeIndex32 * 2; - - } - - // return the end offset of the triangle range - return OFFSET( nodeIndex32, uint32Array ) + COUNT( nodeIndex16, uint16Array ); - - } - - 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, _box1 ); - return intersectsRangeFunc( offset, count, false, depth, nodeIndexByteOffset + nodeIndex32, _box1 ); - - } 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 = _box1; - box2 = _box2; - - // bounding data is not offset - 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 temp = score1; - score1 = score2; - score2 = temp; - - box1 = box2; - // box2 is always set before use below - - } - - } - - // Check box 1 intersection - if ( ! box1 ) { - - box1 = _box1; - 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; - - // Check box 2 intersection - // cached box2 will have been overwritten by previous traversal - box2 = _box2; - 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; - - } - - } - -} )(); - -const intersectsGeometry = ( function () { - - const triangle = new SeparatingAxisTriangle(); - const triangle2 = new SeparatingAxisTriangle(); - const invertedMat = new Matrix4(); - - const obb = new OrientedBox(); - const obb2 = new OrientedBox(); - - return function intersectsGeometry( nodeIndex32, geometry, otherGeometry, geometryToBvh, cachedObb = null ) { - - let nodeIndex16 = nodeIndex32 * 2, float32Array = _float32Array, uint16Array = _uint16Array, uint32Array = _uint32Array; - - if ( cachedObb === null ) { - - if ( ! otherGeometry.boundingBox ) { - - otherGeometry.computeBoundingBox(); - - } - - obb.set( otherGeometry.boundingBox.min, otherGeometry.boundingBox.max, geometryToBvh ); - cachedObb = obb; - - } - - 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 ); - - // get the inverse of the geometry matrix so we can transform our triangles into the - // geometry space we're trying to test. We assume there are fewer triangles being checked - // here. - invertedMat.copy( geometryToBvh ).invert(); - - if ( otherGeometry.boundsTree ) { - - arrayToBox( BOUNDING_DATA_INDEX( nodeIndex32 ), float32Array, obb2 ); - obb2.matrix.copy( invertedMat ); - obb2.needsUpdate = true; - - const res = otherGeometry.boundsTree.shapecast( { - - intersectsBounds: box => obb2.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 ) { - - // this triangle needs to be transformed into the current BVH coordinate frame - 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 ) { - - // this triangle needs to be transformed into the current BVH coordinate frame - 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$1 ); - const leftIntersection = - cachedObb.intersectsBox( boundingBox$1 ) && - intersectsGeometry( left, geometry, otherGeometry, geometryToBvh, cachedObb ); - - if ( leftIntersection ) return true; - - arrayToBox( BOUNDING_DATA_INDEX( right ), float32Array, boundingBox$1 ); - const rightIntersection = - cachedObb.intersectsBox( boundingBox$1 ) && - intersectsGeometry( right, geometry, otherGeometry, geometryToBvh, cachedObb ); - - if ( rightIntersection ) return true; - - return false; - - } - - }; - -} )(); - -function intersectRay( nodeIndex32, array, ray, target ) { - - arrayToBox( nodeIndex32, array, boundingBox$1 ); - return ray.intersectBox( boundingBox$1, target ); - -} - -const bufferStack = []; -let _prevBuffer; -let _float32Array; -let _uint16Array; -let _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() ); - - } - -} - -const SKIP_GENERATION = Symbol( 'skip tree generation' ); - -const aabb = /* @__PURE__ */ new Box3(); -const aabb2 = /* @__PURE__ */ new Box3(); -const tempMatrix = /* @__PURE__ */ new Matrix4(); -const obb = /* @__PURE__ */ new OrientedBox(); -const obb2 = /* @__PURE__ */ new OrientedBox(); -const temp = /* @__PURE__ */ new Vector3(); -const temp1 = /* @__PURE__ */ new Vector3(); -const temp2 = /* @__PURE__ */ new Vector3(); -const temp3 = /* @__PURE__ */ new Vector3(); -const temp4 = /* @__PURE__ */ new Vector3(); -const tempBox = /* @__PURE__ */ new Box3(); -const trianglePool = /* @__PURE__ */ new PrimitivePool( () => new SeparatingAxisTriangle() ); - -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 ] === undefined ? 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 ] === undefined ? 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.' ); - - } - - // default options - 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() ); - - } - - } - - // retain references to the geometry so we can use them it without having to - // take a geometry reference in every function. - 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; - const posArr = posAttr.array; - - // support for an interleaved position buffer - const bufferOffset = posAttr.offset || 0; - let stride = 3; - if ( posAttr.isInterleavedBufferAttribute ) { - - stride = posAttr.data.stride; - - } - - 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, byteOffset, 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 ] * stride + bufferOffset; - const x = posArr[ index + 0 ]; - const y = posArr[ index + 1 ]; - const z = posArr[ index + 2 ]; - - 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 ]; - - // the identifying node indices provided by the shapecast function include offsets of all - // root buffers to guarantee they're unique between roots so offset left and right indices here. - const offsetLeft = left + byteOffset; - const offsetRight = right + byteOffset; - let forceChildren = force; - let includesLeft = false; - let includesRight = false; - - if ( nodeIndices ) { - - // if we see that neither the left or right child are included in the set that need to be updated - // then we assume that all children need to be updated. - 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, byteOffset, forceChildren ); - - } - - let rightChange = false; - if ( traverseRight ) { - - rightChange = _traverse( right, byteOffset, 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 { - - // TODO: use node functions here - 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( ray, 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, ray, 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( ray, 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, ray ); - 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 ) { - - // Support the previous function signature that provided three sequential index buffer - // indices here. - 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 ) { - - // BVHCast function for intersecting two BVHs against each other. Ultimately just uses two recursive shapecast calls rather - // than an approach that walks down the tree (see bvhcast.js file for more info). - - 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 ) { - - function iterateOverDoubleTriangles( 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; - - } - - } - - this.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: box => aabb.intersectsBox( box ), - - intersectsRange: ( offset2, count2, contained, 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: box => obb.intersectsBox( box ), - 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, Math.min( closestDistance, maxThreshold ) ); - - }, - - intersectsBounds: ( box, isLeaf, score ) => { - - if ( score < closestDistance && score < maxThreshold ) { - - // if we know the triangles of this bounds will be intersected next then - // save the bounds to use during triangle checks. - 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 ) { - - // if the other geometry has a bvh then use the accelerated path where we use shapecast to find - // the closest bounds in the other geometry to check. - return otherGeometry.boundsTree.shapecast( { - boundsTraverseOrder: box => { - - return obb2.distanceToBox( box, Math.min( closestDistance, maxThreshold ) ); - - }, - - 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; - - } - - // stop traversal if we find a point that's under the given threshold - if ( dist < minThreshold ) { - - return true; - - } - - } - - } - - }, - } ); - - } else { - - // If no bounds tree then we'll just check every triangle. - 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; - - } - - // stop traversal if we find a point that's under the given threshold - 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 ) { - - // early out if under minThreshold - // skip checking if over maxThreshold - // set minThreshold = maxThreshold to quickly check if a point is within a threshold - // returns Infinity if no value found - 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; - - } - -} - -// Deprecation -const originalRaycast = MeshBVH.prototype.raycast; -MeshBVH.prototype.raycast = function ( ...args ) { - - if ( args[ 0 ].isMesh ) { - - console.warn( 'MeshBVH: The function signature and results frame for "raycast" has changed. See docs for new signature.' ); - const [ - mesh, raycaster, ray, intersects, - ] = args; - - const results = originalRaycast.call( this, ray, mesh.material ); - results.forEach( hit => { - - hit = convertRaycastIntersect( hit, mesh, raycaster ); - if ( hit ) { - - intersects.push( hit ); - - } - - } ); - - return intersects; - - } else { - - return originalRaycast.apply( this, args ); - - } - -}; - -const originalRaycastFirst = MeshBVH.prototype.raycastFirst; -MeshBVH.prototype.raycastFirst = function ( ...args ) { - - if ( args[ 0 ].isMesh ) { - - console.warn( 'MeshBVH: The function signature and results frame for "raycastFirst" has changed. See docs for new signature.' ); - const [ - mesh, raycaster, ray, - ] = args; - - return convertRaycastIntersect( originalRaycastFirst.call( this, ray, mesh.material ), mesh, raycaster ); - - } else { - - return originalRaycastFirst.apply( this, args ); - - } - -}; - -const originalClosestPointToPoint = MeshBVH.prototype.closestPointToPoint; -MeshBVH.prototype.closestPointToPoint = function ( ...args ) { - - - if ( args[ 0 ].isMesh ) { - - console.warn( 'MeshBVH: The function signature and results frame for "closestPointToPoint" has changed. See docs for new signature.' ); - - args.unshift(); - - const target = args[ 1 ]; - const result = {}; - args[ 1 ] = result; - - originalClosestPointToPoint.apply( this, args ); - - if ( target ) { - - target.copy( result.point ); - - } - - return result.distance; - - } else { - - return originalClosestPointToPoint.apply( this, args ); - - } - -}; - -const originalClosestPointToGeometry = MeshBVH.prototype.closestPointToGeometry; -MeshBVH.prototype.closestPointToGeometry = function ( ...args ) { - - const target1 = args[ 2 ]; - const target2 = args[ 3 ]; - if ( target1 && target1.isVector3 || target2 && target2.isVector3 ) { - - console.warn( 'MeshBVH: The function signature and results frame for "closestPointToGeometry" has changed. See docs for new signature.' ); - - const result1 = {}; - const result2 = {}; - const geometryToBvh = args[ 1 ]; - args[ 2 ] = result1; - args[ 3 ] = result2; - - originalClosestPointToGeometry.apply( this, args ); - - if ( target1 ) { - - target1.copy( result1.point ); - - } - - if ( target2 ) { - - target2.copy( result2.point ).applyMatrix4( geometryToBvh ); - - } - - return result1.distance; - - } else { - - return originalClosestPointToGeometry.apply( this, args ); - - } - -}; - -const originalRefit = MeshBVH.prototype.refit; -MeshBVH.prototype.refit = function ( ...args ) { - - const nodeIndices = args[ 0 ]; - const terminationIndices = args[ 1 ]; - if ( terminationIndices && ( terminationIndices instanceof Set || Array.isArray( terminationIndices ) ) ) { - - console.warn( 'MeshBVH: The function signature for "refit" has changed. See docs for new signature.' ); - - const newNodeIndices = new Set(); - terminationIndices.forEach( v => newNodeIndices.add( v ) ); - if ( nodeIndices ) { - - nodeIndices.forEach( v => newNodeIndices.add( v ) ); - - } - - originalRefit.call( this, newNodeIndices ); - - } else { - - originalRefit.apply( this, args ); - - } - -}; - -[ - 'intersectsGeometry', - 'shapecast', - 'intersectsBox', - 'intersectsSphere', -].forEach( name => { - - const originalFunc = MeshBVH.prototype[ name ]; - MeshBVH.prototype[ name ] = function ( ...args ) { - - if ( args[ 0 ] === null || args[ 0 ].isMesh ) { - - args.shift(); - console.warn( `MeshBVH: The function signature for "${ name }" has changed and no longer takes Mesh. See docs for new signature.` ); - - } - - return originalFunc.apply( this, args ); - - }; - -} ); - -const boundingBox = /* @__PURE__ */ new Box3(); -class MeshBVHRootVisualizer 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 ) { - - // count the number of bounds required - 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 ); - - // fill in the position buffer with the bounds corners - 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, boundingBox ); - - const { min, max } = boundingBox; - 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 ) { - - // fill in the index buffer to point to the corner points - 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 ]; - - } - - } - - // update the geometry - geometry.setIndex( - new BufferAttribute( indexArray, 1, false ), - ); - geometry.setAttribute( - 'position', - new BufferAttribute( positionArray, 3, false ), - ); - this.visible = true; - - } - - } - -} - -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: 0x00FF88, - transparent: true, - opacity: 0.3, - depthWrite: false, - } ); - - const meshMaterial = new MeshBasicMaterial( { - color: 0x00FF88, - 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 ) { - - this._roots.pop(); - - } - - for ( let i = 0; i < totalRoots; i ++ ) { - - if ( i >= this._roots.length ) { - - const root = new MeshBVHRootVisualizer( this.mesh, this.edgeMaterial, this.depth, i ); - this.add( root ); - this._roots.push( root ); - - } - - 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(); - - } - - } - -} - -const _box1 = /* @__PURE__ */ new Box3(); -const _box2 = /* @__PURE__ */ new Box3(); -const _vec = /* @__PURE__ */ new Vector3(); - -// https://stackoverflow.com/questions/1248302/how-to-get-the-size-of-a-javascript-object -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 there are no leaf nodes because the tree hasn't finished generating yet. - 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 = 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 ) { - - // check triangles - 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 ) { - - // check if my bounds fit in my parents - arrayToBox( 0, boundingData, _box2 ); - - const isContained = _box2.containsBox( _box1 ); - console.assert( isContained, 'Parent bounds does not fully contain child.' ); - passes = passes && isContained; - - } - - } ); - - return passes; - -} - -// Returns a simple, human readable object that represents the BVH. -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; - - // traversal hits the left then right node - const parent = depthStack[ depth - 1 ]; - if ( parent ) { - - if ( parent.left === null ) { - - parent.left = info; - - } else { - - parent.right = info; - - } - - } - - } ); - - return depthStack[ 0 ]; - -} - -const ray = /* @__PURE__ */ new Ray(); -const tmpInverseMatrix = /* @__PURE__ */ new Matrix4(); -const origMeshRaycastFunc = Mesh.prototype.raycast; - -function acceleratedRaycast( raycaster, intersects ) { - - if ( this.geometry.boundsTree ) { - - if ( this.material === undefined ) 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; - -} - -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; - - } - -} - -class VertexAttributeTexture 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.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; - - // derive the type of texture this should be in the shader - 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; - - } - - } - - // get the target format to store the texture as - let type, format, normalizeValue, targetBufferCons; - let internalFormat = countToStringFormat( itemSize ); - switch ( targetType ) { - - case FloatType: - normalizeValue = 1.0; - 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.0; - 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.0; - format = countToIntFormat( itemSize ); - - if ( byteCount === 1 ) { - - targetBufferCons = Uint8Array; - type = UnsignedByteType; - - } else if ( byteCount === 2 ) { - - targetBufferCons = Uint16Array; - type = UnsignedShortType; - - } else { - - targetBufferCons = Uint32Array; - type = UnsignedIntType; - - } - - break; - - } - - // there will be a mismatch between format length and final length because - // RGBFormat and RGBIntegerFormat was removed - if ( finalStride === 3 && ( format === RGBAFormat || format === RGBAIntegerFormat ) ) { - - finalStride = 4; - - } - - // copy the data over to the new texture array - const dimension = Math.ceil( Math.sqrt( count ) ); - const length = finalStride * dimension * dimension; - const dataArray = new targetBufferCons( length ); - 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.0; - - } - - } - - if ( itemSize >= 4 ) { - - dataArray[ ii + 3 ] = attr.getW( i ) / normalizeValue; - - } - - } - - this.internalFormat = internalFormat; - this.format = format; - this.type = type; - this.image.width = dimension; - this.image.height = dimension; - this.image.data = dataArray; - this.needsUpdate = true; - - attr.itemSize = originalItemSize; - attr.count = originalCount; - - } - -} - -class UIntVertexAttributeTexture extends VertexAttributeTexture { - - constructor() { - - super(); - this._forcedType = UnsignedIntType; - - } - -} - -class IntVertexAttributeTexture extends VertexAttributeTexture { - - constructor() { - - super(); - this._forcedType = IntType; - - } - - -} - -class FloatVertexAttributeTexture extends VertexAttributeTexture { - - constructor() { - - super(); - this._forcedType = FloatType; - - } - -} - -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 ); - - // Both bounds need two elements per node so compute the height so it's twice as long as - // the width so we can expand the row by two and still have a square texture - 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 = 0xffff0000 | 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; - - 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; - -} - -class MeshBVHUniformStruct { - - 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(); - - } - -} - -const 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. -`; - -const 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; - -} - -`; - -export { AVERAGE, CENTER, CONTAINED, FloatVertexAttributeTexture, INTERSECTED, IntVertexAttributeTexture, MeshBVH, MeshBVHUniformStruct, MeshBVHVisualizer, NOT_INTERSECTED, SAH, UIntVertexAttributeTexture, VertexAttributeTexture, acceleratedRaycast, computeBoundsTree, disposeBoundsTree, estimateMemoryInBytes, getBVHExtremes, getJSONStructure, getTriangleHitPointInfo, shaderIntersectFunction, shaderStructs, validateBounds }; -//# sourceMappingURL=./three-mesh-bvh.module.js.map \ No newline at end of file diff --git a/test/three-mesh-bvh.module.js.map b/test/three-mesh-bvh.module.js.map deleted file mode 100644 index 6c23867..0000000 --- a/test/three-mesh-bvh.module.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.module.js","sources":["../src/core/Constants.js","../src/core/MeshBVHNode.js","../src/utils/ArrayBoxUtilities.js","../src/core/buildFunctions.js","../src/math/SeparatingAxisBounds.js","../src/math/MathUtilities.js","../src/math/SeparatingAxisTriangle.js","../src/math/OrientedBox.js","../src/utils/ThreeRayIntersectUtilities.js","../src/utils/GeometryRayIntersectUtilities.js","../src/utils/TriangleUtilities.js","../src/utils/PrimitivePool.js","../src/core/nodeBufferFunctions.js","../src/core/castFunctions.js","../src/core/MeshBVH.js","../src/objects/MeshBVHVisualizer.js","../src/debug/Debug.js","../src/utils/ExtensionUtilities.js","../src/gpu/VertexAttributeTexture.js","../src/gpu/MeshBVHUniformStruct.js","../src/gpu/shaderFunctions.js"],"sourcesContent":["// Split strategy constants\r\nexport const CENTER = 0;\r\nexport const AVERAGE = 1;\r\nexport const SAH = 2;\r\n\r\n// Traversal constants\r\nexport const NOT_INTERSECTED = 0;\r\nexport const INTERSECTED = 1;\r\nexport const CONTAINED = 2;\r\n\r\n// SAH cost constants\r\n// TODO: hone these costs more. The relative difference between them should be the\r\n// difference in measured time to perform a triangle intersection vs traversing\r\n// bounds.\r\nexport const TRIANGLE_INTERSECT_COST = 1.25;\r\nexport const TRAVERSAL_COST = 1;\r\n\r\n\r\n// Build constants\r\nexport const BYTES_PER_NODE = 6 * 4 + 4 + 4;\r\nexport const IS_LEAFNODE_FLAG = 0xFFFF;\r\n\r\n// EPSILON for computing floating point error during build\r\n// https://en.wikipedia.org/wiki/Machine_epsilon#Values_for_standard_hardware_floating_point_arithmetics\r\nexport const FLOAT32_EPSILON = Math.pow( 2, - 24 );\r\n\r\n","export class MeshBVHNode {\r\n\r\n\tconstructor() {\r\n\r\n\t\t// internal nodes have boundingData, left, right, and splitAxis\r\n\t\t// leaf nodes have offset and count (referring to primitives in the mesh geometry)\r\n\r\n\t}\r\n\r\n}\r\n","export function arrayToBox( nodeIndex32, array, target ) {\r\n\r\n\ttarget.min.x = array[ nodeIndex32 ];\r\n\ttarget.min.y = array[ nodeIndex32 + 1 ];\r\n\ttarget.min.z = array[ nodeIndex32 + 2 ];\r\n\r\n\ttarget.max.x = array[ nodeIndex32 + 3 ];\r\n\ttarget.max.y = array[ nodeIndex32 + 4 ];\r\n\ttarget.max.z = array[ nodeIndex32 + 5 ];\r\n\r\n\treturn target;\r\n\r\n}\r\n\r\nexport function getLongestEdgeIndex( bounds ) {\r\n\r\n\tlet splitDimIdx = - 1;\r\n\tlet splitDist = - Infinity;\r\n\r\n\tfor ( let i = 0; i < 3; i ++ ) {\r\n\r\n\t\tconst dist = bounds[ i + 3 ] - bounds[ i ];\r\n\t\tif ( dist > splitDist ) {\r\n\r\n\t\t\tsplitDist = dist;\r\n\t\t\tsplitDimIdx = i;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\treturn splitDimIdx;\r\n\r\n}\r\n\r\n// copys bounds a into bounds b\r\nexport function copyBounds( source, target ) {\r\n\r\n\ttarget.set( source );\r\n\r\n}\r\n\r\n// sets bounds target to the union of bounds a and b\r\nexport function unionBounds( a, b, target ) {\r\n\r\n\tlet aVal, bVal;\r\n\tfor ( let d = 0; d < 3; d ++ ) {\r\n\r\n\t\tconst d3 = d + 3;\r\n\r\n\t\t// set the minimum values\r\n\t\taVal = a[ d ];\r\n\t\tbVal = b[ d ];\r\n\t\ttarget[ d ] = aVal < bVal ? aVal : bVal;\r\n\r\n\t\t// set the max values\r\n\t\taVal = a[ d3 ];\r\n\t\tbVal = b[ d3 ];\r\n\t\ttarget[ d3 ] = aVal > bVal ? aVal : bVal;\r\n\r\n\t}\r\n\r\n}\r\n\r\n// expands the given bounds by the provided triangle bounds\r\nexport function expandByTriangleBounds( startIndex, triangleBounds, bounds ) {\r\n\r\n\tfor ( let d = 0; d < 3; d ++ ) {\r\n\r\n\t\tconst tCenter = triangleBounds[ startIndex + 2 * d ];\r\n\t\tconst tHalf = triangleBounds[ startIndex + 2 * d + 1 ];\r\n\r\n\t\tconst tMin = tCenter - tHalf;\r\n\t\tconst tMax = tCenter + tHalf;\r\n\r\n\t\tif ( tMin < bounds[ d ] ) {\r\n\r\n\t\t\tbounds[ d ] = tMin;\r\n\r\n\t\t}\r\n\r\n\t\tif ( tMax > bounds[ d + 3 ] ) {\r\n\r\n\t\t\tbounds[ d + 3 ] = tMax;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n}\r\n\r\n// compute bounds surface area\r\nexport function computeSurfaceArea( bounds ) {\r\n\r\n\tconst d0 = bounds[ 3 ] - bounds[ 0 ];\r\n\tconst d1 = bounds[ 4 ] - bounds[ 1 ];\r\n\tconst d2 = bounds[ 5 ] - bounds[ 2 ];\r\n\r\n\treturn 2 * ( d0 * d1 + d1 * d2 + d2 * d0 );\r\n\r\n}\r\n","import { BufferAttribute } from 'three';\r\nimport { MeshBVHNode } from './MeshBVHNode.js';\r\nimport { getLongestEdgeIndex, computeSurfaceArea, copyBounds, unionBounds, expandByTriangleBounds } from '../utils/ArrayBoxUtilities.js';\r\nimport {\r\n\tCENTER, AVERAGE, SAH, TRIANGLE_INTERSECT_COST, TRAVERSAL_COST,\r\n\tBYTES_PER_NODE, FLOAT32_EPSILON, IS_LEAFNODE_FLAG,\r\n} from './Constants.js';\r\n\r\nfunction ensureIndex( geo, options ) {\r\n\r\n\tif ( ! geo.index ) {\r\n\r\n\t\tconst vertexCount = geo.attributes.position.count;\r\n\t\tconst BufferConstructor = options.useSharedArrayBuffer ? SharedArrayBuffer : ArrayBuffer;\r\n\t\tlet index;\r\n\t\tif ( vertexCount > 65535 ) {\r\n\r\n\t\t\tindex = new Uint32Array( new BufferConstructor( 4 * vertexCount ) );\r\n\r\n\t\t} else {\r\n\r\n\t\t\tindex = new Uint16Array( new BufferConstructor( 2 * vertexCount ) );\r\n\r\n\t\t}\r\n\r\n\t\tgeo.setIndex( new BufferAttribute( index, 1 ) );\r\n\r\n\t\tfor ( let i = 0; i < vertexCount; i ++ ) {\r\n\r\n\t\t\tindex[ i ] = i;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n}\r\n\r\n// Computes the set of { offset, count } ranges which need independent BVH roots. Each\r\n// region in the geometry index that belongs to a different set of material groups requires\r\n// a separate BVH root, so that triangles indices belonging to one group never get swapped\r\n// with triangle indices belongs to another group. For example, if the groups were like this:\r\n//\r\n// [-------------------------------------------------------------]\r\n// |__________________|\r\n// g0 = [0, 20] |______________________||_____________________|\r\n// g1 = [16, 40] g2 = [41, 60]\r\n//\r\n// we would need four BVH roots: [0, 15], [16, 20], [21, 40], [41, 60].\r\nfunction getRootIndexRanges( geo ) {\r\n\r\n\tif ( ! geo.groups || ! geo.groups.length ) {\r\n\r\n\t\treturn [ { offset: 0, count: geo.index.count / 3 } ];\r\n\r\n\t}\r\n\r\n\tconst ranges = [];\r\n\tconst rangeBoundaries = new Set();\r\n\tfor ( const group of geo.groups ) {\r\n\r\n\t\trangeBoundaries.add( group.start );\r\n\t\trangeBoundaries.add( group.start + group.count );\r\n\r\n\t}\r\n\r\n\t// note that if you don't pass in a comparator, it sorts them lexicographically as strings :-(\r\n\tconst sortedBoundaries = Array.from( rangeBoundaries.values() ).sort( ( a, b ) => a - b );\r\n\tfor ( let i = 0; i < sortedBoundaries.length - 1; i ++ ) {\r\n\r\n\t\tconst start = sortedBoundaries[ i ], end = sortedBoundaries[ i + 1 ];\r\n\t\tranges.push( { offset: ( start / 3 ), count: ( end - start ) / 3 } );\r\n\r\n\t}\r\n\r\n\treturn ranges;\r\n\r\n}\r\n\r\n// computes the union of the bounds of all of the given triangles and puts the resulting box in target. If\r\n// centroidTarget is provided then a bounding box is computed for the centroids of the triangles, as well.\r\n// These are computed together to avoid redundant accesses to bounds array.\r\nfunction getBounds( triangleBounds, offset, count, target, centroidTarget = null ) {\r\n\r\n\tlet minx = Infinity;\r\n\tlet miny = Infinity;\r\n\tlet minz = Infinity;\r\n\tlet maxx = - Infinity;\r\n\tlet maxy = - Infinity;\r\n\tlet maxz = - Infinity;\r\n\r\n\tlet cminx = Infinity;\r\n\tlet cminy = Infinity;\r\n\tlet cminz = Infinity;\r\n\tlet cmaxx = - Infinity;\r\n\tlet cmaxy = - Infinity;\r\n\tlet cmaxz = - Infinity;\r\n\r\n\tconst includeCentroid = centroidTarget !== null;\r\n\tfor ( let i = offset * 6, end = ( offset + count ) * 6; i < end; i += 6 ) {\r\n\r\n\t\tconst cx = triangleBounds[ i + 0 ];\r\n\t\tconst hx = triangleBounds[ i + 1 ];\r\n\t\tconst lx = cx - hx;\r\n\t\tconst rx = cx + hx;\r\n\t\tif ( lx < minx ) minx = lx;\r\n\t\tif ( rx > maxx ) maxx = rx;\r\n\t\tif ( includeCentroid && cx < cminx ) cminx = cx;\r\n\t\tif ( includeCentroid && cx > cmaxx ) cmaxx = cx;\r\n\r\n\t\tconst cy = triangleBounds[ i + 2 ];\r\n\t\tconst hy = triangleBounds[ i + 3 ];\r\n\t\tconst ly = cy - hy;\r\n\t\tconst ry = cy + hy;\r\n\t\tif ( ly < miny ) miny = ly;\r\n\t\tif ( ry > maxy ) maxy = ry;\r\n\t\tif ( includeCentroid && cy < cminy ) cminy = cy;\r\n\t\tif ( includeCentroid && cy > cmaxy ) cmaxy = cy;\r\n\r\n\t\tconst cz = triangleBounds[ i + 4 ];\r\n\t\tconst hz = triangleBounds[ i + 5 ];\r\n\t\tconst lz = cz - hz;\r\n\t\tconst rz = cz + hz;\r\n\t\tif ( lz < minz ) minz = lz;\r\n\t\tif ( rz > maxz ) maxz = rz;\r\n\t\tif ( includeCentroid && cz < cminz ) cminz = cz;\r\n\t\tif ( includeCentroid && cz > cmaxz ) cmaxz = cz;\r\n\r\n\t}\r\n\r\n\ttarget[ 0 ] = minx;\r\n\ttarget[ 1 ] = miny;\r\n\ttarget[ 2 ] = minz;\r\n\r\n\ttarget[ 3 ] = maxx;\r\n\ttarget[ 4 ] = maxy;\r\n\ttarget[ 5 ] = maxz;\r\n\r\n\tif ( includeCentroid ) {\r\n\r\n\t\tcentroidTarget[ 0 ] = cminx;\r\n\t\tcentroidTarget[ 1 ] = cminy;\r\n\t\tcentroidTarget[ 2 ] = cminz;\r\n\r\n\t\tcentroidTarget[ 3 ] = cmaxx;\r\n\t\tcentroidTarget[ 4 ] = cmaxy;\r\n\t\tcentroidTarget[ 5 ] = cmaxz;\r\n\r\n\t}\r\n\r\n}\r\n\r\n// A stand alone function for retrieving the centroid bounds.\r\nfunction getCentroidBounds( triangleBounds, offset, count, centroidTarget ) {\r\n\r\n\tlet cminx = Infinity;\r\n\tlet cminy = Infinity;\r\n\tlet cminz = Infinity;\r\n\tlet cmaxx = - Infinity;\r\n\tlet cmaxy = - Infinity;\r\n\tlet cmaxz = - Infinity;\r\n\r\n\tfor ( let i = offset * 6, end = ( offset + count ) * 6; i < end; i += 6 ) {\r\n\r\n\t\tconst cx = triangleBounds[ i + 0 ];\r\n\t\tif ( cx < cminx ) cminx = cx;\r\n\t\tif ( cx > cmaxx ) cmaxx = cx;\r\n\r\n\t\tconst cy = triangleBounds[ i + 2 ];\r\n\t\tif ( cy < cminy ) cminy = cy;\r\n\t\tif ( cy > cmaxy ) cmaxy = cy;\r\n\r\n\t\tconst cz = triangleBounds[ i + 4 ];\r\n\t\tif ( cz < cminz ) cminz = cz;\r\n\t\tif ( cz > cmaxz ) cmaxz = cz;\r\n\r\n\t}\r\n\r\n\tcentroidTarget[ 0 ] = cminx;\r\n\tcentroidTarget[ 1 ] = cminy;\r\n\tcentroidTarget[ 2 ] = cminz;\r\n\r\n\tcentroidTarget[ 3 ] = cmaxx;\r\n\tcentroidTarget[ 4 ] = cmaxy;\r\n\tcentroidTarget[ 5 ] = cmaxz;\r\n\r\n}\r\n\r\n\r\n// reorders `tris` such that for `count` elements after `offset`, elements on the left side of the split\r\n// will be on the left and elements on the right side of the split will be on the right. returns the index\r\n// of the first element on the right side, or offset + count if there are no elements on the right side.\r\nfunction partition( index, triangleBounds, offset, count, split ) {\r\n\r\n\tlet left = offset;\r\n\tlet right = offset + count - 1;\r\n\tconst pos = split.pos;\r\n\tconst axisOffset = split.axis * 2;\r\n\r\n\t// hoare partitioning, see e.g. https://en.wikipedia.org/wiki/Quicksort#Hoare_partition_scheme\r\n\twhile ( true ) {\r\n\r\n\t\twhile ( left <= right && triangleBounds[ left * 6 + axisOffset ] < pos ) {\r\n\r\n\t\t\tleft ++;\r\n\r\n\t\t}\r\n\r\n\r\n\t\t// if a triangle center lies on the partition plane it is considered to be on the right side\r\n\t\twhile ( left <= right && triangleBounds[ right * 6 + axisOffset ] >= pos ) {\r\n\r\n\t\t\tright --;\r\n\r\n\t\t}\r\n\r\n\t\tif ( left < right ) {\r\n\r\n\t\t\t// we need to swap all of the information associated with the triangles at index\r\n\t\t\t// left and right; that's the verts in the geometry index, the bounds,\r\n\t\t\t// and perhaps the SAH planes\r\n\r\n\t\t\tfor ( let i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\t\tlet t0 = index[ left * 3 + i ];\r\n\t\t\t\tindex[ left * 3 + i ] = index[ right * 3 + i ];\r\n\t\t\t\tindex[ right * 3 + i ] = t0;\r\n\r\n\t\t\t\tlet t1 = triangleBounds[ left * 6 + i * 2 + 0 ];\r\n\t\t\t\ttriangleBounds[ left * 6 + i * 2 + 0 ] = triangleBounds[ right * 6 + i * 2 + 0 ];\r\n\t\t\t\ttriangleBounds[ right * 6 + i * 2 + 0 ] = t1;\r\n\r\n\t\t\t\tlet t2 = triangleBounds[ left * 6 + i * 2 + 1 ];\r\n\t\t\t\ttriangleBounds[ left * 6 + i * 2 + 1 ] = triangleBounds[ right * 6 + i * 2 + 1 ];\r\n\t\t\t\ttriangleBounds[ right * 6 + i * 2 + 1 ] = t2;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tleft ++;\r\n\t\t\tright --;\r\n\r\n\t\t} else {\r\n\r\n\t\t\treturn left;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n}\r\n\r\nconst BIN_COUNT = 32;\r\nconst binsSort = ( a, b ) => a.candidate - b.candidate;\r\nconst sahBins = new Array( BIN_COUNT ).fill().map( () => {\r\n\r\n\treturn {\r\n\r\n\t\tcount: 0,\r\n\t\tbounds: new Float32Array( 6 ),\r\n\t\trightCacheBounds: new Float32Array( 6 ),\r\n\t\tleftCacheBounds: new Float32Array( 6 ),\r\n\t\tcandidate: 0,\r\n\r\n\t};\r\n\r\n} );\r\nconst leftBounds = new Float32Array( 6 );\r\n\r\nfunction getOptimalSplit( nodeBoundingData, centroidBoundingData, triangleBounds, offset, count, strategy ) {\r\n\r\n\tlet axis = - 1;\r\n\tlet pos = 0;\r\n\r\n\t// Center\r\n\tif ( strategy === CENTER ) {\r\n\r\n\t\taxis = getLongestEdgeIndex( centroidBoundingData );\r\n\t\tif ( axis !== - 1 ) {\r\n\r\n\t\t\tpos = ( centroidBoundingData[ axis ] + centroidBoundingData[ axis + 3 ] ) / 2;\r\n\r\n\t\t}\r\n\r\n\t} else if ( strategy === AVERAGE ) {\r\n\r\n\t\taxis = getLongestEdgeIndex( nodeBoundingData );\r\n\t\tif ( axis !== - 1 ) {\r\n\r\n\t\t\tpos = getAverage( triangleBounds, offset, count, axis );\r\n\r\n\t\t}\r\n\r\n\t} else if ( strategy === SAH ) {\r\n\r\n\t\tconst rootSurfaceArea = computeSurfaceArea( nodeBoundingData );\r\n\t\tlet bestCost = TRIANGLE_INTERSECT_COST * count;\r\n\r\n\t\t// iterate over all axes\r\n\t\tconst cStart = offset * 6;\r\n\t\tconst cEnd = ( offset + count ) * 6;\r\n\t\tfor ( let a = 0; a < 3; a ++ ) {\r\n\r\n\t\t\tconst axisLeft = centroidBoundingData[ a ];\r\n\t\t\tconst axisRight = centroidBoundingData[ a + 3 ];\r\n\t\t\tconst axisLength = axisRight - axisLeft;\r\n\t\t\tconst binWidth = axisLength / BIN_COUNT;\r\n\r\n\t\t\t// If we have fewer triangles than we're planning to split then just check all\r\n\t\t\t// the triangle positions because it will be faster.\r\n\t\t\tif ( count < BIN_COUNT / 4 ) {\r\n\r\n\t\t\t\t// initialize the bin candidates\r\n\t\t\t\tconst truncatedBins = [ ...sahBins ];\r\n\t\t\t\ttruncatedBins.length = count;\r\n\r\n\t\t\t\t// set the candidates\r\n\t\t\t\tlet b = 0;\r\n\t\t\t\tfor ( let c = cStart; c < cEnd; c += 6, b ++ ) {\r\n\r\n\t\t\t\t\tconst bin = truncatedBins[ b ];\r\n\t\t\t\t\tbin.candidate = triangleBounds[ c + 2 * a ];\r\n\t\t\t\t\tbin.count = 0;\r\n\r\n\t\t\t\t\tconst {\r\n\t\t\t\t\t\tbounds,\r\n\t\t\t\t\t\tleftCacheBounds,\r\n\t\t\t\t\t\trightCacheBounds,\r\n\t\t\t\t\t} = bin;\r\n\t\t\t\t\tfor ( let d = 0; d < 3; d ++ ) {\r\n\r\n\t\t\t\t\t\trightCacheBounds[ d ] = Infinity;\r\n\t\t\t\t\t\trightCacheBounds[ d + 3 ] = - Infinity;\r\n\r\n\t\t\t\t\t\tleftCacheBounds[ d ] = Infinity;\r\n\t\t\t\t\t\tleftCacheBounds[ d + 3 ] = - Infinity;\r\n\r\n\t\t\t\t\t\tbounds[ d ] = Infinity;\r\n\t\t\t\t\t\tbounds[ d + 3 ] = - Infinity;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\texpandByTriangleBounds( c, triangleBounds, bounds );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\ttruncatedBins.sort( binsSort );\r\n\r\n\t\t\t\t// remove redundant splits\r\n\t\t\t\tlet splitCount = count;\r\n\t\t\t\tfor ( let bi = 0; bi < splitCount; bi ++ ) {\r\n\r\n\t\t\t\t\tconst bin = truncatedBins[ bi ];\r\n\t\t\t\t\twhile ( bi + 1 < splitCount && truncatedBins[ bi + 1 ].candidate === bin.candidate ) {\r\n\r\n\t\t\t\t\t\ttruncatedBins.splice( bi + 1, 1 );\r\n\t\t\t\t\t\tsplitCount --;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// find the appropriate bin for each triangle and expand the bounds.\r\n\t\t\t\tfor ( let c = cStart; c < cEnd; c += 6 ) {\r\n\r\n\t\t\t\t\tconst center = triangleBounds[ c + 2 * a ];\r\n\t\t\t\t\tfor ( let bi = 0; bi < splitCount; bi ++ ) {\r\n\r\n\t\t\t\t\t\tconst bin = truncatedBins[ bi ];\r\n\t\t\t\t\t\tif ( center >= bin.candidate ) {\r\n\r\n\t\t\t\t\t\t\texpandByTriangleBounds( c, triangleBounds, bin.rightCacheBounds );\r\n\r\n\t\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\t\texpandByTriangleBounds( c, triangleBounds, bin.leftCacheBounds );\r\n\t\t\t\t\t\t\tbin.count ++;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// expand all the bounds\r\n\t\t\t\tfor ( let bi = 0; bi < splitCount; bi ++ ) {\r\n\r\n\t\t\t\t\tconst bin = truncatedBins[ bi ];\r\n\t\t\t\t\tconst leftCount = bin.count;\r\n\t\t\t\t\tconst rightCount = count - bin.count;\r\n\r\n\t\t\t\t\t// check the cost of this split\r\n\t\t\t\t\tconst leftBounds = bin.leftCacheBounds;\r\n\t\t\t\t\tconst rightBounds = bin.rightCacheBounds;\r\n\r\n\t\t\t\t\tlet leftProb = 0;\r\n\t\t\t\t\tif ( leftCount !== 0 ) {\r\n\r\n\t\t\t\t\t\tleftProb = computeSurfaceArea( leftBounds ) / rootSurfaceArea;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tlet rightProb = 0;\r\n\t\t\t\t\tif ( rightCount !== 0 ) {\r\n\r\n\t\t\t\t\t\trightProb = computeSurfaceArea( rightBounds ) / rootSurfaceArea;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tconst cost = TRAVERSAL_COST + TRIANGLE_INTERSECT_COST * (\r\n\t\t\t\t\t\tleftProb * leftCount + rightProb * rightCount\r\n\t\t\t\t\t);\r\n\r\n\t\t\t\t\tif ( cost < bestCost ) {\r\n\r\n\t\t\t\t\t\taxis = a;\r\n\t\t\t\t\t\tbestCost = cost;\r\n\t\t\t\t\t\tpos = bin.candidate;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\t// reset the bins\r\n\t\t\t\tfor ( let i = 0; i < BIN_COUNT; i ++ ) {\r\n\r\n\t\t\t\t\tconst bin = sahBins[ i ];\r\n\t\t\t\t\tbin.count = 0;\r\n\t\t\t\t\tbin.candidate = axisLeft + binWidth + i * binWidth;\r\n\r\n\t\t\t\t\tconst bounds = bin.bounds;\r\n\t\t\t\t\tfor ( let d = 0; d < 3; d ++ ) {\r\n\r\n\t\t\t\t\t\tbounds[ d ] = Infinity;\r\n\t\t\t\t\t\tbounds[ d + 3 ] = - Infinity;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// iterate over all center positions\r\n\t\t\t\tfor ( let c = cStart; c < cEnd; c += 6 ) {\r\n\r\n\t\t\t\t\tconst triCenter = triangleBounds[ c + 2 * a ];\r\n\t\t\t\t\tconst relativeCenter = triCenter - axisLeft;\r\n\r\n\t\t\t\t\t// in the partition function if the centroid lies on the split plane then it is\r\n\t\t\t\t\t// considered to be on the right side of the split\r\n\t\t\t\t\tlet binIndex = ~ ~ ( relativeCenter / binWidth );\r\n\t\t\t\t\tif ( binIndex >= BIN_COUNT ) binIndex = BIN_COUNT - 1;\r\n\r\n\t\t\t\t\tconst bin = sahBins[ binIndex ];\r\n\t\t\t\t\tbin.count ++;\r\n\r\n\t\t\t\t\texpandByTriangleBounds( c, triangleBounds, bin.bounds );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// cache the unioned bounds from right to left so we don't have to regenerate them each time\r\n\t\t\t\tconst lastBin = sahBins[ BIN_COUNT - 1 ];\r\n\t\t\t\tcopyBounds( lastBin.bounds, lastBin.rightCacheBounds );\r\n\t\t\t\tfor ( let i = BIN_COUNT - 2; i >= 0; i -- ) {\r\n\r\n\t\t\t\t\tconst bin = sahBins[ i ];\r\n\t\t\t\t\tconst nextBin = sahBins[ i + 1 ];\r\n\t\t\t\t\tunionBounds( bin.bounds, nextBin.rightCacheBounds, bin.rightCacheBounds );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tlet leftCount = 0;\r\n\t\t\t\tfor ( let i = 0; i < BIN_COUNT - 1; i ++ ) {\r\n\r\n\t\t\t\t\tconst bin = sahBins[ i ];\r\n\t\t\t\t\tconst binCount = bin.count;\r\n\t\t\t\t\tconst bounds = bin.bounds;\r\n\r\n\t\t\t\t\tconst nextBin = sahBins[ i + 1 ];\r\n\t\t\t\t\tconst rightBounds = nextBin.rightCacheBounds;\r\n\r\n\t\t\t\t\t// dont do anything with the bounds if the new bounds have no triangles\r\n\t\t\t\t\tif ( binCount !== 0 ) {\r\n\r\n\t\t\t\t\t\tif ( leftCount === 0 ) {\r\n\r\n\t\t\t\t\t\t\tcopyBounds( bounds, leftBounds );\r\n\r\n\t\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\t\tunionBounds( bounds, leftBounds, leftBounds );\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tleftCount += binCount;\r\n\r\n\t\t\t\t\t// check the cost of this split\r\n\t\t\t\t\tlet leftProb = 0;\r\n\t\t\t\t\tlet rightProb = 0;\r\n\r\n\t\t\t\t\tif ( leftCount !== 0 ) {\r\n\r\n\t\t\t\t\t\tleftProb = computeSurfaceArea( leftBounds ) / rootSurfaceArea;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tconst rightCount = count - leftCount;\r\n\t\t\t\t\tif ( rightCount !== 0 ) {\r\n\r\n\t\t\t\t\t\trightProb = computeSurfaceArea( rightBounds ) / rootSurfaceArea;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tconst cost = TRAVERSAL_COST + TRIANGLE_INTERSECT_COST * (\r\n\t\t\t\t\t\tleftProb * leftCount + rightProb * rightCount\r\n\t\t\t\t\t);\r\n\r\n\t\t\t\t\tif ( cost < bestCost ) {\r\n\r\n\t\t\t\t\t\taxis = a;\r\n\t\t\t\t\t\tbestCost = cost;\r\n\t\t\t\t\t\tpos = bin.candidate;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t} else {\r\n\r\n\t\tconsole.warn( `MeshBVH: Invalid build strategy value ${ strategy } used.` );\r\n\r\n\t}\r\n\r\n\treturn { axis, pos };\r\n\r\n}\r\n\r\n// returns the average coordinate on the specified axis of the all the provided triangles\r\nfunction getAverage( triangleBounds, offset, count, axis ) {\r\n\r\n\tlet avg = 0;\r\n\tfor ( let i = offset, end = offset + count; i < end; i ++ ) {\r\n\r\n\t\tavg += triangleBounds[ i * 6 + axis * 2 ];\r\n\r\n\t}\r\n\r\n\treturn avg / count;\r\n\r\n}\r\n\r\n// precomputes the bounding box for each triangle; required for quickly calculating tree splits.\r\n// result is an array of size tris.length * 6 where triangle i maps to a\r\n// [x_center, x_delta, y_center, y_delta, z_center, z_delta] tuple starting at index i * 6,\r\n// representing the center and half-extent in each dimension of triangle i\r\nfunction computeTriangleBounds( geo, fullBounds ) {\r\n\r\n\tconst posAttr = geo.attributes.position;\r\n\tconst posArr = posAttr.array;\r\n\tconst index = geo.index.array;\r\n\tconst triCount = index.length / 3;\r\n\tconst triangleBounds = new Float32Array( triCount * 6 );\r\n\r\n\t// support for an interleaved position buffer\r\n\tconst bufferOffset = posAttr.offset || 0;\r\n\tlet stride = 3;\r\n\tif ( posAttr.isInterleavedBufferAttribute ) {\r\n\r\n\t\tstride = posAttr.data.stride;\r\n\r\n\t}\r\n\r\n\tfor ( let tri = 0; tri < triCount; tri ++ ) {\r\n\r\n\t\tconst tri3 = tri * 3;\r\n\t\tconst tri6 = tri * 6;\r\n\t\tconst ai = index[ tri3 + 0 ] * stride + bufferOffset;\r\n\t\tconst bi = index[ tri3 + 1 ] * stride + bufferOffset;\r\n\t\tconst ci = index[ tri3 + 2 ] * stride + bufferOffset;\r\n\r\n\t\tfor ( let el = 0; el < 3; el ++ ) {\r\n\r\n\t\t\tconst a = posArr[ ai + el ];\r\n\t\t\tconst b = posArr[ bi + el ];\r\n\t\t\tconst c = posArr[ ci + el ];\r\n\r\n\t\t\tlet min = a;\r\n\t\t\tif ( b < min ) min = b;\r\n\t\t\tif ( c < min ) min = c;\r\n\r\n\t\t\tlet max = a;\r\n\t\t\tif ( b > max ) max = b;\r\n\t\t\tif ( c > max ) max = c;\r\n\r\n\t\t\t// Increase the bounds size by float32 epsilon to avoid precision errors when\r\n\t\t\t// converting to 32 bit float. Scale the epsilon by the size of the numbers being\r\n\t\t\t// worked with.\r\n\t\t\tconst halfExtents = ( max - min ) / 2;\r\n\t\t\tconst el2 = el * 2;\r\n\t\t\ttriangleBounds[ tri6 + el2 + 0 ] = min + halfExtents;\r\n\t\t\ttriangleBounds[ tri6 + el2 + 1 ] = halfExtents + ( Math.abs( min ) + halfExtents ) * FLOAT32_EPSILON;\r\n\r\n\t\t\tif ( min < fullBounds[ el ] ) fullBounds[ el ] = min;\r\n\t\t\tif ( max > fullBounds[ el + 3 ] ) fullBounds[ el + 3 ] = max;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\treturn triangleBounds;\r\n\r\n}\r\n\r\nexport function buildTree( geo, options ) {\r\n\r\n\tfunction triggerProgress( trianglesProcessed ) {\r\n\r\n\t\tif ( onProgress ) {\r\n\r\n\t\t\tonProgress( trianglesProcessed / totalTriangles );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t// either recursively splits the given node, creating left and right subtrees for it, or makes it a leaf node,\r\n\t// recording the offset and count of its triangles and writing them into the reordered geometry index.\r\n\tfunction splitNode( node, offset, count, centroidBoundingData = null, depth = 0 ) {\r\n\r\n\t\tif ( ! reachedMaxDepth && depth >= maxDepth ) {\r\n\r\n\t\t\treachedMaxDepth = true;\r\n\t\t\tif ( verbose ) {\r\n\r\n\t\t\t\tconsole.warn( `MeshBVH: Max depth of ${ maxDepth } reached when generating BVH. Consider increasing maxDepth.` );\r\n\t\t\t\tconsole.warn( geo );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// early out if we've met our capacity\r\n\t\tif ( count <= maxLeafTris || depth >= maxDepth ) {\r\n\r\n\t\t\ttriggerProgress( offset );\r\n\t\t\tnode.offset = offset;\r\n\t\t\tnode.count = count;\r\n\t\t\treturn node;\r\n\r\n\t\t}\r\n\r\n\t\t// Find where to split the volume\r\n\t\tconst split = getOptimalSplit( node.boundingData, centroidBoundingData, triangleBounds, offset, count, strategy );\r\n\t\tif ( split.axis === - 1 ) {\r\n\r\n\t\t\ttriggerProgress( offset );\r\n\t\t\tnode.offset = offset;\r\n\t\t\tnode.count = count;\r\n\t\t\treturn node;\r\n\r\n\t\t}\r\n\r\n\t\tconst splitOffset = partition( indexArray, triangleBounds, offset, count, split );\r\n\r\n\t\t// create the two new child nodes\r\n\t\tif ( splitOffset === offset || splitOffset === offset + count ) {\r\n\r\n\t\t\ttriggerProgress( offset );\r\n\t\t\tnode.offset = offset;\r\n\t\t\tnode.count = count;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tnode.splitAxis = split.axis;\r\n\r\n\t\t\t// create the left child and compute its bounding box\r\n\t\t\tconst left = new MeshBVHNode();\r\n\t\t\tconst lstart = offset;\r\n\t\t\tconst lcount = splitOffset - offset;\r\n\t\t\tnode.left = left;\r\n\t\t\tleft.boundingData = new Float32Array( 6 );\r\n\r\n\t\t\tgetBounds( triangleBounds, lstart, lcount, left.boundingData, cacheCentroidBoundingData );\r\n\t\t\tsplitNode( left, lstart, lcount, cacheCentroidBoundingData, depth + 1 );\r\n\r\n\t\t\t// repeat for right\r\n\t\t\tconst right = new MeshBVHNode();\r\n\t\t\tconst rstart = splitOffset;\r\n\t\t\tconst rcount = count - lcount;\r\n\t\t\tnode.right = right;\r\n\t\t\tright.boundingData = new Float32Array( 6 );\r\n\r\n\t\t\tgetBounds( triangleBounds, rstart, rcount, right.boundingData, cacheCentroidBoundingData );\r\n\t\t\tsplitNode( right, rstart, rcount, cacheCentroidBoundingData, depth + 1 );\r\n\r\n\t\t}\r\n\r\n\t\treturn node;\r\n\r\n\t}\r\n\r\n\tensureIndex( geo, options );\r\n\r\n\t// Compute the full bounds of the geometry at the same time as triangle bounds because\r\n\t// we'll need it for the root bounds in the case with no groups and it should be fast here.\r\n\t// We can't use the geometrying bounding box if it's available because it may be out of date.\r\n\tconst fullBounds = new Float32Array( 6 );\r\n\tconst cacheCentroidBoundingData = new Float32Array( 6 );\r\n\tconst triangleBounds = computeTriangleBounds( geo, fullBounds );\r\n\tconst indexArray = geo.index.array;\r\n\tconst maxDepth = options.maxDepth;\r\n\tconst verbose = options.verbose;\r\n\tconst maxLeafTris = options.maxLeafTris;\r\n\tconst strategy = options.strategy;\r\n\tconst onProgress = options.onProgress;\r\n\tconst totalTriangles = geo.index.count / 3;\r\n\tlet reachedMaxDepth = false;\r\n\r\n\tconst roots = [];\r\n\tconst ranges = getRootIndexRanges( geo );\r\n\r\n\tif ( ranges.length === 1 ) {\r\n\r\n\t\tconst range = ranges[ 0 ];\r\n\t\tconst root = new MeshBVHNode();\r\n\t\troot.boundingData = fullBounds;\r\n\t\tgetCentroidBounds( triangleBounds, range.offset, range.count, cacheCentroidBoundingData );\r\n\r\n\t\tsplitNode( root, range.offset, range.count, cacheCentroidBoundingData );\r\n\t\troots.push( root );\r\n\r\n\t} else {\r\n\r\n\t\tfor ( let range of ranges ) {\r\n\r\n\t\t\tconst root = new MeshBVHNode();\r\n\t\t\troot.boundingData = new Float32Array( 6 );\r\n\t\t\tgetBounds( triangleBounds, range.offset, range.count, root.boundingData, cacheCentroidBoundingData );\r\n\r\n\t\t\tsplitNode( root, range.offset, range.count, cacheCentroidBoundingData );\r\n\t\t\troots.push( root );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\treturn roots;\r\n\r\n}\r\n\r\nexport function buildPackedTree( geo, options ) {\r\n\r\n\t// boundingData \t\t\t\t: 6 float32\r\n\t// right / offset \t\t\t\t: 1 uint32\r\n\t// splitAxis / isLeaf + count \t: 1 uint32 / 2 uint16\r\n\tconst roots = buildTree( geo, options );\r\n\r\n\tlet float32Array;\r\n\tlet uint32Array;\r\n\tlet uint16Array;\r\n\tconst packedRoots = [];\r\n\tconst BufferConstructor = options.useSharedArrayBuffer ? SharedArrayBuffer : ArrayBuffer;\r\n\tfor ( let i = 0; i < roots.length; i ++ ) {\r\n\r\n\t\tconst root = roots[ i ];\r\n\t\tlet nodeCount = countNodes( root );\r\n\r\n\t\tconst buffer = new BufferConstructor( BYTES_PER_NODE * nodeCount );\r\n\t\tfloat32Array = new Float32Array( buffer );\r\n\t\tuint32Array = new Uint32Array( buffer );\r\n\t\tuint16Array = new Uint16Array( buffer );\r\n\t\tpopulateBuffer( 0, root );\r\n\t\tpackedRoots.push( buffer );\r\n\r\n\t}\r\n\r\n\treturn packedRoots;\r\n\r\n\tfunction countNodes( node ) {\r\n\r\n\t\tif ( node.count ) {\r\n\r\n\t\t\treturn 1;\r\n\r\n\t\t} else {\r\n\r\n\t\t\treturn 1 + countNodes( node.left ) + countNodes( node.right );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tfunction populateBuffer( byteOffset, node ) {\r\n\r\n\t\tconst stride4Offset = byteOffset / 4;\r\n\t\tconst stride2Offset = byteOffset / 2;\r\n\t\tconst isLeaf = ! ! node.count;\r\n\t\tconst boundingData = node.boundingData;\r\n\t\tfor ( let i = 0; i < 6; i ++ ) {\r\n\r\n\t\t\tfloat32Array[ stride4Offset + i ] = boundingData[ i ];\r\n\r\n\t\t}\r\n\r\n\t\tif ( isLeaf ) {\r\n\r\n\t\t\tconst offset = node.offset;\r\n\t\t\tconst count = node.count;\r\n\t\t\tuint32Array[ stride4Offset + 6 ] = offset;\r\n\t\t\tuint16Array[ stride2Offset + 14 ] = count;\r\n\t\t\tuint16Array[ stride2Offset + 15 ] = IS_LEAFNODE_FLAG;\r\n\t\t\treturn byteOffset + BYTES_PER_NODE;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tconst left = node.left;\r\n\t\t\tconst right = node.right;\r\n\t\t\tconst splitAxis = node.splitAxis;\r\n\r\n\t\t\tlet nextUnusedPointer;\r\n\t\t\tnextUnusedPointer = populateBuffer( byteOffset + BYTES_PER_NODE, left );\r\n\r\n\t\t\tif ( ( nextUnusedPointer / 4 ) > Math.pow( 2, 32 ) ) {\r\n\r\n\t\t\t\tthrow new Error( 'MeshBVH: Cannot store child pointer greater than 32 bits.' );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tuint32Array[ stride4Offset + 6 ] = nextUnusedPointer / 4;\r\n\t\t\tnextUnusedPointer = populateBuffer( nextUnusedPointer, right );\r\n\r\n\t\t\tuint32Array[ stride4Offset + 7 ] = splitAxis;\r\n\t\t\treturn nextUnusedPointer;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n}\r\n","import { Vector3 } from 'three';\r\n\r\nexport class SeparatingAxisBounds {\r\n\r\n\tconstructor() {\r\n\r\n\t\tthis.min = Infinity;\r\n\t\tthis.max = - Infinity;\r\n\r\n\t}\r\n\r\n\tsetFromPointsField( points, field ) {\r\n\r\n\t\tlet min = Infinity;\r\n\t\tlet max = - Infinity;\r\n\t\tfor ( let i = 0, l = points.length; i < l; i ++ ) {\r\n\r\n\t\t\tconst p = points[ i ];\r\n\t\t\tconst val = p[ field ];\r\n\t\t\tmin = val < min ? val : min;\r\n\t\t\tmax = val > max ? val : max;\r\n\r\n\t\t}\r\n\r\n\t\tthis.min = min;\r\n\t\tthis.max = max;\r\n\r\n\t}\r\n\r\n\tsetFromPoints( axis, points ) {\r\n\r\n\t\tlet min = Infinity;\r\n\t\tlet max = - Infinity;\r\n\t\tfor ( let i = 0, l = points.length; i < l; i ++ ) {\r\n\r\n\t\t\tconst p = points[ i ];\r\n\t\t\tconst val = axis.dot( p );\r\n\t\t\tmin = val < min ? val : min;\r\n\t\t\tmax = val > max ? val : max;\r\n\r\n\t\t}\r\n\r\n\t\tthis.min = min;\r\n\t\tthis.max = max;\r\n\r\n\t}\r\n\r\n\tisSeparated( other ) {\r\n\r\n\t\treturn this.min > other.max || other.min > this.max;\r\n\r\n\t}\r\n\r\n}\r\n\r\nSeparatingAxisBounds.prototype.setFromBox = ( function () {\r\n\r\n\tconst p = new Vector3();\r\n\treturn function setFromBox( axis, box ) {\r\n\r\n\t\tconst boxMin = box.min;\r\n\t\tconst boxMax = box.max;\r\n\t\tlet min = Infinity;\r\n\t\tlet max = - Infinity;\r\n\t\tfor ( let x = 0; x <= 1; x ++ ) {\r\n\r\n\t\t\tfor ( let y = 0; y <= 1; y ++ ) {\r\n\r\n\t\t\t\tfor ( let z = 0; z <= 1; z ++ ) {\r\n\r\n\t\t\t\t\tp.x = boxMin.x * x + boxMax.x * ( 1 - x );\r\n\t\t\t\t\tp.y = boxMin.y * y + boxMax.y * ( 1 - y );\r\n\t\t\t\t\tp.z = boxMin.z * z + boxMax.z * ( 1 - z );\r\n\r\n\t\t\t\t\tconst val = axis.dot( p );\r\n\t\t\t\t\tmin = Math.min( val, min );\r\n\t\t\t\t\tmax = Math.max( val, max );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tthis.min = min;\r\n\t\tthis.max = max;\r\n\r\n\t};\r\n\r\n} )();\r\n\r\nexport const areIntersecting = ( function () {\r\n\r\n\tconst cacheSatBounds = new SeparatingAxisBounds();\r\n\treturn function areIntersecting( shape1, shape2 ) {\r\n\r\n\t\tconst points1 = shape1.points;\r\n\t\tconst satAxes1 = shape1.satAxes;\r\n\t\tconst satBounds1 = shape1.satBounds;\r\n\r\n\t\tconst points2 = shape2.points;\r\n\t\tconst satAxes2 = shape2.satAxes;\r\n\t\tconst satBounds2 = shape2.satBounds;\r\n\r\n\t\t// check axes of the first shape\r\n\t\tfor ( let i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\tconst sb = satBounds1[ i ];\r\n\t\t\tconst sa = satAxes1[ i ];\r\n\t\t\tcacheSatBounds.setFromPoints( sa, points2 );\r\n\t\t\tif ( sb.isSeparated( cacheSatBounds ) ) return false;\r\n\r\n\t\t}\r\n\r\n\t\t// check axes of the second shape\r\n\t\tfor ( let i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\tconst sb = satBounds2[ i ];\r\n\t\t\tconst sa = satAxes2[ i ];\r\n\t\t\tcacheSatBounds.setFromPoints( sa, points1 );\r\n\t\t\tif ( sb.isSeparated( cacheSatBounds ) ) return false;\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n} )();\r\n","import { Vector3, Vector2, Plane, Line3 } from 'three';\r\n\r\nexport const closestPointLineToLine = ( function () {\r\n\r\n\t// https://github.com/juj/MathGeoLib/blob/master/src/Geometry/Line.cpp#L56\r\n\tconst dir1 = new Vector3();\r\n\tconst dir2 = new Vector3();\r\n\tconst v02 = new Vector3();\r\n\treturn function closestPointLineToLine( l1, l2, result ) {\r\n\r\n\t\tconst v0 = l1.start;\r\n\t\tconst v10 = dir1;\r\n\t\tconst v2 = l2.start;\r\n\t\tconst v32 = dir2;\r\n\r\n\t\tv02.subVectors( v0, v2 );\r\n\t\tdir1.subVectors( l1.end, l2.start );\r\n\t\tdir2.subVectors( l2.end, l2.start );\r\n\r\n\t\t// float d0232 = v02.Dot(v32);\r\n\t\tconst d0232 = v02.dot( v32 );\r\n\r\n\t\t// float d3210 = v32.Dot(v10);\r\n\t\tconst d3210 = v32.dot( v10 );\r\n\r\n\t\t// float d3232 = v32.Dot(v32);\r\n\t\tconst d3232 = v32.dot( v32 );\r\n\r\n\t\t// float d0210 = v02.Dot(v10);\r\n\t\tconst d0210 = v02.dot( v10 );\r\n\r\n\t\t// float d1010 = v10.Dot(v10);\r\n\t\tconst d1010 = v10.dot( v10 );\r\n\r\n\t\t// float denom = d1010*d3232 - d3210*d3210;\r\n\t\tconst denom = d1010 * d3232 - d3210 * d3210;\r\n\r\n\t\tlet d, d2;\r\n\t\tif ( denom !== 0 ) {\r\n\r\n\t\t\td = ( d0232 * d3210 - d0210 * d3232 ) / denom;\r\n\r\n\t\t} else {\r\n\r\n\t\t\td = 0;\r\n\r\n\t\t}\r\n\r\n\t\td2 = ( d0232 + d * d3210 ) / d3232;\r\n\r\n\t\tresult.x = d;\r\n\t\tresult.y = d2;\r\n\r\n\t};\r\n\r\n} )();\r\n\r\nexport const closestPointsSegmentToSegment = ( function () {\r\n\r\n\t// https://github.com/juj/MathGeoLib/blob/master/src/Geometry/LineSegment.cpp#L187\r\n\tconst paramResult = new Vector2();\r\n\tconst temp1 = new Vector3();\r\n\tconst temp2 = new Vector3();\r\n\treturn function closestPointsSegmentToSegment( l1, l2, target1, target2 ) {\r\n\r\n\t\tclosestPointLineToLine( l1, l2, paramResult );\r\n\r\n\t\tlet d = paramResult.x;\r\n\t\tlet d2 = paramResult.y;\r\n\t\tif ( d >= 0 && d <= 1 && d2 >= 0 && d2 <= 1 ) {\r\n\r\n\t\t\tl1.at( d, target1 );\r\n\t\t\tl2.at( d2, target2 );\r\n\r\n\t\t\treturn;\r\n\r\n\t\t} else if ( d >= 0 && d <= 1 ) {\r\n\r\n\t\t\t// Only d2 is out of bounds.\r\n\t\t\tif ( d2 < 0 ) {\r\n\r\n\t\t\t\tl2.at( 0, target2 );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tl2.at( 1, target2 );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tl1.closestPointToPoint( target2, true, target1 );\r\n\t\t\treturn;\r\n\r\n\t\t} else if ( d2 >= 0 && d2 <= 1 ) {\r\n\r\n\t\t\t// Only d is out of bounds.\r\n\t\t\tif ( d < 0 ) {\r\n\r\n\t\t\t\tl1.at( 0, target1 );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tl1.at( 1, target1 );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tl2.closestPointToPoint( target1, true, target2 );\r\n\t\t\treturn;\r\n\r\n\t\t} else {\r\n\r\n\t\t\t// Both u and u2 are out of bounds.\r\n\t\t\tlet p;\r\n\t\t\tif ( d < 0 ) {\r\n\r\n\t\t\t\tp = l1.start;\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tp = l1.end;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tlet p2;\r\n\t\t\tif ( d2 < 0 ) {\r\n\r\n\t\t\t\tp2 = l2.start;\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tp2 = l2.end;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tconst closestPoint = temp1;\r\n\t\t\tconst closestPoint2 = temp2;\r\n\t\t\tl1.closestPointToPoint( p2, true, temp1 );\r\n\t\t\tl2.closestPointToPoint( p, true, temp2 );\r\n\r\n\t\t\tif ( closestPoint.distanceToSquared( p2 ) <= closestPoint2.distanceToSquared( p ) ) {\r\n\r\n\t\t\t\ttarget1.copy( closestPoint );\r\n\t\t\t\ttarget2.copy( p2 );\r\n\t\t\t\treturn;\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\ttarget1.copy( p );\r\n\t\t\t\ttarget2.copy( closestPoint2 );\r\n\t\t\t\treturn;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n} )();\r\n\r\n\r\nexport const sphereIntersectTriangle = ( function () {\r\n\r\n\t// https://stackoverflow.com/questions/34043955/detect-collision-between-sphere-and-triangle-in-three-js\r\n\tconst closestPointTemp = new Vector3();\r\n\tconst projectedPointTemp = new Vector3();\r\n\tconst planeTemp = new Plane();\r\n\tconst lineTemp = new Line3();\r\n\treturn function sphereIntersectTriangle( sphere, triangle ) {\r\n\r\n\t\tconst { radius, center } = sphere;\r\n\t\tconst { a, b, c } = triangle;\r\n\r\n\t\t// phase 1\r\n\t\tlineTemp.start = a;\r\n\t\tlineTemp.end = b;\r\n\t\tconst closestPoint1 = lineTemp.closestPointToPoint( center, true, closestPointTemp );\r\n\t\tif ( closestPoint1.distanceTo( center ) <= radius ) return true;\r\n\r\n\t\tlineTemp.start = a;\r\n\t\tlineTemp.end = c;\r\n\t\tconst closestPoint2 = lineTemp.closestPointToPoint( center, true, closestPointTemp );\r\n\t\tif ( closestPoint2.distanceTo( center ) <= radius ) return true;\r\n\r\n\t\tlineTemp.start = b;\r\n\t\tlineTemp.end = c;\r\n\t\tconst closestPoint3 = lineTemp.closestPointToPoint( center, true, closestPointTemp );\r\n\t\tif ( closestPoint3.distanceTo( center ) <= radius ) return true;\r\n\r\n\t\t// phase 2\r\n\t\tconst plane = triangle.getPlane( planeTemp );\r\n\t\tconst dp = Math.abs( plane.distanceToPoint( center ) );\r\n\t\tif ( dp <= radius ) {\r\n\r\n\t\t\tconst pp = plane.projectPoint( center, projectedPointTemp );\r\n\t\t\tconst cp = triangle.containsPoint( pp );\r\n\t\t\tif ( cp ) return true;\r\n\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\r\n\t};\r\n\r\n} )();\r\n","import { Triangle, Vector3, Line3, Sphere, Plane } from 'three';\r\nimport { SeparatingAxisBounds } from './SeparatingAxisBounds.js';\r\nimport { closestPointsSegmentToSegment, sphereIntersectTriangle } from './MathUtilities.js';\r\n\r\nexport class SeparatingAxisTriangle extends Triangle {\r\n\r\n\tconstructor( ...args ) {\r\n\r\n\t\tsuper( ...args );\r\n\r\n\t\tthis.isSeparatingAxisTriangle = true;\r\n\t\tthis.satAxes = new Array( 4 ).fill().map( () => new Vector3() );\r\n\t\tthis.satBounds = new Array( 4 ).fill().map( () => new SeparatingAxisBounds() );\r\n\t\tthis.points = [ this.a, this.b, this.c ];\r\n\t\tthis.sphere = new Sphere();\r\n\t\tthis.plane = new Plane();\r\n\t\tthis.needsUpdate = false;\r\n\r\n\t}\r\n\r\n\tintersectsSphere( sphere ) {\r\n\r\n\t\treturn sphereIntersectTriangle( sphere, this );\r\n\r\n\t}\r\n\r\n\tupdate() {\r\n\r\n\t\tconst a = this.a;\r\n\t\tconst b = this.b;\r\n\t\tconst c = this.c;\r\n\t\tconst points = this.points;\r\n\r\n\t\tconst satAxes = this.satAxes;\r\n\t\tconst satBounds = this.satBounds;\r\n\r\n\t\tconst axis0 = satAxes[ 0 ];\r\n\t\tconst sab0 = satBounds[ 0 ];\r\n\t\tthis.getNormal( axis0 );\r\n\t\tsab0.setFromPoints( axis0, points );\r\n\r\n\t\tconst axis1 = satAxes[ 1 ];\r\n\t\tconst sab1 = satBounds[ 1 ];\r\n\t\taxis1.subVectors( a, b );\r\n\t\tsab1.setFromPoints( axis1, points );\r\n\r\n\t\tconst axis2 = satAxes[ 2 ];\r\n\t\tconst sab2 = satBounds[ 2 ];\r\n\t\taxis2.subVectors( b, c );\r\n\t\tsab2.setFromPoints( axis2, points );\r\n\r\n\t\tconst axis3 = satAxes[ 3 ];\r\n\t\tconst sab3 = satBounds[ 3 ];\r\n\t\taxis3.subVectors( c, a );\r\n\t\tsab3.setFromPoints( axis3, points );\r\n\r\n\t\tthis.sphere.setFromPoints( this.points );\r\n\t\tthis.plane.setFromNormalAndCoplanarPoint( axis0, a );\r\n\t\tthis.needsUpdate = false;\r\n\r\n\t}\r\n\r\n}\r\n\r\nSeparatingAxisTriangle.prototype.closestPointToSegment = ( function () {\r\n\r\n\tconst point1 = new Vector3();\r\n\tconst point2 = new Vector3();\r\n\tconst edge = new Line3();\r\n\r\n\treturn function distanceToSegment( segment, target1 = null, target2 = null ) {\r\n\r\n\t\tconst { start, end } = segment;\r\n\t\tconst points = this.points;\r\n\t\tlet distSq;\r\n\t\tlet closestDistanceSq = Infinity;\r\n\r\n\t\t// check the triangle edges\r\n\t\tfor ( let i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\tconst nexti = ( i + 1 ) % 3;\r\n\t\t\tedge.start.copy( points[ i ] );\r\n\t\t\tedge.end.copy( points[ nexti ] );\r\n\r\n\t\t\tclosestPointsSegmentToSegment( edge, segment, point1, point2 );\r\n\r\n\t\t\tdistSq = point1.distanceToSquared( point2 );\r\n\t\t\tif ( distSq < closestDistanceSq ) {\r\n\r\n\t\t\t\tclosestDistanceSq = distSq;\r\n\t\t\t\tif ( target1 ) target1.copy( point1 );\r\n\t\t\t\tif ( target2 ) target2.copy( point2 );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// check end points\r\n\t\tthis.closestPointToPoint( start, point1 );\r\n\t\tdistSq = start.distanceToSquared( point1 );\r\n\t\tif ( distSq < closestDistanceSq ) {\r\n\r\n\t\t\tclosestDistanceSq = distSq;\r\n\t\t\tif ( target1 ) target1.copy( point1 );\r\n\t\t\tif ( target2 ) target2.copy( start );\r\n\r\n\t\t}\r\n\r\n\t\tthis.closestPointToPoint( end, point1 );\r\n\t\tdistSq = end.distanceToSquared( point1 );\r\n\t\tif ( distSq < closestDistanceSq ) {\r\n\r\n\t\t\tclosestDistanceSq = distSq;\r\n\t\t\tif ( target1 ) target1.copy( point1 );\r\n\t\t\tif ( target2 ) target2.copy( end );\r\n\r\n\t\t}\r\n\r\n\t\treturn Math.sqrt( closestDistanceSq );\r\n\r\n\t};\r\n\r\n} )();\r\n\r\nSeparatingAxisTriangle.prototype.intersectsTriangle = ( function () {\r\n\r\n\tconst saTri2 = new SeparatingAxisTriangle();\r\n\tconst arr1 = new Array( 3 );\r\n\tconst arr2 = new Array( 3 );\r\n\tconst cachedSatBounds = new SeparatingAxisBounds();\r\n\tconst cachedSatBounds2 = new SeparatingAxisBounds();\r\n\tconst cachedAxis = new Vector3();\r\n\tconst dir1 = new Vector3();\r\n\tconst dir2 = new Vector3();\r\n\tconst tempDir = new Vector3();\r\n\tconst edge = new Line3();\r\n\tconst edge1 = new Line3();\r\n\tconst edge2 = new Line3();\r\n\r\n\t// TODO: If the triangles are coplanar and intersecting the target is nonsensical. It should at least\r\n\t// be a line contained by both triangles if not a different special case somehow represented in the return result.\r\n\treturn function intersectsTriangle( other, target = null ) {\r\n\r\n\t\tif ( this.needsUpdate ) {\r\n\r\n\t\t\tthis.update();\r\n\r\n\t\t}\r\n\r\n\t\tif ( ! other.isSeparatingAxisTriangle ) {\r\n\r\n\t\t\tsaTri2.copy( other );\r\n\t\t\tsaTri2.update();\r\n\t\t\tother = saTri2;\r\n\r\n\t\t} else if ( other.needsUpdate ) {\r\n\r\n\t\t\tother.update();\r\n\r\n\t\t}\r\n\r\n\t\tconst satBounds1 = this.satBounds;\r\n\t\tconst satAxes1 = this.satAxes;\r\n\t\tarr2[ 0 ] = other.a;\r\n\t\tarr2[ 1 ] = other.b;\r\n\t\tarr2[ 2 ] = other.c;\r\n\t\tfor ( let i = 0; i < 4; i ++ ) {\r\n\r\n\t\t\tconst sb = satBounds1[ i ];\r\n\t\t\tconst sa = satAxes1[ i ];\r\n\t\t\tcachedSatBounds.setFromPoints( sa, arr2 );\r\n\t\t\tif ( sb.isSeparated( cachedSatBounds ) ) return false;\r\n\r\n\t\t}\r\n\r\n\t\tconst satBounds2 = other.satBounds;\r\n\t\tconst satAxes2 = other.satAxes;\r\n\t\tarr1[ 0 ] = this.a;\r\n\t\tarr1[ 1 ] = this.b;\r\n\t\tarr1[ 2 ] = this.c;\r\n\t\tfor ( let i = 0; i < 4; i ++ ) {\r\n\r\n\t\t\tconst sb = satBounds2[ i ];\r\n\t\t\tconst sa = satAxes2[ i ];\r\n\t\t\tcachedSatBounds.setFromPoints( sa, arr1 );\r\n\t\t\tif ( sb.isSeparated( cachedSatBounds ) ) return false;\r\n\r\n\t\t}\r\n\r\n\t\t// check crossed axes\r\n\t\tfor ( let i = 0; i < 4; i ++ ) {\r\n\r\n\t\t\tconst sa1 = satAxes1[ i ];\r\n\t\t\tfor ( let i2 = 0; i2 < 4; i2 ++ ) {\r\n\r\n\t\t\t\tconst sa2 = satAxes2[ i2 ];\r\n\t\t\t\tcachedAxis.crossVectors( sa1, sa2 );\r\n\t\t\t\tcachedSatBounds.setFromPoints( cachedAxis, arr1 );\r\n\t\t\t\tcachedSatBounds2.setFromPoints( cachedAxis, arr2 );\r\n\t\t\t\tif ( cachedSatBounds.isSeparated( cachedSatBounds2 ) ) return false;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( target ) {\r\n\r\n\t\t\tconst plane1 = this.plane;\r\n\t\t\tconst plane2 = other.plane;\r\n\r\n\t\t\tif ( Math.abs( plane1.normal.dot( plane2.normal ) ) > 1.0 - 1e-10 ) {\r\n\r\n\t\t\t\t// TODO find two points that intersect on the edges and make that the result\r\n\t\t\t\tconsole.warn( 'SeparatingAxisTriangle.intersectsTriangle: Triangles are coplanar which does not support an output edge. Setting edge to 0, 0, 0.' );\r\n\t\t\t\ttarget.start.set( 0, 0, 0 );\r\n\t\t\t\ttarget.end.set( 0, 0, 0 );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\t// find the edge that intersects the other triangle plane\r\n\t\t\t\tconst points1 = this.points;\r\n\t\t\t\tlet found1 = false;\r\n\t\t\t\tfor ( let i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\t\t\tconst p1 = points1[ i ];\r\n\t\t\t\t\tconst p2 = points1[ ( i + 1 ) % 3 ];\r\n\r\n\t\t\t\t\tedge.start.copy( p1 );\r\n\t\t\t\t\tedge.end.copy( p2 );\r\n\r\n\t\t\t\t\tif ( plane2.intersectLine( edge, found1 ? edge1.start : edge1.end ) ) {\r\n\r\n\t\t\t\t\t\tif ( found1 ) {\r\n\r\n\t\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tfound1 = true;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// find the other triangles edge that intersects this plane\r\n\t\t\t\tconst points2 = other.points;\r\n\t\t\t\tlet found2 = false;\r\n\t\t\t\tfor ( let i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\t\t\tconst p1 = points2[ i ];\r\n\t\t\t\t\tconst p2 = points2[ ( i + 1 ) % 3 ];\r\n\r\n\t\t\t\t\tedge.start.copy( p1 );\r\n\t\t\t\t\tedge.end.copy( p2 );\r\n\r\n\t\t\t\t\tif ( plane1.intersectLine( edge, found2 ? edge2.start : edge2.end ) ) {\r\n\r\n\t\t\t\t\t\tif ( found2 ) {\r\n\r\n\t\t\t\t\t\t\tbreak;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tfound2 = true;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// find swap the second edge so both lines are running the same direction\r\n\t\t\t\tedge1.delta( dir1 );\r\n\t\t\t\tedge2.delta( dir2 );\r\n\r\n\r\n\t\t\t\tif ( dir1.dot( dir2 ) < 0 ) {\r\n\r\n\t\t\t\t\tlet tmp = edge2.start;\r\n\t\t\t\t\tedge2.start = edge2.end;\r\n\t\t\t\t\tedge2.end = tmp;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\ttempDir.subVectors( edge1.start, edge2.start );\r\n\t\t\t\tif ( tempDir.dot( dir1 ) > 0 ) {\r\n\r\n\t\t\t\t\ttarget.start.copy( edge1.start );\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\ttarget.start.copy( edge2.start );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\ttempDir.subVectors( edge1.end, edge2.end );\r\n\t\t\t\tif ( tempDir.dot( dir1 ) < 0 ) {\r\n\r\n\t\t\t\t\ttarget.end.copy( edge1.end );\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\ttarget.end.copy( edge2.end );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\r\n\t};\r\n\r\n} )();\r\n\r\n\r\nSeparatingAxisTriangle.prototype.distanceToPoint = ( function () {\r\n\r\n\tconst target = new Vector3();\r\n\treturn function distanceToPoint( point ) {\r\n\r\n\t\tthis.closestPointToPoint( point, target );\r\n\t\treturn point.distanceTo( target );\r\n\r\n\t};\r\n\r\n} )();\r\n\r\n\r\nSeparatingAxisTriangle.prototype.distanceToTriangle = ( function () {\r\n\r\n\tconst point = new Vector3();\r\n\tconst point2 = new Vector3();\r\n\tconst cornerFields = [ 'a', 'b', 'c' ];\r\n\tconst line1 = new Line3();\r\n\tconst line2 = new Line3();\r\n\r\n\treturn function distanceToTriangle( other, target1 = null, target2 = null ) {\r\n\r\n\t\tconst lineTarget = target1 || target2 ? line1 : null;\r\n\t\tif ( this.intersectsTriangle( other, lineTarget ) ) {\r\n\r\n\t\t\tif ( target1 || target2 ) {\r\n\r\n\t\t\t\tif ( target1 ) lineTarget.getCenter( target1 );\r\n\t\t\t\tif ( target2 ) lineTarget.getCenter( target2 );\r\n\r\n\t\t\t}\r\n\r\n\t\t\treturn 0;\r\n\r\n\t\t}\r\n\r\n\t\tlet closestDistanceSq = Infinity;\r\n\r\n\t\t// check all point distances\r\n\t\tfor ( let i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\tlet dist;\r\n\t\t\tconst field = cornerFields[ i ];\r\n\t\t\tconst otherVec = other[ field ];\r\n\t\t\tthis.closestPointToPoint( otherVec, point );\r\n\r\n\t\t\tdist = otherVec.distanceToSquared( point );\r\n\r\n\t\t\tif ( dist < closestDistanceSq ) {\r\n\r\n\t\t\t\tclosestDistanceSq = dist;\r\n\t\t\t\tif ( target1 ) target1.copy( point );\r\n\t\t\t\tif ( target2 ) target2.copy( otherVec );\r\n\r\n\t\t\t}\r\n\r\n\r\n\t\t\tconst thisVec = this[ field ];\r\n\t\t\tother.closestPointToPoint( thisVec, point );\r\n\r\n\t\t\tdist = thisVec.distanceToSquared( point );\r\n\r\n\t\t\tif ( dist < closestDistanceSq ) {\r\n\r\n\t\t\t\tclosestDistanceSq = dist;\r\n\t\t\t\tif ( target1 ) target1.copy( thisVec );\r\n\t\t\t\tif ( target2 ) target2.copy( point );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tfor ( let i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\tconst f11 = cornerFields[ i ];\r\n\t\t\tconst f12 = cornerFields[ ( i + 1 ) % 3 ];\r\n\t\t\tline1.set( this[ f11 ], this[ f12 ] );\r\n\t\t\tfor ( let i2 = 0; i2 < 3; i2 ++ ) {\r\n\r\n\t\t\t\tconst f21 = cornerFields[ i2 ];\r\n\t\t\t\tconst f22 = cornerFields[ ( i2 + 1 ) % 3 ];\r\n\t\t\t\tline2.set( other[ f21 ], other[ f22 ] );\r\n\r\n\t\t\t\tclosestPointsSegmentToSegment( line1, line2, point, point2 );\r\n\r\n\t\t\t\tconst dist = point.distanceToSquared( point2 );\r\n\t\t\t\tif ( dist < closestDistanceSq ) {\r\n\r\n\t\t\t\t\tclosestDistanceSq = dist;\r\n\t\t\t\t\tif ( target1 ) target1.copy( point );\r\n\t\t\t\t\tif ( target2 ) target2.copy( point2 );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn Math.sqrt( closestDistanceSq );\r\n\r\n\t};\r\n\r\n} )();\r\n\r\n","import { Box3, Vector3, Matrix4, Line3 } from 'three';\r\nimport { SeparatingAxisBounds } from './SeparatingAxisBounds.js';\r\nimport { SeparatingAxisTriangle } from './SeparatingAxisTriangle.js';\r\nimport { closestPointsSegmentToSegment } from './MathUtilities.js';\r\n\r\nexport class OrientedBox extends Box3 {\r\n\r\n\tconstructor( ...args ) {\r\n\r\n\t\tsuper( ...args );\r\n\r\n\t\tthis.isOrientedBox = true;\r\n\t\tthis.matrix = new Matrix4();\r\n\t\tthis.invMatrix = new Matrix4();\r\n\t\tthis.points = new Array( 8 ).fill().map( () => new Vector3() );\r\n\t\tthis.satAxes = new Array( 3 ).fill().map( () => new Vector3() );\r\n\t\tthis.satBounds = new Array( 3 ).fill().map( () => new SeparatingAxisBounds() );\r\n\t\tthis.alignedSatBounds = new Array( 3 ).fill().map( () => new SeparatingAxisBounds() );\r\n\t\tthis.needsUpdate = false;\r\n\r\n\t}\r\n\r\n\tset( min, max, matrix ) {\r\n\r\n\t\tsuper.set( min, max );\r\n\t\tthis.matrix = matrix;\r\n\t\tthis.needsUpdate = true;\r\n\r\n\t}\r\n\r\n\tcopy( other ) {\r\n\r\n\t\tsuper.copy( other );\r\n\t\tthis.matrix.copy( other.matrix );\r\n\t\tthis.needsUpdate = true;\r\n\r\n\t}\r\n\r\n}\r\n\r\nOrientedBox.prototype.update = ( function () {\r\n\r\n\treturn function update() {\r\n\r\n\t\tconst matrix = this.matrix;\r\n\t\tconst min = this.min;\r\n\t\tconst max = this.max;\r\n\r\n\t\tconst points = this.points;\r\n\t\tfor ( let x = 0; x <= 1; x ++ ) {\r\n\r\n\t\t\tfor ( let y = 0; y <= 1; y ++ ) {\r\n\r\n\t\t\t\tfor ( let z = 0; z <= 1; z ++ ) {\r\n\r\n\t\t\t\t\tconst i = ( ( 1 << 0 ) * x ) | ( ( 1 << 1 ) * y ) | ( ( 1 << 2 ) * z );\r\n\t\t\t\t\tconst v = points[ i ];\r\n\t\t\t\t\tv.x = x ? max.x : min.x;\r\n\t\t\t\t\tv.y = y ? max.y : min.y;\r\n\t\t\t\t\tv.z = z ? max.z : min.z;\r\n\r\n\t\t\t\t\tv.applyMatrix4( matrix );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tconst satBounds = this.satBounds;\r\n\t\tconst satAxes = this.satAxes;\r\n\t\tconst minVec = points[ 0 ];\r\n\t\tfor ( let i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\tconst axis = satAxes[ i ];\r\n\t\t\tconst sb = satBounds[ i ];\r\n\t\t\tconst index = 1 << i;\r\n\t\t\tconst pi = points[ index ];\r\n\r\n\t\t\taxis.subVectors( minVec, pi );\r\n\t\t\tsb.setFromPoints( axis, points );\r\n\r\n\t\t}\r\n\r\n\t\tconst alignedSatBounds = this.alignedSatBounds;\r\n\t\talignedSatBounds[ 0 ].setFromPointsField( points, 'x' );\r\n\t\talignedSatBounds[ 1 ].setFromPointsField( points, 'y' );\r\n\t\talignedSatBounds[ 2 ].setFromPointsField( points, 'z' );\r\n\r\n\t\tthis.invMatrix.copy( this.matrix ).invert();\r\n\t\tthis.needsUpdate = false;\r\n\r\n\t};\r\n\r\n} )();\r\n\r\nOrientedBox.prototype.intersectsBox = ( function () {\r\n\r\n\tconst aabbBounds = new SeparatingAxisBounds();\r\n\treturn function intersectsBox( box ) {\r\n\r\n\t\t// TODO: should this be doing SAT against the AABB?\r\n\t\tif ( this.needsUpdate ) {\r\n\r\n\t\t\tthis.update();\r\n\r\n\t\t}\r\n\r\n\t\tconst min = box.min;\r\n\t\tconst max = box.max;\r\n\t\tconst satBounds = this.satBounds;\r\n\t\tconst satAxes = this.satAxes;\r\n\t\tconst alignedSatBounds = this.alignedSatBounds;\r\n\r\n\t\taabbBounds.min = min.x;\r\n\t\taabbBounds.max = max.x;\r\n\t\tif ( alignedSatBounds[ 0 ].isSeparated( aabbBounds ) ) return false;\r\n\r\n\t\taabbBounds.min = min.y;\r\n\t\taabbBounds.max = max.y;\r\n\t\tif ( alignedSatBounds[ 1 ].isSeparated( aabbBounds ) ) return false;\r\n\r\n\t\taabbBounds.min = min.z;\r\n\t\taabbBounds.max = max.z;\r\n\t\tif ( alignedSatBounds[ 2 ].isSeparated( aabbBounds ) ) return false;\r\n\r\n\t\tfor ( let i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\tconst axis = satAxes[ i ];\r\n\t\t\tconst sb = satBounds[ i ];\r\n\t\t\taabbBounds.setFromBox( axis, box );\r\n\t\t\tif ( sb.isSeparated( aabbBounds ) ) return false;\r\n\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\r\n\t};\r\n\r\n} )();\r\n\r\nOrientedBox.prototype.intersectsTriangle = ( function () {\r\n\r\n\tconst saTri = new SeparatingAxisTriangle();\r\n\tconst pointsArr = new Array( 3 );\r\n\tconst cachedSatBounds = new SeparatingAxisBounds();\r\n\tconst cachedSatBounds2 = new SeparatingAxisBounds();\r\n\tconst cachedAxis = new Vector3();\r\n\treturn function intersectsTriangle( triangle ) {\r\n\r\n\t\tif ( this.needsUpdate ) {\r\n\r\n\t\t\tthis.update();\r\n\r\n\t\t}\r\n\r\n\t\tif ( ! triangle.isSeparatingAxisTriangle ) {\r\n\r\n\t\t\tsaTri.copy( triangle );\r\n\t\t\tsaTri.update();\r\n\t\t\ttriangle = saTri;\r\n\r\n\t\t} else if ( triangle.needsUpdate ) {\r\n\r\n\t\t\ttriangle.update();\r\n\r\n\t\t}\r\n\r\n\t\tconst satBounds = this.satBounds;\r\n\t\tconst satAxes = this.satAxes;\r\n\r\n\t\tpointsArr[ 0 ] = triangle.a;\r\n\t\tpointsArr[ 1 ] = triangle.b;\r\n\t\tpointsArr[ 2 ] = triangle.c;\r\n\r\n\t\tfor ( let i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\tconst sb = satBounds[ i ];\r\n\t\t\tconst sa = satAxes[ i ];\r\n\t\t\tcachedSatBounds.setFromPoints( sa, pointsArr );\r\n\t\t\tif ( sb.isSeparated( cachedSatBounds ) ) return false;\r\n\r\n\t\t}\r\n\r\n\t\tconst triSatBounds = triangle.satBounds;\r\n\t\tconst triSatAxes = triangle.satAxes;\r\n\t\tconst points = this.points;\r\n\t\tfor ( let i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\tconst sb = triSatBounds[ i ];\r\n\t\t\tconst sa = triSatAxes[ i ];\r\n\t\t\tcachedSatBounds.setFromPoints( sa, points );\r\n\t\t\tif ( sb.isSeparated( cachedSatBounds ) ) return false;\r\n\r\n\t\t}\r\n\r\n\t\t// check crossed axes\r\n\t\tfor ( let i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\tconst sa1 = satAxes[ i ];\r\n\t\t\tfor ( let i2 = 0; i2 < 4; i2 ++ ) {\r\n\r\n\t\t\t\tconst sa2 = triSatAxes[ i2 ];\r\n\t\t\t\tcachedAxis.crossVectors( sa1, sa2 );\r\n\t\t\t\tcachedSatBounds.setFromPoints( cachedAxis, pointsArr );\r\n\t\t\t\tcachedSatBounds2.setFromPoints( cachedAxis, points );\r\n\t\t\t\tif ( cachedSatBounds.isSeparated( cachedSatBounds2 ) ) return false;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\r\n\t};\r\n\r\n} )();\r\n\r\nOrientedBox.prototype.closestPointToPoint = ( function () {\r\n\r\n\treturn function closestPointToPoint( point, target1 ) {\r\n\r\n\t\tif ( this.needsUpdate ) {\r\n\r\n\t\t\tthis.update();\r\n\r\n\t\t}\r\n\r\n\t\ttarget1\r\n\t\t\t.copy( point )\r\n\t\t\t.applyMatrix4( this.invMatrix )\r\n\t\t\t.clamp( this.min, this.max )\r\n\t\t\t.applyMatrix4( this.matrix );\r\n\r\n\t\treturn target1;\r\n\r\n\t};\r\n\r\n} )();\r\n\r\nOrientedBox.prototype.distanceToPoint = ( function () {\r\n\r\n\tconst target = new Vector3();\r\n\treturn function distanceToPoint( point ) {\r\n\r\n\t\tthis.closestPointToPoint( point, target );\r\n\t\treturn point.distanceTo( target );\r\n\r\n\t};\r\n\r\n} )();\r\n\r\nOrientedBox.prototype.distanceToBox = ( function () {\r\n\r\n\tconst xyzFields = [ 'x', 'y', 'z' ];\r\n\tconst segments1 = new Array( 12 ).fill().map( () => new Line3() );\r\n\tconst segments2 = new Array( 12 ).fill().map( () => new Line3() );\r\n\r\n\tconst point1 = new Vector3();\r\n\tconst point2 = new Vector3();\r\n\r\n\t// early out if we find a value below threshold\r\n\treturn function distanceToBox( box, threshold = 0, target1 = null, target2 = null ) {\r\n\r\n\t\tif ( this.needsUpdate ) {\r\n\r\n\t\t\tthis.update();\r\n\r\n\t\t}\r\n\r\n\t\tif ( this.intersectsBox( box ) ) {\r\n\r\n\t\t\tif ( target1 || target2 ) {\r\n\r\n\t\t\t\tbox.getCenter( point2 );\r\n\t\t\t\tthis.closestPointToPoint( point2, point1 );\r\n\t\t\t\tbox.closestPointToPoint( point1, point2 );\r\n\r\n\t\t\t\tif ( target1 ) target1.copy( point1 );\r\n\t\t\t\tif ( target2 ) target2.copy( point2 );\r\n\r\n\t\t\t}\r\n\r\n\t\t\treturn 0;\r\n\r\n\t\t}\r\n\r\n\t\tconst threshold2 = threshold * threshold;\r\n\t\tconst min = box.min;\r\n\t\tconst max = box.max;\r\n\t\tconst points = this.points;\r\n\r\n\r\n\t\t// iterate over every edge and compare distances\r\n\t\tlet closestDistanceSq = Infinity;\r\n\r\n\t\t// check over all these points\r\n\t\tfor ( let i = 0; i < 8; i ++ ) {\r\n\r\n\t\t\tconst p = points[ i ];\r\n\t\t\tpoint2.copy( p ).clamp( min, max );\r\n\r\n\t\t\tconst dist = p.distanceToSquared( point2 );\r\n\t\t\tif ( dist < closestDistanceSq ) {\r\n\r\n\t\t\t\tclosestDistanceSq = dist;\r\n\t\t\t\tif ( target1 ) target1.copy( p );\r\n\t\t\t\tif ( target2 ) target2.copy( point2 );\r\n\r\n\t\t\t\tif ( dist < threshold2 ) return Math.sqrt( dist );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// generate and check all line segment distances\r\n\t\tlet count = 0;\r\n\t\tfor ( let i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\tfor ( let i1 = 0; i1 <= 1; i1 ++ ) {\r\n\r\n\t\t\t\tfor ( let i2 = 0; i2 <= 1; i2 ++ ) {\r\n\r\n\t\t\t\t\tconst nextIndex = ( i + 1 ) % 3;\r\n\t\t\t\t\tconst nextIndex2 = ( i + 2 ) % 3;\r\n\r\n\t\t\t\t\t// get obb line segments\r\n\t\t\t\t\tconst index = i1 << nextIndex | i2 << nextIndex2;\r\n\t\t\t\t\tconst index2 = 1 << i | i1 << nextIndex | i2 << nextIndex2;\r\n\t\t\t\t\tconst p1 = points[ index ];\r\n\t\t\t\t\tconst p2 = points[ index2 ];\r\n\t\t\t\t\tconst line1 = segments1[ count ];\r\n\t\t\t\t\tline1.set( p1, p2 );\r\n\r\n\r\n\t\t\t\t\t// get aabb line segments\r\n\t\t\t\t\tconst f1 = xyzFields[ i ];\r\n\t\t\t\t\tconst f2 = xyzFields[ nextIndex ];\r\n\t\t\t\t\tconst f3 = xyzFields[ nextIndex2 ];\r\n\t\t\t\t\tconst line2 = segments2[ count ];\r\n\t\t\t\t\tconst start = line2.start;\r\n\t\t\t\t\tconst end = line2.end;\r\n\r\n\t\t\t\t\tstart[ f1 ] = min[ f1 ];\r\n\t\t\t\t\tstart[ f2 ] = i1 ? min[ f2 ] : max[ f2 ];\r\n\t\t\t\t\tstart[ f3 ] = i2 ? min[ f3 ] : max[ f2 ];\r\n\r\n\t\t\t\t\tend[ f1 ] = max[ f1 ];\r\n\t\t\t\t\tend[ f2 ] = i1 ? min[ f2 ] : max[ f2 ];\r\n\t\t\t\t\tend[ f3 ] = i2 ? min[ f3 ] : max[ f2 ];\r\n\r\n\t\t\t\t\tcount ++;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// check all the other boxes point\r\n\t\tfor ( let x = 0; x <= 1; x ++ ) {\r\n\r\n\t\t\tfor ( let y = 0; y <= 1; y ++ ) {\r\n\r\n\t\t\t\tfor ( let z = 0; z <= 1; z ++ ) {\r\n\r\n\t\t\t\t\tpoint2.x = x ? max.x : min.x;\r\n\t\t\t\t\tpoint2.y = y ? max.y : min.y;\r\n\t\t\t\t\tpoint2.z = z ? max.z : min.z;\r\n\r\n\t\t\t\t\tthis.closestPointToPoint( point2, point1 );\r\n\t\t\t\t\tconst dist = point2.distanceToSquared( point1 );\r\n\t\t\t\t\tif ( dist < closestDistanceSq ) {\r\n\r\n\t\t\t\t\t\tclosestDistanceSq = dist;\r\n\t\t\t\t\t\tif ( target1 ) target1.copy( point1 );\r\n\t\t\t\t\t\tif ( target2 ) target2.copy( point2 );\r\n\r\n\t\t\t\t\t\tif ( dist < threshold2 ) return Math.sqrt( dist );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tfor ( let i = 0; i < 12; i ++ ) {\r\n\r\n\t\t\tconst l1 = segments1[ i ];\r\n\t\t\tfor ( let i2 = 0; i2 < 12; i2 ++ ) {\r\n\r\n\t\t\t\tconst l2 = segments2[ i2 ];\r\n\t\t\t\tclosestPointsSegmentToSegment( l1, l2, point1, point2 );\r\n\t\t\t\tconst dist = point1.distanceToSquared( point2 );\r\n\t\t\t\tif ( dist < closestDistanceSq ) {\r\n\r\n\t\t\t\t\tclosestDistanceSq = dist;\r\n\t\t\t\t\tif ( target1 ) target1.copy( point1 );\r\n\t\t\t\t\tif ( target2 ) target2.copy( point2 );\r\n\r\n\t\t\t\t\tif ( dist < threshold2 ) return Math.sqrt( dist );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn Math.sqrt( closestDistanceSq );\r\n\r\n\t};\r\n\r\n} )();\r\n","import { Vector3, Vector2, Triangle, DoubleSide, BackSide } from 'three';\r\n\r\n// Ripped and modified From THREE.js Mesh raycast\r\n// https://github.com/mrdoob/three.js/blob/0aa87c999fe61e216c1133fba7a95772b503eddf/src/objects/Mesh.js#L115\r\nconst vA = /* @__PURE__ */ new Vector3();\r\nconst vB = /* @__PURE__ */ new Vector3();\r\nconst vC = /* @__PURE__ */ new Vector3();\r\n\r\nconst uvA = /* @__PURE__ */ new Vector2();\r\nconst uvB = /* @__PURE__ */ new Vector2();\r\nconst uvC = /* @__PURE__ */ new Vector2();\r\n\r\nconst intersectionPoint = /* @__PURE__ */ new Vector3();\r\nfunction checkIntersection( ray, pA, pB, pC, point, side ) {\r\n\r\n\tlet intersect;\r\n\tif ( side === BackSide ) {\r\n\r\n\t\tintersect = ray.intersectTriangle( pC, pB, pA, true, point );\r\n\r\n\t} else {\r\n\r\n\t\tintersect = ray.intersectTriangle( pA, pB, pC, side !== DoubleSide, point );\r\n\r\n\t}\r\n\r\n\tif ( intersect === null ) return null;\r\n\r\n\tconst distance = ray.origin.distanceTo( point );\r\n\r\n\treturn {\r\n\r\n\t\tdistance: distance,\r\n\t\tpoint: point.clone(),\r\n\r\n\t};\r\n\r\n}\r\n\r\nfunction checkBufferGeometryIntersection( ray, position, uv, a, b, c, side ) {\r\n\r\n\tvA.fromBufferAttribute( position, a );\r\n\tvB.fromBufferAttribute( position, b );\r\n\tvC.fromBufferAttribute( position, c );\r\n\r\n\tconst intersection = checkIntersection( ray, vA, vB, vC, intersectionPoint, side );\r\n\r\n\tif ( intersection ) {\r\n\r\n\t\tif ( uv ) {\r\n\r\n\t\t\tuvA.fromBufferAttribute( uv, a );\r\n\t\t\tuvB.fromBufferAttribute( uv, b );\r\n\t\t\tuvC.fromBufferAttribute( uv, c );\r\n\r\n\t\t\tintersection.uv = Triangle.getUV( intersectionPoint, vA, vB, vC, uvA, uvB, uvC, new Vector2( ) );\r\n\r\n\t\t}\r\n\r\n\t\tconst face = {\r\n\t\t\ta: a,\r\n\t\t\tb: b,\r\n\t\t\tc: c,\r\n\t\t\tnormal: new Vector3(),\r\n\t\t\tmaterialIndex: 0\r\n\t\t};\r\n\r\n\t\tTriangle.getNormal( vA, vB, vC, face.normal );\r\n\r\n\t\tintersection.face = face;\r\n\t\tintersection.faceIndex = a;\r\n\r\n\t}\r\n\r\n\treturn intersection;\r\n\r\n}\r\n\r\n// https://github.com/mrdoob/three.js/blob/0aa87c999fe61e216c1133fba7a95772b503eddf/src/objects/Mesh.js#L258\r\nfunction intersectTri( geo, side, ray, tri, intersections ) {\r\n\r\n\tconst triOffset = tri * 3;\r\n\tconst a = geo.index.getX( triOffset );\r\n\tconst b = geo.index.getX( triOffset + 1 );\r\n\tconst c = geo.index.getX( triOffset + 2 );\r\n\r\n\tconst intersection = checkBufferGeometryIntersection( ray, geo.attributes.position, geo.attributes.uv, a, b, c, side );\r\n\r\n\tif ( intersection ) {\r\n\r\n\t\tintersection.faceIndex = tri;\r\n\t\tif ( intersections ) intersections.push( intersection );\r\n\t\treturn intersection;\r\n\r\n\t}\r\n\r\n\treturn null;\r\n\r\n}\r\n\r\nexport { intersectTri };\r\n","import { intersectTri } from './ThreeRayIntersectUtilities.js';\r\n\r\nexport function intersectTris( geo, side, ray, offset, count, intersections ) {\r\n\r\n\tfor ( let i = offset, end = offset + count; i < end; i ++ ) {\r\n\r\n\t\tintersectTri( geo, side, ray, i, intersections );\r\n\r\n\t}\r\n\r\n}\r\n\r\nexport function intersectClosestTri( geo, side, ray, offset, count ) {\r\n\r\n\tlet dist = Infinity;\r\n\tlet res = null;\r\n\tfor ( let i = offset, end = offset + count; i < end; i ++ ) {\r\n\r\n\t\tconst intersection = intersectTri( geo, side, ray, i );\r\n\t\tif ( intersection && intersection.distance < dist ) {\r\n\r\n\t\t\tres = intersection;\r\n\t\t\tdist = intersection.distance;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\treturn res;\r\n\r\n}\r\n\r\n// converts the given BVH raycast intersection to align with the three.js raycast\r\n// structure (include object, world space distance and point).\r\nexport function convertRaycastIntersect( hit, object, raycaster ) {\r\n\r\n\tif ( hit === null ) {\r\n\r\n\t\treturn null;\r\n\r\n\t}\r\n\r\n\thit.point.applyMatrix4( object.matrixWorld );\r\n\thit.distance = hit.point.distanceTo( raycaster.ray.origin );\r\n\thit.object = object;\r\n\r\n\tif ( hit.distance < raycaster.near || hit.distance > raycaster.far ) {\r\n\r\n\t\treturn null;\r\n\r\n\t} else {\r\n\r\n\t\treturn hit;\r\n\r\n\t}\r\n\r\n}\r\n","\r\nimport { Vector2, Vector3, Triangle } from 'three';\r\n\r\n// sets the vertices of triangle `tri` with the 3 vertices after i\r\nexport function setTriangle( tri, i, index, pos ) {\r\n\r\n\tconst ta = tri.a;\r\n\tconst tb = tri.b;\r\n\tconst tc = tri.c;\r\n\r\n\tlet i0 = i;\r\n\tlet i1 = i + 1;\r\n\tlet i2 = i + 2;\r\n\tif ( index ) {\r\n\r\n\t\ti0 = index.getX( i );\r\n\t\ti1 = index.getX( i + 1 );\r\n\t\ti2 = index.getX( i + 2 );\r\n\r\n\t}\r\n\r\n\tta.x = pos.getX( i0 );\r\n\tta.y = pos.getY( i0 );\r\n\tta.z = pos.getZ( i0 );\r\n\r\n\ttb.x = pos.getX( i1 );\r\n\ttb.y = pos.getY( i1 );\r\n\ttb.z = pos.getZ( i1 );\r\n\r\n\ttc.x = pos.getX( i2 );\r\n\ttc.y = pos.getY( i2 );\r\n\ttc.z = pos.getZ( i2 );\r\n\r\n}\r\n\r\nexport function iterateOverTriangles(\r\n\toffset,\r\n\tcount,\r\n\tgeometry,\r\n\tintersectsTriangleFunc,\r\n\tcontained,\r\n\tdepth,\r\n\ttriangle\r\n) {\r\n\r\n\tconst index = geometry.index;\r\n\tconst pos = geometry.attributes.position;\r\n\tfor ( let i = offset, l = count + offset; i < l; i ++ ) {\r\n\r\n\t\tsetTriangle( triangle, i * 3, index, pos );\r\n\t\ttriangle.needsUpdate = true;\r\n\r\n\t\tif ( intersectsTriangleFunc( triangle, i, contained, depth ) ) {\r\n\r\n\t\t\treturn true;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\treturn false;\r\n\r\n}\r\n\r\nconst tempV1 = /* @__PURE__ */ new Vector3();\r\nconst tempV2 = /* @__PURE__ */ new Vector3();\r\nconst tempV3 = /* @__PURE__ */ new Vector3();\r\nconst tempUV1 = /* @__PURE__ */ new Vector2();\r\nconst tempUV2 = /* @__PURE__ */ new Vector2();\r\nconst tempUV3 = /* @__PURE__ */ new Vector2();\r\n\r\nexport function getTriangleHitPointInfo( point, geometry, triangleIndex, target ) {\r\n\r\n\tconst indices = geometry.getIndex().array;\r\n\tconst positions = geometry.getAttribute( 'position' );\r\n\tconst uvs = geometry.getAttribute( 'uv' );\r\n\r\n\tconst a = indices[ triangleIndex * 3 ];\r\n\tconst b = indices[ triangleIndex * 3 + 1 ];\r\n\tconst c = indices[ triangleIndex * 3 + 2 ];\r\n\r\n\ttempV1.fromBufferAttribute( positions, a );\r\n\ttempV2.fromBufferAttribute( positions, b );\r\n\ttempV3.fromBufferAttribute( positions, c );\r\n\r\n\t// find the associated material index\r\n\tlet materialIndex = 0;\r\n\tconst groups = geometry.groups;\r\n\tconst firstVertexIndex = triangleIndex * 3;\r\n\tfor ( let i = 0, l = groups.length; i < l; i ++ ) {\r\n\r\n\t\tconst group = groups[ i ];\r\n\t\tconst { start, count } = group;\r\n\t\tif ( firstVertexIndex >= start && firstVertexIndex < start + count ) {\r\n\r\n\t\t\tmaterialIndex = group.materialIndex;\r\n\t\t\tbreak;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t// extract uvs\r\n\tlet uv = null;\r\n\tif ( uvs ) {\r\n\r\n\t\ttempUV1.fromBufferAttribute( uvs, a );\r\n\t\ttempUV2.fromBufferAttribute( uvs, b );\r\n\t\ttempUV3.fromBufferAttribute( uvs, c );\r\n\r\n\t\tif ( target && target.uv ) uv = target.uv;\r\n\t\telse uv = new Vector2();\r\n\r\n\t\tTriangle.getUV( point, tempV1, tempV2, tempV3, tempUV1, tempUV2, tempUV3, uv );\r\n\r\n\t}\r\n\r\n\t// adjust the provided target or create a new one\r\n\tif ( target ) {\r\n\r\n\t\tif ( ! target.face ) target.face = { };\r\n\t\ttarget.face.a = a;\r\n\t\ttarget.face.b = b;\r\n\t\ttarget.face.c = c;\r\n\t\ttarget.face.materialIndex = materialIndex;\r\n\t\tif ( ! target.face.normal ) target.face.normal = new Vector3();\r\n\t\tTriangle.getNormal( tempV1, tempV2, tempV3, target.face.normal );\r\n\r\n\t\tif ( ! target.uv ) target.uv = new Vector2();\r\n\t\ttarget.uv.copy( uv );\r\n\r\n\t\treturn target;\r\n\r\n\t} else {\r\n\r\n\t\treturn {\r\n\t\t\tface: {\r\n\t\t\t\ta: a,\r\n\t\t\t\tb: b,\r\n\t\t\t\tc: c,\r\n\t\t\t\tmaterialIndex: materialIndex,\r\n\t\t\t\tnormal: Triangle.getNormal( tempV1, tempV2, tempV3, new Vector3() )\r\n\t\t\t},\r\n\t\t\tuv: uv\r\n\t\t};\r\n\r\n\t}\r\n\r\n}\r\n","export class PrimitivePool {\r\n\r\n\tconstructor( getNewPrimitive ) {\r\n\r\n\t\tthis._getNewPrimitive = getNewPrimitive;\r\n\t\tthis._primitives = [];\r\n\r\n\t}\r\n\r\n\tgetPrimitive() {\r\n\r\n\t\tconst primitives = this._primitives;\r\n\t\tif ( primitives.length === 0 ) {\r\n\r\n\t\t\treturn this._getNewPrimitive();\r\n\r\n\t\t} else {\r\n\r\n\t\t\treturn primitives.pop();\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\treleasePrimitive( primitive ) {\r\n\r\n\t\tthis._primitives.push( primitive );\r\n\r\n\t}\r\n\r\n}\r\n","export function IS_LEAF( n16, uint16Array ) {\r\n\r\n\treturn uint16Array[ n16 + 15 ] === 0xFFFF;\r\n\r\n}\r\n\r\nexport function OFFSET( n32, uint32Array ) {\r\n\r\n\treturn uint32Array[ n32 + 6 ];\r\n\r\n}\r\n\r\nexport function COUNT( n16, uint16Array ) {\r\n\r\n\treturn uint16Array[ n16 + 14 ];\r\n\r\n}\r\n\r\nexport function LEFT_NODE( n32 ) {\r\n\r\n\treturn n32 + 8;\r\n\r\n}\r\n\r\nexport function RIGHT_NODE( n32, uint32Array ) {\r\n\r\n\treturn uint32Array[ n32 + 6 ];\r\n\r\n}\r\n\r\nexport function SPLIT_AXIS( n32, uint32Array ) {\r\n\r\n\treturn uint32Array[ n32 + 7 ];\r\n\r\n}\r\n\r\nexport function BOUNDING_DATA_INDEX( n32 ) {\r\n\r\n\treturn n32;\r\n\r\n}\r\n","import { Box3, Vector3, Matrix4 } from 'three';\r\nimport { CONTAINED } from './Constants.js';\r\n\r\nimport { OrientedBox } from '../math/OrientedBox.js';\r\nimport { SeparatingAxisTriangle } from '../math/SeparatingAxisTriangle.js';\r\nimport { intersectTris, intersectClosestTri } from '../utils/GeometryRayIntersectUtilities.js';\r\nimport { setTriangle } from '../utils/TriangleUtilities.js';\r\nimport { arrayToBox } from '../utils/ArrayBoxUtilities.js';\r\nimport { PrimitivePool } from '../utils/PrimitivePool.js';\r\nimport { COUNT, OFFSET, LEFT_NODE, RIGHT_NODE, IS_LEAF, BOUNDING_DATA_INDEX, SPLIT_AXIS } from './nodeBufferFunctions.js';\r\n\r\nconst boundingBox = new Box3();\r\nconst boxIntersection = new Vector3();\r\nconst xyzFields = [ 'x', 'y', 'z' ];\r\n\r\nexport function raycast( nodeIndex32, geometry, side, ray, intersects ) {\r\n\r\n\tlet nodeIndex16 = nodeIndex32 * 2, float32Array = _float32Array, uint16Array = _uint16Array, uint32Array = _uint32Array;\r\n\r\n\tconst isLeaf = IS_LEAF( nodeIndex16, uint16Array );\r\n\tif ( isLeaf ) {\r\n\r\n\t\tconst offset = OFFSET( nodeIndex32, uint32Array );\r\n\t\tconst count = COUNT( nodeIndex16, uint16Array );\r\n\r\n\t\tintersectTris( geometry, side, ray, offset, count, intersects );\r\n\r\n\t} else {\r\n\r\n\t\tconst leftIndex = LEFT_NODE( nodeIndex32 );\r\n\t\tif ( intersectRay( leftIndex, float32Array, ray, boxIntersection ) ) {\r\n\r\n\t\t\traycast( leftIndex, geometry, side, ray, intersects );\r\n\r\n\t\t}\r\n\r\n\t\tconst rightIndex = RIGHT_NODE( nodeIndex32, uint32Array );\r\n\t\tif ( intersectRay( rightIndex, float32Array, ray, boxIntersection ) ) {\r\n\r\n\t\t\traycast( rightIndex, geometry, side, ray, intersects );\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n}\r\n\r\nexport function raycastFirst( nodeIndex32, geometry, side, ray ) {\r\n\r\n\tlet nodeIndex16 = nodeIndex32 * 2, float32Array = _float32Array, uint16Array = _uint16Array, uint32Array = _uint32Array;\r\n\r\n\tconst isLeaf = IS_LEAF( nodeIndex16, uint16Array );\r\n\tif ( isLeaf ) {\r\n\r\n\t\tconst offset = OFFSET( nodeIndex32, uint32Array );\r\n\t\tconst count = COUNT( nodeIndex16, uint16Array );\r\n\t\treturn intersectClosestTri( geometry, side, ray, offset, count );\r\n\r\n\t} else {\r\n\r\n\t\t// consider the position of the split plane with respect to the oncoming ray; whichever direction\r\n\t\t// the ray is coming from, look for an intersection among that side of the tree first\r\n\t\tconst splitAxis = SPLIT_AXIS( nodeIndex32, uint32Array );\r\n\t\tconst xyzAxis = xyzFields[ splitAxis ];\r\n\t\tconst rayDir = ray.direction[ xyzAxis ];\r\n\t\tconst leftToRight = rayDir >= 0;\r\n\r\n\t\t// c1 is the child to check first\r\n\t\tlet c1, c2;\r\n\t\tif ( leftToRight ) {\r\n\r\n\t\t\tc1 = LEFT_NODE( nodeIndex32 );\r\n\t\t\tc2 = RIGHT_NODE( nodeIndex32, uint32Array );\r\n\r\n\t\t} else {\r\n\r\n\t\t\tc1 = RIGHT_NODE( nodeIndex32, uint32Array );\r\n\t\t\tc2 = LEFT_NODE( nodeIndex32 );\r\n\r\n\t\t}\r\n\r\n\t\tconst c1Intersection = intersectRay( c1, float32Array, ray, boxIntersection );\r\n\t\tconst c1Result = c1Intersection ? raycastFirst( c1, geometry, side, ray ) : null;\r\n\r\n\t\t// if we got an intersection in the first node and it's closer than the second node's bounding\r\n\t\t// box, we don't need to consider the second node because it couldn't possibly be a better result\r\n\t\tif ( c1Result ) {\r\n\r\n\t\t\t// check if the point is within the second bounds\r\n\t\t\t// \"point\" is in the local frame of the bvh\r\n\t\t\tconst point = c1Result.point[ xyzAxis ];\r\n\t\t\tconst isOutside = leftToRight ?\r\n\t\t\t\tpoint <= float32Array[ c2 + splitAxis ] : // min bounding data\r\n\t\t\t\tpoint >= float32Array[ c2 + splitAxis + 3 ]; // max bounding data\r\n\r\n\t\t\tif ( isOutside ) {\r\n\r\n\t\t\t\treturn c1Result;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// either there was no intersection in the first node, or there could still be a closer\r\n\t\t// intersection in the second, so check the second node and then take the better of the two\r\n\t\tconst c2Intersection = intersectRay( c2, float32Array, ray, boxIntersection );\r\n\t\tconst c2Result = c2Intersection ? raycastFirst( c2, geometry, side, ray ) : null;\r\n\r\n\t\tif ( c1Result && c2Result ) {\r\n\r\n\t\t\treturn c1Result.distance <= c2Result.distance ? c1Result : c2Result;\r\n\r\n\t\t} else {\r\n\r\n\t\t\treturn c1Result || c2Result || null;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n}\r\n\r\nexport const shapecast = ( function () {\r\n\r\n\tlet _box1, _box2;\r\n\tconst boxStack = [];\r\n\tconst boxPool = new PrimitivePool( () => new Box3() );\r\n\r\n\treturn function shapecast( ...args ) {\r\n\r\n\t\t_box1 = boxPool.getPrimitive();\r\n\t\t_box2 = boxPool.getPrimitive();\r\n\t\tboxStack.push( _box1, _box2 );\r\n\r\n\t\tconst result = shapecastTraverse( ...args );\r\n\r\n\t\tboxPool.releasePrimitive( _box1 );\r\n\t\tboxPool.releasePrimitive( _box2 );\r\n\t\tboxStack.pop();\r\n\t\tboxStack.pop();\r\n\r\n\t\tconst length = boxStack.length;\r\n\t\tif ( length > 0 ) {\r\n\r\n\t\t\t_box2 = boxStack[ length - 1 ];\r\n\t\t\t_box1 = boxStack[ length - 2 ];\r\n\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\r\n\t};\r\n\r\n\tfunction shapecastTraverse(\r\n\t\tnodeIndex32,\r\n\t\tgeometry,\r\n\t\tintersectsBoundsFunc,\r\n\t\tintersectsRangeFunc,\r\n\t\tnodeScoreFunc = null,\r\n\t\tnodeIndexByteOffset = 0, // offset for unique node identifier\r\n\t\tdepth = 0\r\n\t) {\r\n\r\n\t\t// Define these inside the function so it has access to the local variables needed\r\n\t\t// when converting to the buffer equivalents\r\n\t\tfunction getLeftOffset( nodeIndex32 ) {\r\n\r\n\t\t\tlet nodeIndex16 = nodeIndex32 * 2, uint16Array = _uint16Array, uint32Array = _uint32Array;\r\n\r\n\t\t\t// traverse until we find a leaf\r\n\t\t\twhile ( ! IS_LEAF( nodeIndex16, uint16Array ) ) {\r\n\r\n\t\t\t\tnodeIndex32 = LEFT_NODE( nodeIndex32 );\r\n\t\t\t\tnodeIndex16 = nodeIndex32 * 2;\r\n\r\n\t\t\t}\r\n\r\n\t\t\treturn OFFSET( nodeIndex32, uint32Array );\r\n\r\n\t\t}\r\n\r\n\t\tfunction getRightEndOffset( nodeIndex32 ) {\r\n\r\n\t\t\tlet nodeIndex16 = nodeIndex32 * 2, uint16Array = _uint16Array, uint32Array = _uint32Array;\r\n\r\n\t\t\t// traverse until we find a leaf\r\n\t\t\twhile ( ! IS_LEAF( nodeIndex16, uint16Array ) ) {\r\n\r\n\t\t\t\t// adjust offset to point to the right node\r\n\t\t\t\tnodeIndex32 = RIGHT_NODE( nodeIndex32, uint32Array );\r\n\t\t\t\tnodeIndex16 = nodeIndex32 * 2;\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// return the end offset of the triangle range\r\n\t\t\treturn OFFSET( nodeIndex32, uint32Array ) + COUNT( nodeIndex16, uint16Array );\r\n\r\n\t\t}\r\n\r\n\t\tlet nodeIndex16 = nodeIndex32 * 2, float32Array = _float32Array, uint16Array = _uint16Array, uint32Array = _uint32Array;\r\n\r\n\t\tconst isLeaf = IS_LEAF( nodeIndex16, uint16Array );\r\n\t\tif ( isLeaf ) {\r\n\r\n\t\t\tconst offset = OFFSET( nodeIndex32, uint32Array );\r\n\t\t\tconst count = COUNT( nodeIndex16, uint16Array );\r\n\t\t\tarrayToBox( BOUNDING_DATA_INDEX( nodeIndex32 ), float32Array, _box1 );\r\n\t\t\treturn intersectsRangeFunc( offset, count, false, depth, nodeIndexByteOffset + nodeIndex32, _box1 );\r\n\r\n\t\t} else {\r\n\r\n\t\t\tconst left = LEFT_NODE( nodeIndex32 );\r\n\t\t\tconst right = RIGHT_NODE( nodeIndex32, uint32Array );\r\n\t\t\tlet c1 = left;\r\n\t\t\tlet c2 = right;\r\n\r\n\t\t\tlet score1, score2;\r\n\t\t\tlet box1, box2;\r\n\t\t\tif ( nodeScoreFunc ) {\r\n\r\n\t\t\t\tbox1 = _box1;\r\n\t\t\t\tbox2 = _box2;\r\n\r\n\t\t\t\t// bounding data is not offset\r\n\t\t\t\tarrayToBox( BOUNDING_DATA_INDEX( c1 ), float32Array, box1 );\r\n\t\t\t\tarrayToBox( BOUNDING_DATA_INDEX( c2 ), float32Array, box2 );\r\n\r\n\t\t\t\tscore1 = nodeScoreFunc( box1 );\r\n\t\t\t\tscore2 = nodeScoreFunc( box2 );\r\n\r\n\t\t\t\tif ( score2 < score1 ) {\r\n\r\n\t\t\t\t\tc1 = right;\r\n\t\t\t\t\tc2 = left;\r\n\r\n\t\t\t\t\tconst temp = score1;\r\n\t\t\t\t\tscore1 = score2;\r\n\t\t\t\t\tscore2 = temp;\r\n\r\n\t\t\t\t\tbox1 = box2;\r\n\t\t\t\t\t// box2 is always set before use below\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// Check box 1 intersection\r\n\t\t\tif ( ! box1 ) {\r\n\r\n\t\t\t\tbox1 = _box1;\r\n\t\t\t\tarrayToBox( BOUNDING_DATA_INDEX( c1 ), float32Array, box1 );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tconst isC1Leaf = IS_LEAF( c1 * 2, uint16Array );\r\n\t\t\tconst c1Intersection = intersectsBoundsFunc( box1, isC1Leaf, score1, depth + 1, nodeIndexByteOffset + c1 );\r\n\r\n\t\t\tlet c1StopTraversal;\r\n\t\t\tif ( c1Intersection === CONTAINED ) {\r\n\r\n\t\t\t\tconst offset = getLeftOffset( c1 );\r\n\t\t\t\tconst end = getRightEndOffset( c1 );\r\n\t\t\t\tconst count = end - offset;\r\n\r\n\t\t\t\tc1StopTraversal = intersectsRangeFunc( offset, count, true, depth + 1, nodeIndexByteOffset + c1, box1 );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tc1StopTraversal =\r\n\t\t\t\t\tc1Intersection &&\r\n\t\t\t\t\tshapecastTraverse(\r\n\t\t\t\t\t\tc1,\r\n\t\t\t\t\t\tgeometry,\r\n\t\t\t\t\t\tintersectsBoundsFunc,\r\n\t\t\t\t\t\tintersectsRangeFunc,\r\n\t\t\t\t\t\tnodeScoreFunc,\r\n\t\t\t\t\t\tnodeIndexByteOffset,\r\n\t\t\t\t\t\tdepth + 1\r\n\t\t\t\t\t);\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( c1StopTraversal ) return true;\r\n\r\n\t\t\t// Check box 2 intersection\r\n\t\t\t// cached box2 will have been overwritten by previous traversal\r\n\t\t\tbox2 = _box2;\r\n\t\t\tarrayToBox( BOUNDING_DATA_INDEX( c2 ), float32Array, box2 );\r\n\r\n\t\t\tconst isC2Leaf = IS_LEAF( c2 * 2, uint16Array );\r\n\t\t\tconst c2Intersection = intersectsBoundsFunc( box2, isC2Leaf, score2, depth + 1, nodeIndexByteOffset + c2 );\r\n\r\n\t\t\tlet c2StopTraversal;\r\n\t\t\tif ( c2Intersection === CONTAINED ) {\r\n\r\n\t\t\t\tconst offset = getLeftOffset( c2 );\r\n\t\t\t\tconst end = getRightEndOffset( c2 );\r\n\t\t\t\tconst count = end - offset;\r\n\r\n\t\t\t\tc2StopTraversal = intersectsRangeFunc( offset, count, true, depth + 1, nodeIndexByteOffset + c2, box2 );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tc2StopTraversal =\r\n\t\t\t\t\tc2Intersection &&\r\n\t\t\t\t\tshapecastTraverse(\r\n\t\t\t\t\t\tc2,\r\n\t\t\t\t\t\tgeometry,\r\n\t\t\t\t\t\tintersectsBoundsFunc,\r\n\t\t\t\t\t\tintersectsRangeFunc,\r\n\t\t\t\t\t\tnodeScoreFunc,\r\n\t\t\t\t\t\tnodeIndexByteOffset,\r\n\t\t\t\t\t\tdepth + 1\r\n\t\t\t\t\t);\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( c2StopTraversal ) return true;\r\n\r\n\t\t\treturn false;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n} )();\r\n\r\nexport const intersectsGeometry = ( function () {\r\n\r\n\tconst triangle = new SeparatingAxisTriangle();\r\n\tconst triangle2 = new SeparatingAxisTriangle();\r\n\tconst invertedMat = new Matrix4();\r\n\r\n\tconst obb = new OrientedBox();\r\n\tconst obb2 = new OrientedBox();\r\n\r\n\treturn function intersectsGeometry( nodeIndex32, geometry, otherGeometry, geometryToBvh, cachedObb = null ) {\r\n\r\n\t\tlet nodeIndex16 = nodeIndex32 * 2, float32Array = _float32Array, uint16Array = _uint16Array, uint32Array = _uint32Array;\r\n\r\n\t\tif ( cachedObb === null ) {\r\n\r\n\t\t\tif ( ! otherGeometry.boundingBox ) {\r\n\r\n\t\t\t\totherGeometry.computeBoundingBox();\r\n\r\n\t\t\t}\r\n\r\n\t\t\tobb.set( otherGeometry.boundingBox.min, otherGeometry.boundingBox.max, geometryToBvh );\r\n\t\t\tcachedObb = obb;\r\n\r\n\t\t}\r\n\r\n\t\tconst isLeaf = IS_LEAF( nodeIndex16, uint16Array );\r\n\t\tif ( isLeaf ) {\r\n\r\n\t\t\tconst thisGeometry = geometry;\r\n\t\t\tconst thisIndex = thisGeometry.index;\r\n\t\t\tconst thisPos = thisGeometry.attributes.position;\r\n\r\n\t\t\tconst index = otherGeometry.index;\r\n\t\t\tconst pos = otherGeometry.attributes.position;\r\n\r\n\t\t\tconst offset = OFFSET( nodeIndex32, uint32Array );\r\n\t\t\tconst count = COUNT( nodeIndex16, uint16Array );\r\n\r\n\t\t\t// get the inverse of the geometry matrix so we can transform our triangles into the\r\n\t\t\t// geometry space we're trying to test. We assume there are fewer triangles being checked\r\n\t\t\t// here.\r\n\t\t\tinvertedMat.copy( geometryToBvh ).invert();\r\n\r\n\t\t\tif ( otherGeometry.boundsTree ) {\r\n\r\n\t\t\t\tarrayToBox( BOUNDING_DATA_INDEX( nodeIndex32 ), float32Array, obb2 );\r\n\t\t\t\tobb2.matrix.copy( invertedMat );\r\n\t\t\t\tobb2.needsUpdate = true;\r\n\r\n\t\t\t\tconst res = otherGeometry.boundsTree.shapecast( {\r\n\r\n\t\t\t\t\tintersectsBounds: box => obb2.intersectsBox( box ),\r\n\r\n\t\t\t\t\tintersectsTriangle: tri => {\r\n\r\n\t\t\t\t\t\ttri.a.applyMatrix4( geometryToBvh );\r\n\t\t\t\t\t\ttri.b.applyMatrix4( geometryToBvh );\r\n\t\t\t\t\t\ttri.c.applyMatrix4( geometryToBvh );\r\n\t\t\t\t\t\ttri.needsUpdate = true;\r\n\r\n\t\t\t\t\t\tfor ( let i = offset * 3, l = ( count + offset ) * 3; i < l; i += 3 ) {\r\n\r\n\t\t\t\t\t\t\t// this triangle needs to be transformed into the current BVH coordinate frame\r\n\t\t\t\t\t\t\tsetTriangle( triangle2, i, thisIndex, thisPos );\r\n\t\t\t\t\t\t\ttriangle2.needsUpdate = true;\r\n\t\t\t\t\t\t\tif ( tri.intersectsTriangle( triangle2 ) ) {\r\n\r\n\t\t\t\t\t\t\t\treturn true;\r\n\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\treturn false;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} );\r\n\r\n\t\t\t\treturn res;\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tfor ( let i = offset * 3, l = ( count + offset * 3 ); i < l; i += 3 ) {\r\n\r\n\t\t\t\t\t// this triangle needs to be transformed into the current BVH coordinate frame\r\n\t\t\t\t\tsetTriangle( triangle, i, thisIndex, thisPos );\r\n\t\t\t\t\ttriangle.a.applyMatrix4( invertedMat );\r\n\t\t\t\t\ttriangle.b.applyMatrix4( invertedMat );\r\n\t\t\t\t\ttriangle.c.applyMatrix4( invertedMat );\r\n\t\t\t\t\ttriangle.needsUpdate = true;\r\n\r\n\t\t\t\t\tfor ( let i2 = 0, l2 = index.count; i2 < l2; i2 += 3 ) {\r\n\r\n\t\t\t\t\t\tsetTriangle( triangle2, i2, index, pos );\r\n\t\t\t\t\t\ttriangle2.needsUpdate = true;\r\n\r\n\t\t\t\t\t\tif ( triangle.intersectsTriangle( triangle2 ) ) {\r\n\r\n\t\t\t\t\t\t\treturn true;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\r\n\t\t\tconst left = nodeIndex32 + 8;\r\n\t\t\tconst right = uint32Array[ nodeIndex32 + 6 ];\r\n\r\n\t\t\tarrayToBox( BOUNDING_DATA_INDEX( left ), float32Array, boundingBox );\r\n\t\t\tconst leftIntersection =\r\n\t\t\t\tcachedObb.intersectsBox( boundingBox ) &&\r\n\t\t\t\tintersectsGeometry( left, geometry, otherGeometry, geometryToBvh, cachedObb );\r\n\r\n\t\t\tif ( leftIntersection ) return true;\r\n\r\n\t\t\tarrayToBox( BOUNDING_DATA_INDEX( right ), float32Array, boundingBox );\r\n\t\t\tconst rightIntersection =\r\n\t\t\t\tcachedObb.intersectsBox( boundingBox ) &&\r\n\t\t\t\tintersectsGeometry( right, geometry, otherGeometry, geometryToBvh, cachedObb );\r\n\r\n\t\t\tif ( rightIntersection ) return true;\r\n\r\n\t\t\treturn false;\r\n\r\n\t\t}\r\n\r\n\t};\r\n\r\n} )();\r\n\r\nfunction intersectRay( nodeIndex32, array, ray, target ) {\r\n\r\n\tarrayToBox( nodeIndex32, array, boundingBox );\r\n\treturn ray.intersectBox( boundingBox, target );\r\n\r\n}\r\n\r\nconst bufferStack = [];\r\nlet _prevBuffer;\r\nlet _float32Array;\r\nlet _uint16Array;\r\nlet _uint32Array;\r\nexport function setBuffer( buffer ) {\r\n\r\n\tif ( _prevBuffer ) {\r\n\r\n\t\tbufferStack.push( _prevBuffer );\r\n\r\n\t}\r\n\r\n\t_prevBuffer = buffer;\r\n\t_float32Array = new Float32Array( buffer );\r\n\t_uint16Array = new Uint16Array( buffer );\r\n\t_uint32Array = new Uint32Array( buffer );\r\n\r\n}\r\n\r\nexport function clearBuffer() {\r\n\r\n\t_prevBuffer = null;\r\n\t_float32Array = null;\r\n\t_uint16Array = null;\r\n\t_uint32Array = null;\r\n\r\n\tif ( bufferStack.length ) {\r\n\r\n\t\tsetBuffer( bufferStack.pop() );\r\n\r\n\t}\r\n\r\n}\r\n","import { Vector3, BufferAttribute, Box3, FrontSide, Matrix4 } from 'three';\r\nimport { CENTER, BYTES_PER_NODE, IS_LEAFNODE_FLAG } from './Constants.js';\r\nimport { buildPackedTree } from './buildFunctions.js';\r\nimport {\r\n\traycast,\r\n\traycastFirst,\r\n\tshapecast,\r\n\tintersectsGeometry,\r\n\tsetBuffer,\r\n\tclearBuffer,\r\n} from './castFunctions.js';\r\nimport { OrientedBox } from '../math/OrientedBox.js';\r\nimport { SeparatingAxisTriangle } from '../math/SeparatingAxisTriangle.js';\r\nimport { PrimitivePool } from '../utils/PrimitivePool.js';\r\nimport { arrayToBox } from '../utils/ArrayBoxUtilities.js';\r\nimport { iterateOverTriangles, setTriangle } from '../utils/TriangleUtilities.js';\r\nimport { convertRaycastIntersect } from '../utils/GeometryRayIntersectUtilities.js';\r\n\r\nconst SKIP_GENERATION = Symbol( 'skip tree generation' );\r\n\r\nconst aabb = /* @__PURE__ */ new Box3();\r\nconst aabb2 = /* @__PURE__ */ new Box3();\r\nconst tempMatrix = /* @__PURE__ */ new Matrix4();\r\nconst obb = /* @__PURE__ */ new OrientedBox();\r\nconst obb2 = /* @__PURE__ */ new OrientedBox();\r\nconst temp = /* @__PURE__ */ new Vector3();\r\nconst temp1 = /* @__PURE__ */ new Vector3();\r\nconst temp2 = /* @__PURE__ */ new Vector3();\r\nconst temp3 = /* @__PURE__ */ new Vector3();\r\nconst temp4 = /* @__PURE__ */ new Vector3();\r\nconst tempBox = /* @__PURE__ */ new Box3();\r\nconst trianglePool = /* @__PURE__ */ new PrimitivePool( () => new SeparatingAxisTriangle() );\r\n\r\nexport class MeshBVH {\r\n\r\n\tstatic serialize( bvh, options = {} ) {\r\n\r\n\t\tif ( options.isBufferGeometry ) {\r\n\r\n\t\t\tconsole.warn( 'MeshBVH.serialize: The arguments for the function have changed. See documentation for new signature.' );\r\n\r\n\t\t\treturn MeshBVH.serialize(\r\n\t\t\t\targuments[ 0 ],\r\n\t\t\t\t{\r\n\t\t\t\t\tcloneBuffers: arguments[ 2 ] === undefined ? true : arguments[ 2 ],\r\n\t\t\t\t}\r\n\t\t\t);\r\n\r\n\t\t}\r\n\r\n\t\toptions = {\r\n\t\t\tcloneBuffers: true,\r\n\t\t\t...options,\r\n\t\t};\r\n\r\n\t\tconst geometry = bvh.geometry;\r\n\t\tconst rootData = bvh._roots;\r\n\t\tconst indexAttribute = geometry.getIndex();\r\n\t\tlet result;\r\n\t\tif ( options.cloneBuffers ) {\r\n\r\n\t\t\tresult = {\r\n\t\t\t\troots: rootData.map( root => root.slice() ),\r\n\t\t\t\tindex: indexAttribute.array.slice(),\r\n\t\t\t};\r\n\r\n\t\t} else {\r\n\r\n\t\t\tresult = {\r\n\t\t\t\troots: rootData,\r\n\t\t\t\tindex: indexAttribute.array,\r\n\t\t\t};\r\n\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\r\n\t}\r\n\r\n\tstatic deserialize( data, geometry, options = {} ) {\r\n\r\n\t\tif ( typeof options === 'boolean' ) {\r\n\r\n\t\t\tconsole.warn( 'MeshBVH.deserialize: The arguments for the function have changed. See documentation for new signature.' );\r\n\r\n\t\t\treturn MeshBVH.deserialize(\r\n\t\t\t\targuments[ 0 ],\r\n\t\t\t\targuments[ 1 ],\r\n\t\t\t\t{\r\n\t\t\t\t\tsetIndex: arguments[ 2 ] === undefined ? true : arguments[ 2 ],\r\n\t\t\t\t}\r\n\t\t\t);\r\n\r\n\t\t}\r\n\r\n\t\toptions = {\r\n\t\t\tsetIndex: true,\r\n\t\t\t...options,\r\n\t\t};\r\n\r\n\t\tconst { index, roots } = data;\r\n\t\tconst bvh = new MeshBVH( geometry, { ...options, [ SKIP_GENERATION ]: true } );\r\n\t\tbvh._roots = roots;\r\n\r\n\t\tif ( options.setIndex ) {\r\n\r\n\t\t\tconst indexAttribute = geometry.getIndex();\r\n\t\t\tif ( indexAttribute === null ) {\r\n\r\n\t\t\t\tconst newIndex = new BufferAttribute( data.index, 1, false );\r\n\t\t\t\tgeometry.setIndex( newIndex );\r\n\r\n\t\t\t} else if ( indexAttribute.array !== index ) {\r\n\r\n\t\t\t\tindexAttribute.array.set( index );\r\n\t\t\t\tindexAttribute.needsUpdate = true;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn bvh;\r\n\r\n\t}\r\n\r\n\tconstructor( geometry, options = {} ) {\r\n\r\n\t\tif ( ! geometry.isBufferGeometry ) {\r\n\r\n\t\t\tthrow new Error( 'MeshBVH: Only BufferGeometries are supported.' );\r\n\r\n\t\t} else if ( geometry.index && geometry.index.isInterleavedBufferAttribute ) {\r\n\r\n\t\t\tthrow new Error( 'MeshBVH: InterleavedBufferAttribute is not supported for the index attribute.' );\r\n\r\n\t\t}\r\n\r\n\t\t// default options\r\n\t\toptions = Object.assign( {\r\n\r\n\t\t\tstrategy: CENTER,\r\n\t\t\tmaxDepth: 40,\r\n\t\t\tmaxLeafTris: 10,\r\n\t\t\tverbose: true,\r\n\t\t\tuseSharedArrayBuffer: false,\r\n\t\t\tsetBoundingBox: true,\r\n\t\t\tonProgress: null,\r\n\r\n\t\t\t// undocumented options\r\n\r\n\t\t\t// Whether to skip generating the tree. Used for deserialization.\r\n\t\t\t[ SKIP_GENERATION ]: false,\r\n\r\n\t\t}, options );\r\n\r\n\t\tif ( options.useSharedArrayBuffer && typeof SharedArrayBuffer === 'undefined' ) {\r\n\r\n\t\t\tthrow new Error( 'MeshBVH: SharedArrayBuffer is not available.' );\r\n\r\n\t\t}\r\n\r\n\t\tthis._roots = null;\r\n\t\tif ( ! options[ SKIP_GENERATION ] ) {\r\n\r\n\t\t\tthis._roots = buildPackedTree( geometry, options );\r\n\r\n\t\t\tif ( ! geometry.boundingBox && options.setBoundingBox ) {\r\n\r\n\t\t\t\tgeometry.boundingBox = this.getBoundingBox( new Box3() );\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// retain references to the geometry so we can use them it without having to\r\n\t\t// take a geometry reference in every function.\r\n\t\tthis.geometry = geometry;\r\n\r\n\t}\r\n\r\n\trefit( nodeIndices = null ) {\r\n\r\n\t\tif ( nodeIndices && Array.isArray( nodeIndices ) ) {\r\n\r\n\t\t\tnodeIndices = new Set( nodeIndices );\r\n\r\n\t\t}\r\n\r\n\t\tconst geometry = this.geometry;\r\n\t\tconst indexArr = geometry.index.array;\r\n\t\tconst posAttr = geometry.attributes.position;\r\n\t\tconst posArr = posAttr.array;\r\n\r\n\t\t// support for an interleaved position buffer\r\n\t\tconst bufferOffset = posAttr.offset || 0;\r\n\t\tlet stride = 3;\r\n\t\tif ( posAttr.isInterleavedBufferAttribute ) {\r\n\r\n\t\t\tstride = posAttr.data.stride;\r\n\r\n\t\t}\r\n\r\n\t\tlet buffer, uint32Array, uint16Array, float32Array;\r\n\t\tlet byteOffset = 0;\r\n\t\tconst roots = this._roots;\r\n\t\tfor ( let i = 0, l = roots.length; i < l; i ++ ) {\r\n\r\n\t\t\tbuffer = roots[ i ];\r\n\t\t\tuint32Array = new Uint32Array( buffer );\r\n\t\t\tuint16Array = new Uint16Array( buffer );\r\n\t\t\tfloat32Array = new Float32Array( buffer );\r\n\r\n\t\t\t_traverse( 0, byteOffset );\r\n\t\t\tbyteOffset += buffer.byteLength;\r\n\r\n\t\t}\r\n\r\n\t\tfunction _traverse( node32Index, byteOffset, force = false ) {\r\n\r\n\t\t\tconst node16Index = node32Index * 2;\r\n\t\t\tconst isLeaf = uint16Array[ node16Index + 15 ] === IS_LEAFNODE_FLAG;\r\n\t\t\tif ( isLeaf ) {\r\n\r\n\t\t\t\tconst offset = uint32Array[ node32Index + 6 ];\r\n\t\t\t\tconst count = uint16Array[ node16Index + 14 ];\r\n\r\n\t\t\t\tlet minx = Infinity;\r\n\t\t\t\tlet miny = Infinity;\r\n\t\t\t\tlet minz = Infinity;\r\n\t\t\t\tlet maxx = - Infinity;\r\n\t\t\t\tlet maxy = - Infinity;\r\n\t\t\t\tlet maxz = - Infinity;\r\n\t\t\t\tfor ( let i = 3 * offset, l = 3 * ( offset + count ); i < l; i ++ ) {\r\n\r\n\t\t\t\t\tconst index = indexArr[ i ] * stride + bufferOffset;\r\n\t\t\t\t\tconst x = posArr[ index + 0 ];\r\n\t\t\t\t\tconst y = posArr[ index + 1 ];\r\n\t\t\t\t\tconst z = posArr[ index + 2 ];\r\n\r\n\t\t\t\t\tif ( x < minx ) minx = x;\r\n\t\t\t\t\tif ( x > maxx ) maxx = x;\r\n\r\n\t\t\t\t\tif ( y < miny ) miny = y;\r\n\t\t\t\t\tif ( y > maxy ) maxy = y;\r\n\r\n\t\t\t\t\tif ( z < minz ) minz = z;\r\n\t\t\t\t\tif ( z > maxz ) maxz = z;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (\r\n\t\t\t\t\tfloat32Array[ node32Index + 0 ] !== minx ||\r\n\t\t\t\t\tfloat32Array[ node32Index + 1 ] !== miny ||\r\n\t\t\t\t\tfloat32Array[ node32Index + 2 ] !== minz ||\r\n\r\n\t\t\t\t\tfloat32Array[ node32Index + 3 ] !== maxx ||\r\n\t\t\t\t\tfloat32Array[ node32Index + 4 ] !== maxy ||\r\n\t\t\t\t\tfloat32Array[ node32Index + 5 ] !== maxz\r\n\t\t\t\t) {\r\n\r\n\t\t\t\t\tfloat32Array[ node32Index + 0 ] = minx;\r\n\t\t\t\t\tfloat32Array[ node32Index + 1 ] = miny;\r\n\t\t\t\t\tfloat32Array[ node32Index + 2 ] = minz;\r\n\r\n\t\t\t\t\tfloat32Array[ node32Index + 3 ] = maxx;\r\n\t\t\t\t\tfloat32Array[ node32Index + 4 ] = maxy;\r\n\t\t\t\t\tfloat32Array[ node32Index + 5 ] = maxz;\r\n\r\n\t\t\t\t\treturn true;\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\treturn false;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tconst left = node32Index + 8;\r\n\t\t\t\tconst right = uint32Array[ node32Index + 6 ];\r\n\r\n\t\t\t\t// the identifying node indices provided by the shapecast function include offsets of all\r\n\t\t\t\t// root buffers to guarantee they're unique between roots so offset left and right indices here.\r\n\t\t\t\tconst offsetLeft = left + byteOffset;\r\n\t\t\t\tconst offsetRight = right + byteOffset;\r\n\t\t\t\tlet forceChildren = force;\r\n\t\t\t\tlet includesLeft = false;\r\n\t\t\t\tlet includesRight = false;\r\n\r\n\t\t\t\tif ( nodeIndices ) {\r\n\r\n\t\t\t\t\t// if we see that neither the left or right child are included in the set that need to be updated\r\n\t\t\t\t\t// then we assume that all children need to be updated.\r\n\t\t\t\t\tif ( ! forceChildren ) {\r\n\r\n\t\t\t\t\t\tincludesLeft = nodeIndices.has( offsetLeft );\r\n\t\t\t\t\t\tincludesRight = nodeIndices.has( offsetRight );\r\n\t\t\t\t\t\tforceChildren = ! includesLeft && ! includesRight;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tincludesLeft = true;\r\n\t\t\t\t\tincludesRight = true;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst traverseLeft = forceChildren || includesLeft;\r\n\t\t\t\tconst traverseRight = forceChildren || includesRight;\r\n\r\n\t\t\t\tlet leftChange = false;\r\n\t\t\t\tif ( traverseLeft ) {\r\n\r\n\t\t\t\t\tleftChange = _traverse( left, byteOffset, forceChildren );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tlet rightChange = false;\r\n\t\t\t\tif ( traverseRight ) {\r\n\r\n\t\t\t\t\trightChange = _traverse( right, byteOffset, forceChildren );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst didChange = leftChange || rightChange;\r\n\t\t\t\tif ( didChange ) {\r\n\r\n\t\t\t\t\tfor ( let i = 0; i < 3; i ++ ) {\r\n\r\n\t\t\t\t\t\tconst lefti = left + i;\r\n\t\t\t\t\t\tconst righti = right + i;\r\n\t\t\t\t\t\tconst minLeftValue = float32Array[ lefti ];\r\n\t\t\t\t\t\tconst maxLeftValue = float32Array[ lefti + 3 ];\r\n\t\t\t\t\t\tconst minRightValue = float32Array[ righti ];\r\n\t\t\t\t\t\tconst maxRightValue = float32Array[ righti + 3 ];\r\n\r\n\t\t\t\t\t\tfloat32Array[ node32Index + i ] = minLeftValue < minRightValue ? minLeftValue : minRightValue;\r\n\t\t\t\t\t\tfloat32Array[ node32Index + i + 3 ] = maxLeftValue > maxRightValue ? maxLeftValue : maxRightValue;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn didChange;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\ttraverse( callback, rootIndex = 0 ) {\r\n\r\n\t\tconst buffer = this._roots[ rootIndex ];\r\n\t\tconst uint32Array = new Uint32Array( buffer );\r\n\t\tconst uint16Array = new Uint16Array( buffer );\r\n\t\t_traverse( 0 );\r\n\r\n\t\tfunction _traverse( node32Index, depth = 0 ) {\r\n\r\n\t\t\tconst node16Index = node32Index * 2;\r\n\t\t\tconst isLeaf = uint16Array[ node16Index + 15 ] === IS_LEAFNODE_FLAG;\r\n\t\t\tif ( isLeaf ) {\r\n\r\n\t\t\t\tconst offset = uint32Array[ node32Index + 6 ];\r\n\t\t\t\tconst count = uint16Array[ node16Index + 14 ];\r\n\t\t\t\tcallback( depth, isLeaf, new Float32Array( buffer, node32Index * 4, 6 ), offset, count );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\t// TODO: use node functions here\r\n\t\t\t\tconst left = node32Index + BYTES_PER_NODE / 4;\r\n\t\t\t\tconst right = uint32Array[ node32Index + 6 ];\r\n\t\t\t\tconst splitAxis = uint32Array[ node32Index + 7 ];\r\n\t\t\t\tconst stopTraversal = callback( depth, isLeaf, new Float32Array( buffer, node32Index * 4, 6 ), splitAxis );\r\n\r\n\t\t\t\tif ( ! stopTraversal ) {\r\n\r\n\t\t\t\t\t_traverse( left, depth + 1 );\r\n\t\t\t\t\t_traverse( right, depth + 1 );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/* Core Cast Functions */\r\n\traycast( ray, materialOrSide = FrontSide ) {\r\n\r\n\t\tconst roots = this._roots;\r\n\t\tconst geometry = this.geometry;\r\n\t\tconst intersects = [];\r\n\t\tconst isMaterial = materialOrSide.isMaterial;\r\n\t\tconst isArrayMaterial = Array.isArray( materialOrSide );\r\n\r\n\t\tconst groups = geometry.groups;\r\n\t\tconst side = isMaterial ? materialOrSide.side : materialOrSide;\r\n\t\tfor ( let i = 0, l = roots.length; i < l; i ++ ) {\r\n\r\n\t\t\tconst materialSide = isArrayMaterial ? materialOrSide[ groups[ i ].materialIndex ].side : side;\r\n\t\t\tconst startCount = intersects.length;\r\n\r\n\t\t\tsetBuffer( roots[ i ] );\r\n\t\t\traycast( 0, geometry, materialSide, ray, intersects );\r\n\t\t\tclearBuffer();\r\n\r\n\t\t\tif ( isArrayMaterial ) {\r\n\r\n\t\t\t\tconst materialIndex = groups[ i ].materialIndex;\r\n\t\t\t\tfor ( let j = startCount, jl = intersects.length; j < jl; j ++ ) {\r\n\r\n\t\t\t\t\tintersects[ j ].face.materialIndex = materialIndex;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn intersects;\r\n\r\n\t}\r\n\r\n\traycastFirst( ray, materialOrSide = FrontSide ) {\r\n\r\n\t\tconst roots = this._roots;\r\n\t\tconst geometry = this.geometry;\r\n\t\tconst isMaterial = materialOrSide.isMaterial;\r\n\t\tconst isArrayMaterial = Array.isArray( materialOrSide );\r\n\r\n\t\tlet closestResult = null;\r\n\r\n\t\tconst groups = geometry.groups;\r\n\t\tconst side = isMaterial ? materialOrSide.side : materialOrSide;\r\n\t\tfor ( let i = 0, l = roots.length; i < l; i ++ ) {\r\n\r\n\t\t\tconst materialSide = isArrayMaterial ? materialOrSide[ groups[ i ].materialIndex ].side : side;\r\n\r\n\t\t\tsetBuffer( roots[ i ] );\r\n\t\t\tconst result = raycastFirst( 0, geometry, materialSide, ray );\r\n\t\t\tclearBuffer();\r\n\r\n\t\t\tif ( result != null && ( closestResult == null || result.distance < closestResult.distance ) ) {\r\n\r\n\t\t\t\tclosestResult = result;\r\n\t\t\t\tif ( isArrayMaterial ) {\r\n\r\n\t\t\t\t\tresult.face.materialIndex = groups[ i ].materialIndex;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn closestResult;\r\n\r\n\t}\r\n\r\n\tintersectsGeometry( otherGeometry, geomToMesh ) {\r\n\r\n\t\tconst geometry = this.geometry;\r\n\t\tlet result = false;\r\n\t\tfor ( const root of this._roots ) {\r\n\r\n\t\t\tsetBuffer( root );\r\n\t\t\tresult = intersectsGeometry( 0, geometry, otherGeometry, geomToMesh );\r\n\t\t\tclearBuffer();\r\n\r\n\t\t\tif ( result ) {\r\n\r\n\t\t\t\tbreak;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\treturn result;\r\n\r\n\t}\r\n\r\n\tshapecast( callbacks, _intersectsTriangleFunc, _orderNodesFunc ) {\r\n\r\n\t\tconst geometry = this.geometry;\r\n\t\tif ( callbacks instanceof Function ) {\r\n\r\n\t\t\tif ( _intersectsTriangleFunc ) {\r\n\r\n\t\t\t\t// Support the previous function signature that provided three sequential index buffer\r\n\t\t\t\t// indices here.\r\n\t\t\t\tconst originalTriangleFunc = _intersectsTriangleFunc;\r\n\t\t\t\t_intersectsTriangleFunc = ( tri, index, contained, depth ) => {\r\n\r\n\t\t\t\t\tconst i3 = index * 3;\r\n\t\t\t\t\treturn originalTriangleFunc( tri, i3, i3 + 1, i3 + 2, contained, depth );\r\n\r\n\t\t\t\t};\r\n\r\n\r\n\t\t\t}\r\n\r\n\t\t\tcallbacks = {\r\n\r\n\t\t\t\tboundsTraverseOrder: _orderNodesFunc,\r\n\t\t\t\tintersectsBounds: callbacks,\r\n\t\t\t\tintersectsTriangle: _intersectsTriangleFunc,\r\n\t\t\t\tintersectsRange: null,\r\n\r\n\t\t\t};\r\n\r\n\t\t\tconsole.warn( 'MeshBVH: Shapecast function signature has changed and now takes an object of callbacks as a second argument. See docs for new signature.' );\r\n\r\n\t\t}\r\n\r\n\t\tconst triangle = trianglePool.getPrimitive();\r\n\t\tlet {\r\n\t\t\tboundsTraverseOrder,\r\n\t\t\tintersectsBounds,\r\n\t\t\tintersectsRange,\r\n\t\t\tintersectsTriangle,\r\n\t\t} = callbacks;\r\n\r\n\t\tif ( intersectsRange && intersectsTriangle ) {\r\n\r\n\t\t\tconst originalIntersectsRange = intersectsRange;\r\n\t\t\tintersectsRange = ( offset, count, contained, depth, nodeIndex ) => {\r\n\r\n\t\t\t\tif ( ! originalIntersectsRange( offset, count, contained, depth, nodeIndex ) ) {\r\n\r\n\t\t\t\t\treturn iterateOverTriangles( offset, count, geometry, intersectsTriangle, contained, depth, triangle );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn true;\r\n\r\n\t\t\t};\r\n\r\n\t\t} else if ( ! intersectsRange ) {\r\n\r\n\t\t\tif ( intersectsTriangle ) {\r\n\r\n\t\t\t\tintersectsRange = ( offset, count, contained, depth ) => {\r\n\r\n\t\t\t\t\treturn iterateOverTriangles( offset, count, geometry, intersectsTriangle, contained, depth, triangle );\r\n\r\n\t\t\t\t};\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tintersectsRange = ( offset, count, contained ) => {\r\n\r\n\t\t\t\t\treturn contained;\r\n\r\n\t\t\t\t};\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tlet result = false;\r\n\t\tlet byteOffset = 0;\r\n\t\tfor ( const root of this._roots ) {\r\n\r\n\t\t\tsetBuffer( root );\r\n\t\t\tresult = shapecast( 0, geometry, intersectsBounds, intersectsRange, boundsTraverseOrder, byteOffset );\r\n\t\t\tclearBuffer();\r\n\r\n\t\t\tif ( result ) {\r\n\r\n\t\t\t\tbreak;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tbyteOffset += root.byteLength;\r\n\r\n\t\t}\r\n\r\n\t\ttrianglePool.releasePrimitive( triangle );\r\n\r\n\t\treturn result;\r\n\r\n\t}\r\n\r\n\tbvhcast( otherBvh, matrixToLocal, callbacks ) {\r\n\r\n\t\t// BVHCast function for intersecting two BVHs against each other. Ultimately just uses two recursive shapecast calls rather\r\n\t\t// than an approach that walks down the tree (see bvhcast.js file for more info).\r\n\r\n\t\tlet {\r\n\t\t\tintersectsRanges,\r\n\t\t\tintersectsTriangles,\r\n\t\t} = callbacks;\r\n\r\n\t\tconst indexAttr = this.geometry.index;\r\n\t\tconst positionAttr = this.geometry.attributes.position;\r\n\r\n\t\tconst otherIndexAttr = otherBvh.geometry.index;\r\n\t\tconst otherPositionAttr = otherBvh.geometry.attributes.position;\r\n\r\n\t\ttempMatrix.copy( matrixToLocal ).invert();\r\n\r\n\t\tconst triangle = trianglePool.getPrimitive();\r\n\t\tconst triangle2 = trianglePool.getPrimitive();\r\n\r\n\t\tif ( intersectsTriangles ) {\r\n\r\n\t\t\tfunction iterateOverDoubleTriangles( offset1, count1, offset2, count2, depth1, index1, depth2, index2 ) {\r\n\r\n\t\t\t\tfor ( let i2 = offset2, l2 = offset2 + count2; i2 < l2; i2 ++ ) {\r\n\r\n\t\t\t\t\tsetTriangle( triangle2, i2 * 3, otherIndexAttr, otherPositionAttr );\r\n\t\t\t\t\ttriangle2.a.applyMatrix4( matrixToLocal );\r\n\t\t\t\t\ttriangle2.b.applyMatrix4( matrixToLocal );\r\n\t\t\t\t\ttriangle2.c.applyMatrix4( matrixToLocal );\r\n\t\t\t\t\ttriangle2.needsUpdate = true;\r\n\r\n\t\t\t\t\tfor ( let i1 = offset1, l1 = offset1 + count1; i1 < l1; i1 ++ ) {\r\n\r\n\t\t\t\t\t\tsetTriangle( triangle, i1 * 3, indexAttr, positionAttr );\r\n\t\t\t\t\t\ttriangle.needsUpdate = true;\r\n\r\n\t\t\t\t\t\tif ( intersectsTriangles( triangle, triangle2, i1, i2, depth1, index1, depth2, index2 ) ) {\r\n\r\n\t\t\t\t\t\t\treturn true;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn false;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( intersectsRanges ) {\r\n\r\n\t\t\t\tconst originalIntersectsRanges = intersectsRanges;\r\n\t\t\t\tintersectsRanges = function ( offset1, count1, offset2, count2, depth1, index1, depth2, index2 ) {\r\n\r\n\t\t\t\t\tif ( ! originalIntersectsRanges( offset1, count1, offset2, count2, depth1, index1, depth2, index2 ) ) {\r\n\r\n\t\t\t\t\t\treturn iterateOverDoubleTriangles( offset1, count1, offset2, count2, depth1, index1, depth2, index2 );\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\treturn true;\r\n\r\n\t\t\t\t};\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tintersectsRanges = iterateOverDoubleTriangles;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tthis.getBoundingBox( aabb2 );\r\n\t\taabb2.applyMatrix4( matrixToLocal );\r\n\t\tconst result = this.shapecast( {\r\n\r\n\t\t\tintersectsBounds: box => aabb2.intersectsBox( box ),\r\n\r\n\t\t\tintersectsRange: ( offset1, count1, contained, depth1, nodeIndex1, box ) => {\r\n\r\n\t\t\t\taabb.copy( box );\r\n\t\t\t\taabb.applyMatrix4( tempMatrix );\r\n\t\t\t\treturn otherBvh.shapecast( {\r\n\r\n\t\t\t\t\tintersectsBounds: box => aabb.intersectsBox( box ),\r\n\r\n\t\t\t\t\tintersectsRange: ( offset2, count2, contained, depth2, nodeIndex2 ) => {\r\n\r\n\t\t\t\t\t\treturn intersectsRanges( offset1, count1, offset2, count2, depth1, nodeIndex1, depth2, nodeIndex2 );\r\n\r\n\t\t\t\t\t},\r\n\r\n\t\t\t\t} );\r\n\r\n\t\t\t}\r\n\r\n\t\t} );\r\n\r\n\t\ttrianglePool.releasePrimitive( triangle );\r\n\t\ttrianglePool.releasePrimitive( triangle2 );\r\n\t\treturn result;\r\n\r\n\t}\r\n\r\n\t/* Derived Cast Functions */\r\n\tintersectsBox( box, boxToMesh ) {\r\n\r\n\t\tobb.set( box.min, box.max, boxToMesh );\r\n\t\tobb.needsUpdate = true;\r\n\r\n\t\treturn this.shapecast(\r\n\t\t\t{\r\n\t\t\t\tintersectsBounds: box => obb.intersectsBox( box ),\r\n\t\t\t\tintersectsTriangle: tri => obb.intersectsTriangle( tri )\r\n\t\t\t}\r\n\t\t);\r\n\r\n\t}\r\n\r\n\tintersectsSphere( sphere ) {\r\n\r\n\t\treturn this.shapecast(\r\n\t\t\t{\r\n\t\t\t\tintersectsBounds: box => sphere.intersectsBox( box ),\r\n\t\t\t\tintersectsTriangle: tri => tri.intersectsSphere( sphere )\r\n\t\t\t}\r\n\t\t);\r\n\r\n\t}\r\n\r\n\tclosestPointToGeometry( otherGeometry, geometryToBvh, target1 = { }, target2 = { }, minThreshold = 0, maxThreshold = Infinity ) {\r\n\r\n\t\tif ( ! otherGeometry.boundingBox ) {\r\n\r\n\t\t\totherGeometry.computeBoundingBox();\r\n\r\n\t\t}\r\n\r\n\t\tobb.set( otherGeometry.boundingBox.min, otherGeometry.boundingBox.max, geometryToBvh );\r\n\t\tobb.needsUpdate = true;\r\n\r\n\t\tconst geometry = this.geometry;\r\n\t\tconst pos = geometry.attributes.position;\r\n\t\tconst index = geometry.index;\r\n\t\tconst otherPos = otherGeometry.attributes.position;\r\n\t\tconst otherIndex = otherGeometry.index;\r\n\t\tconst triangle = trianglePool.getPrimitive();\r\n\t\tconst triangle2 = trianglePool.getPrimitive();\r\n\r\n\t\tlet tempTarget1 = temp1;\r\n\t\tlet tempTargetDest1 = temp2;\r\n\t\tlet tempTarget2 = null;\r\n\t\tlet tempTargetDest2 = null;\r\n\r\n\t\tif ( target2 ) {\r\n\r\n\t\t\ttempTarget2 = temp3;\r\n\t\t\ttempTargetDest2 = temp4;\r\n\r\n\t\t}\r\n\r\n\t\tlet closestDistance = Infinity;\r\n\t\tlet closestDistanceTriIndex = null;\r\n\t\tlet closestDistanceOtherTriIndex = null;\r\n\t\ttempMatrix.copy( geometryToBvh ).invert();\r\n\t\tobb2.matrix.copy( tempMatrix );\r\n\t\tthis.shapecast(\r\n\t\t\t{\r\n\r\n\t\t\t\tboundsTraverseOrder: box => {\r\n\r\n\t\t\t\t\treturn obb.distanceToBox( box, Math.min( closestDistance, maxThreshold ) );\r\n\r\n\t\t\t\t},\r\n\r\n\t\t\t\tintersectsBounds: ( box, isLeaf, score ) => {\r\n\r\n\t\t\t\t\tif ( score < closestDistance && score < maxThreshold ) {\r\n\r\n\t\t\t\t\t\t// if we know the triangles of this bounds will be intersected next then\r\n\t\t\t\t\t\t// save the bounds to use during triangle checks.\r\n\t\t\t\t\t\tif ( isLeaf ) {\r\n\r\n\t\t\t\t\t\t\tobb2.min.copy( box.min );\r\n\t\t\t\t\t\t\tobb2.max.copy( box.max );\r\n\t\t\t\t\t\t\tobb2.needsUpdate = true;\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\treturn true;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\treturn false;\r\n\r\n\t\t\t\t},\r\n\r\n\t\t\t\tintersectsRange: ( offset, count ) => {\r\n\r\n\t\t\t\t\tif ( otherGeometry.boundsTree ) {\r\n\r\n\t\t\t\t\t\t// if the other geometry has a bvh then use the accelerated path where we use shapecast to find\r\n\t\t\t\t\t\t// the closest bounds in the other geometry to check.\r\n\t\t\t\t\t\treturn otherGeometry.boundsTree.shapecast( {\r\n\t\t\t\t\t\t\tboundsTraverseOrder: box => {\r\n\r\n\t\t\t\t\t\t\t\treturn obb2.distanceToBox( box, Math.min( closestDistance, maxThreshold ) );\r\n\r\n\t\t\t\t\t\t\t},\r\n\r\n\t\t\t\t\t\t\tintersectsBounds: ( box, isLeaf, score ) => {\r\n\r\n\t\t\t\t\t\t\t\treturn score < closestDistance && score < maxThreshold;\r\n\r\n\t\t\t\t\t\t\t},\r\n\r\n\t\t\t\t\t\t\tintersectsRange: ( otherOffset, otherCount ) => {\r\n\r\n\t\t\t\t\t\t\t\tfor ( let i2 = otherOffset * 3, l2 = ( otherOffset + otherCount ) * 3; i2 < l2; i2 += 3 ) {\r\n\r\n\t\t\t\t\t\t\t\t\tsetTriangle( triangle2, i2, otherIndex, otherPos );\r\n\t\t\t\t\t\t\t\t\ttriangle2.a.applyMatrix4( geometryToBvh );\r\n\t\t\t\t\t\t\t\t\ttriangle2.b.applyMatrix4( geometryToBvh );\r\n\t\t\t\t\t\t\t\t\ttriangle2.c.applyMatrix4( geometryToBvh );\r\n\t\t\t\t\t\t\t\t\ttriangle2.needsUpdate = true;\r\n\r\n\t\t\t\t\t\t\t\t\tfor ( let i = offset * 3, l = ( offset + count ) * 3; i < l; i += 3 ) {\r\n\r\n\t\t\t\t\t\t\t\t\t\tsetTriangle( triangle, i, index, pos );\r\n\t\t\t\t\t\t\t\t\t\ttriangle.needsUpdate = true;\r\n\r\n\t\t\t\t\t\t\t\t\t\tconst dist = triangle.distanceToTriangle( triangle2, tempTarget1, tempTarget2 );\r\n\t\t\t\t\t\t\t\t\t\tif ( dist < closestDistance ) {\r\n\r\n\t\t\t\t\t\t\t\t\t\t\ttempTargetDest1.copy( tempTarget1 );\r\n\r\n\t\t\t\t\t\t\t\t\t\t\tif ( tempTargetDest2 ) {\r\n\r\n\t\t\t\t\t\t\t\t\t\t\t\ttempTargetDest2.copy( tempTarget2 );\r\n\r\n\t\t\t\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\t\t\t\tclosestDistance = dist;\r\n\t\t\t\t\t\t\t\t\t\t\tclosestDistanceTriIndex = i / 3;\r\n\t\t\t\t\t\t\t\t\t\t\tclosestDistanceOtherTriIndex = i2 / 3;\r\n\r\n\t\t\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\t\t\t// stop traversal if we find a point that's under the given threshold\r\n\t\t\t\t\t\t\t\t\t\tif ( dist < minThreshold ) {\r\n\r\n\t\t\t\t\t\t\t\t\t\t\treturn true;\r\n\r\n\t\t\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t},\r\n\t\t\t\t\t\t} );\r\n\r\n\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\t// If no bounds tree then we'll just check every triangle.\r\n\t\t\t\t\t\tconst triCount = otherIndex ? otherIndex.count : otherPos.count;\r\n\t\t\t\t\t\tfor ( let i2 = 0, l2 = triCount; i2 < l2; i2 += 3 ) {\r\n\r\n\t\t\t\t\t\t\tsetTriangle( triangle2, i2, otherIndex, otherPos );\r\n\t\t\t\t\t\t\ttriangle2.a.applyMatrix4( geometryToBvh );\r\n\t\t\t\t\t\t\ttriangle2.b.applyMatrix4( geometryToBvh );\r\n\t\t\t\t\t\t\ttriangle2.c.applyMatrix4( geometryToBvh );\r\n\t\t\t\t\t\t\ttriangle2.needsUpdate = true;\r\n\r\n\t\t\t\t\t\t\tfor ( let i = offset * 3, l = ( offset + count ) * 3; i < l; i += 3 ) {\r\n\r\n\t\t\t\t\t\t\t\tsetTriangle( triangle, i, index, pos );\r\n\t\t\t\t\t\t\t\ttriangle.needsUpdate = true;\r\n\r\n\t\t\t\t\t\t\t\tconst dist = triangle.distanceToTriangle( triangle2, tempTarget1, tempTarget2 );\r\n\t\t\t\t\t\t\t\tif ( dist < closestDistance ) {\r\n\r\n\t\t\t\t\t\t\t\t\ttempTargetDest1.copy( tempTarget1 );\r\n\r\n\t\t\t\t\t\t\t\t\tif ( tempTargetDest2 ) {\r\n\r\n\t\t\t\t\t\t\t\t\t\ttempTargetDest2.copy( tempTarget2 );\r\n\r\n\t\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\t\tclosestDistance = dist;\r\n\t\t\t\t\t\t\t\t\tclosestDistanceTriIndex = i / 3;\r\n\t\t\t\t\t\t\t\t\tclosestDistanceOtherTriIndex = i2 / 3;\r\n\r\n\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\t// stop traversal if we find a point that's under the given threshold\r\n\t\t\t\t\t\t\t\tif ( dist < minThreshold ) {\r\n\r\n\t\t\t\t\t\t\t\t\treturn true;\r\n\r\n\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t},\r\n\r\n\t\t\t}\r\n\r\n\t\t);\r\n\r\n\t\ttrianglePool.releasePrimitive( triangle );\r\n\t\ttrianglePool.releasePrimitive( triangle2 );\r\n\r\n\t\tif ( closestDistance === Infinity ) return null;\r\n\r\n\t\tif ( ! target1.point ) target1.point = tempTargetDest1.clone();\r\n\t\telse target1.point.copy( tempTargetDest1 );\r\n\t\ttarget1.distance = closestDistance,\r\n\t\ttarget1.faceIndex = closestDistanceTriIndex;\r\n\r\n\t\tif ( target2 ) {\r\n\r\n\t\t\tif ( ! target2.point ) target2.point = tempTargetDest2.clone();\r\n\t\t\telse target2.point.copy( tempTargetDest2 );\r\n\t\t\ttarget2.point.applyMatrix4( tempMatrix );\r\n\t\t\ttempTargetDest1.applyMatrix4( tempMatrix );\r\n\t\t\ttarget2.distance = tempTargetDest1.sub( target2.point ).length();\r\n\t\t\ttarget2.faceIndex = closestDistanceOtherTriIndex;\r\n\r\n\t\t}\r\n\r\n\t\treturn target1;\r\n\r\n\t}\r\n\r\n\tclosestPointToPoint( point, target = { }, minThreshold = 0, maxThreshold = Infinity ) {\r\n\r\n\t\t// early out if under minThreshold\r\n\t\t// skip checking if over maxThreshold\r\n\t\t// set minThreshold = maxThreshold to quickly check if a point is within a threshold\r\n\t\t// returns Infinity if no value found\r\n\t\tconst minThresholdSq = minThreshold * minThreshold;\r\n\t\tconst maxThresholdSq = maxThreshold * maxThreshold;\r\n\t\tlet closestDistanceSq = Infinity;\r\n\t\tlet closestDistanceTriIndex = null;\r\n\t\tthis.shapecast(\r\n\r\n\t\t\t{\r\n\r\n\t\t\t\tboundsTraverseOrder: box => {\r\n\r\n\t\t\t\t\ttemp.copy( point ).clamp( box.min, box.max );\r\n\t\t\t\t\treturn temp.distanceToSquared( point );\r\n\r\n\t\t\t\t},\r\n\r\n\t\t\t\tintersectsBounds: ( box, isLeaf, score ) => {\r\n\r\n\t\t\t\t\treturn score < closestDistanceSq && score < maxThresholdSq;\r\n\r\n\t\t\t\t},\r\n\r\n\t\t\t\tintersectsTriangle: ( tri, triIndex ) => {\r\n\r\n\t\t\t\t\ttri.closestPointToPoint( point, temp );\r\n\t\t\t\t\tconst distSq = point.distanceToSquared( temp );\r\n\t\t\t\t\tif ( distSq < closestDistanceSq ) {\r\n\r\n\t\t\t\t\t\ttemp1.copy( temp );\r\n\t\t\t\t\t\tclosestDistanceSq = distSq;\r\n\t\t\t\t\t\tclosestDistanceTriIndex = triIndex;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif ( distSq < minThresholdSq ) {\r\n\r\n\t\t\t\t\t\treturn true;\r\n\r\n\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\treturn false;\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t},\r\n\r\n\t\t\t}\r\n\r\n\t\t);\r\n\r\n\t\tif ( closestDistanceSq === Infinity ) return null;\r\n\r\n\t\tconst closestDistance = Math.sqrt( closestDistanceSq );\r\n\r\n\t\tif ( ! target.point ) target.point = temp1.clone();\r\n\t\telse target.point.copy( temp1 );\r\n\t\ttarget.distance = closestDistance,\r\n\t\ttarget.faceIndex = closestDistanceTriIndex;\r\n\r\n\t\treturn target;\r\n\r\n\t}\r\n\r\n\tgetBoundingBox( target ) {\r\n\r\n\t\ttarget.makeEmpty();\r\n\r\n\t\tconst roots = this._roots;\r\n\t\troots.forEach( buffer => {\r\n\r\n\t\t\tarrayToBox( 0, new Float32Array( buffer ), tempBox );\r\n\t\t\ttarget.union( tempBox );\r\n\r\n\t\t} );\r\n\r\n\t\treturn target;\r\n\r\n\t}\r\n\r\n}\r\n\r\n// Deprecation\r\nconst originalRaycast = MeshBVH.prototype.raycast;\r\nMeshBVH.prototype.raycast = function ( ...args ) {\r\n\r\n\tif ( args[ 0 ].isMesh ) {\r\n\r\n\t\tconsole.warn( 'MeshBVH: The function signature and results frame for \"raycast\" has changed. See docs for new signature.' );\r\n\t\tconst [\r\n\t\t\tmesh, raycaster, ray, intersects,\r\n\t\t] = args;\r\n\r\n\t\tconst results = originalRaycast.call( this, ray, mesh.material );\r\n\t\tresults.forEach( hit => {\r\n\r\n\t\t\thit = convertRaycastIntersect( hit, mesh, raycaster );\r\n\t\t\tif ( hit ) {\r\n\r\n\t\t\t\tintersects.push( hit );\r\n\r\n\t\t\t}\r\n\r\n\t\t} );\r\n\r\n\t\treturn intersects;\r\n\r\n\t} else {\r\n\r\n\t\treturn originalRaycast.apply( this, args );\r\n\r\n\t}\r\n\r\n};\r\n\r\nconst originalRaycastFirst = MeshBVH.prototype.raycastFirst;\r\nMeshBVH.prototype.raycastFirst = function ( ...args ) {\r\n\r\n\tif ( args[ 0 ].isMesh ) {\r\n\r\n\t\tconsole.warn( 'MeshBVH: The function signature and results frame for \"raycastFirst\" has changed. See docs for new signature.' );\r\n\t\tconst [\r\n\t\t\tmesh, raycaster, ray,\r\n\t\t] = args;\r\n\r\n\t\treturn convertRaycastIntersect( originalRaycastFirst.call( this, ray, mesh.material ), mesh, raycaster );\r\n\r\n\t} else {\r\n\r\n\t\treturn originalRaycastFirst.apply( this, args );\r\n\r\n\t}\r\n\r\n};\r\n\r\nconst originalClosestPointToPoint = MeshBVH.prototype.closestPointToPoint;\r\nMeshBVH.prototype.closestPointToPoint = function ( ...args ) {\r\n\r\n\r\n\tif ( args[ 0 ].isMesh ) {\r\n\r\n\t\tconsole.warn( 'MeshBVH: The function signature and results frame for \"closestPointToPoint\" has changed. See docs for new signature.' );\r\n\r\n\t\targs.unshift();\r\n\r\n\t\tconst target = args[ 1 ];\r\n\t\tconst result = {};\r\n\t\targs[ 1 ] = result;\r\n\r\n\t\toriginalClosestPointToPoint.apply( this, args );\r\n\r\n\t\tif ( target ) {\r\n\r\n\t\t\ttarget.copy( result.point );\r\n\r\n\t\t}\r\n\r\n\t\treturn result.distance;\r\n\r\n\t} else {\r\n\r\n\t\treturn originalClosestPointToPoint.apply( this, args );\r\n\r\n\t}\r\n\r\n};\r\n\r\nconst originalClosestPointToGeometry = MeshBVH.prototype.closestPointToGeometry;\r\nMeshBVH.prototype.closestPointToGeometry = function ( ...args ) {\r\n\r\n\tconst target1 = args[ 2 ];\r\n\tconst target2 = args[ 3 ];\r\n\tif ( target1 && target1.isVector3 || target2 && target2.isVector3 ) {\r\n\r\n\t\tconsole.warn( 'MeshBVH: The function signature and results frame for \"closestPointToGeometry\" has changed. See docs for new signature.' );\r\n\r\n\t\tconst result1 = {};\r\n\t\tconst result2 = {};\r\n\t\tconst geometryToBvh = args[ 1 ];\r\n\t\targs[ 2 ] = result1;\r\n\t\targs[ 3 ] = result2;\r\n\r\n\t\toriginalClosestPointToGeometry.apply( this, args );\r\n\r\n\t\tif ( target1 ) {\r\n\r\n\t\t\ttarget1.copy( result1.point );\r\n\r\n\t\t}\r\n\r\n\t\tif ( target2 ) {\r\n\r\n\t\t\ttarget2.copy( result2.point ).applyMatrix4( geometryToBvh );\r\n\r\n\t\t}\r\n\r\n\t\treturn result1.distance;\r\n\r\n\t} else {\r\n\r\n\t\treturn originalClosestPointToGeometry.apply( this, args );\r\n\r\n\t}\r\n\r\n};\r\n\r\nconst originalRefit = MeshBVH.prototype.refit;\r\nMeshBVH.prototype.refit = function ( ...args ) {\r\n\r\n\tconst nodeIndices = args[ 0 ];\r\n\tconst terminationIndices = args[ 1 ];\r\n\tif ( terminationIndices && ( terminationIndices instanceof Set || Array.isArray( terminationIndices ) ) ) {\r\n\r\n\t\tconsole.warn( 'MeshBVH: The function signature for \"refit\" has changed. See docs for new signature.' );\r\n\r\n\t\tconst newNodeIndices = new Set();\r\n\t\tterminationIndices.forEach( v => newNodeIndices.add( v ) );\r\n\t\tif ( nodeIndices ) {\r\n\r\n\t\t\tnodeIndices.forEach( v => newNodeIndices.add( v ) );\r\n\r\n\t\t}\r\n\r\n\t\toriginalRefit.call( this, newNodeIndices );\r\n\r\n\t} else {\r\n\r\n\t\toriginalRefit.apply( this, args );\r\n\r\n\t}\r\n\r\n};\r\n\r\n[\r\n\t'intersectsGeometry',\r\n\t'shapecast',\r\n\t'intersectsBox',\r\n\t'intersectsSphere',\r\n].forEach( name => {\r\n\r\n\tconst originalFunc = MeshBVH.prototype[ name ];\r\n\tMeshBVH.prototype[ name ] = function ( ...args ) {\r\n\r\n\t\tif ( args[ 0 ] === null || args[ 0 ].isMesh ) {\r\n\r\n\t\t\targs.shift();\r\n\t\t\tconsole.warn( `MeshBVH: The function signature for \"${ name }\" has changed and no longer takes Mesh. See docs for new signature.` );\r\n\r\n\t\t}\r\n\r\n\t\treturn originalFunc.apply( this, args );\r\n\r\n\t};\r\n\r\n} );\r\n","import { LineBasicMaterial, BufferAttribute, Box3, Group, MeshBasicMaterial, Object3D, BufferGeometry } from 'three';\r\nimport { arrayToBox } from '../utils/ArrayBoxUtilities.js';\r\n\r\nconst boundingBox = /* @__PURE__ */ new Box3();\r\nclass MeshBVHRootVisualizer extends Object3D {\r\n\r\n\tget isMesh() {\r\n\r\n\t\treturn ! this.displayEdges;\r\n\r\n\t}\r\n\r\n\tget isLineSegments() {\r\n\r\n\t\treturn this.displayEdges;\r\n\r\n\t}\r\n\r\n\tget isLine() {\r\n\r\n\t\treturn this.displayEdges;\r\n\r\n\t}\r\n\r\n\tconstructor( mesh, material, depth = 10, group = 0 ) {\r\n\r\n\t\tsuper();\r\n\r\n\t\tthis.material = material;\r\n\t\tthis.geometry = new BufferGeometry();\r\n\t\tthis.name = 'MeshBVHRootVisualizer';\r\n\t\tthis.depth = depth;\r\n\t\tthis.displayParents = false;\r\n\t\tthis.mesh = mesh;\r\n\t\tthis.displayEdges = true;\r\n\t\tthis._group = group;\r\n\r\n\t}\r\n\r\n\traycast() {}\r\n\r\n\tupdate() {\r\n\r\n\t\tconst geometry = this.geometry;\r\n\t\tconst boundsTree = this.mesh.geometry.boundsTree;\r\n\t\tconst group = this._group;\r\n\t\tgeometry.dispose();\r\n\t\tthis.visible = false;\r\n\t\tif ( boundsTree ) {\r\n\r\n\t\t\t// count the number of bounds required\r\n\t\t\tconst targetDepth = this.depth - 1;\r\n\t\t\tconst displayParents = this.displayParents;\r\n\t\t\tlet boundsCount = 0;\r\n\t\t\tboundsTree.traverse( ( depth, isLeaf ) => {\r\n\r\n\t\t\t\tif ( depth === targetDepth || isLeaf ) {\r\n\r\n\t\t\t\t\tboundsCount ++;\r\n\t\t\t\t\treturn true;\r\n\r\n\t\t\t\t} else if ( displayParents ) {\r\n\r\n\t\t\t\t\tboundsCount ++;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}, group );\r\n\r\n\t\t\t// fill in the position buffer with the bounds corners\r\n\t\t\tlet posIndex = 0;\r\n\t\t\tconst positionArray = new Float32Array( 8 * 3 * boundsCount );\r\n\t\t\tboundsTree.traverse( ( depth, isLeaf, boundingData ) => {\r\n\r\n\t\t\t\tconst terminate = depth === targetDepth || isLeaf;\r\n\t\t\t\tif ( terminate || displayParents ) {\r\n\r\n\t\t\t\t\tarrayToBox( 0, boundingData, boundingBox );\r\n\r\n\t\t\t\t\tconst { min, max } = boundingBox;\r\n\t\t\t\t\tfor ( let x = - 1; x <= 1; x += 2 ) {\r\n\r\n\t\t\t\t\t\tconst xVal = x < 0 ? min.x : max.x;\r\n\t\t\t\t\t\tfor ( let y = - 1; y <= 1; y += 2 ) {\r\n\r\n\t\t\t\t\t\t\tconst yVal = y < 0 ? min.y : max.y;\r\n\t\t\t\t\t\t\tfor ( let z = - 1; z <= 1; z += 2 ) {\r\n\r\n\t\t\t\t\t\t\t\tconst zVal = z < 0 ? min.z : max.z;\r\n\t\t\t\t\t\t\t\tpositionArray[ posIndex + 0 ] = xVal;\r\n\t\t\t\t\t\t\t\tpositionArray[ posIndex + 1 ] = yVal;\r\n\t\t\t\t\t\t\t\tpositionArray[ posIndex + 2 ] = zVal;\r\n\r\n\t\t\t\t\t\t\t\tposIndex += 3;\r\n\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\treturn terminate;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}, group );\r\n\r\n\t\t\tlet indexArray;\r\n\t\t\tlet indices;\r\n\t\t\tif ( this.displayEdges ) {\r\n\r\n\t\t\t\t// fill in the index buffer to point to the corner points\r\n\t\t\t\tindices = new Uint8Array( [\r\n\t\t\t\t\t// x axis\r\n\t\t\t\t\t0, 4,\r\n\t\t\t\t\t1, 5,\r\n\t\t\t\t\t2, 6,\r\n\t\t\t\t\t3, 7,\r\n\r\n\t\t\t\t\t// y axis\r\n\t\t\t\t\t0, 2,\r\n\t\t\t\t\t1, 3,\r\n\t\t\t\t\t4, 6,\r\n\t\t\t\t\t5, 7,\r\n\r\n\t\t\t\t\t// z axis\r\n\t\t\t\t\t0, 1,\r\n\t\t\t\t\t2, 3,\r\n\t\t\t\t\t4, 5,\r\n\t\t\t\t\t6, 7,\r\n\t\t\t\t] );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tindices = new Uint8Array( [\r\n\r\n\t\t\t\t\t// X-, X+\r\n\t\t\t\t\t0, 1, 2,\r\n\t\t\t\t\t2, 1, 3,\r\n\r\n\t\t\t\t\t4, 6, 5,\r\n\t\t\t\t\t6, 7, 5,\r\n\r\n\t\t\t\t\t// Y-, Y+\r\n\t\t\t\t\t1, 4, 5,\r\n\t\t\t\t\t0, 4, 1,\r\n\r\n\t\t\t\t\t2, 3, 6,\r\n\t\t\t\t\t3, 7, 6,\r\n\r\n\t\t\t\t\t// Z-, Z+\r\n\t\t\t\t\t0, 2, 4,\r\n\t\t\t\t\t2, 6, 4,\r\n\r\n\t\t\t\t\t1, 5, 3,\r\n\t\t\t\t\t3, 5, 7,\r\n\r\n\t\t\t\t] );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( positionArray.length > 65535 ) {\r\n\r\n\t\t\t\tindexArray = new Uint32Array( indices.length * boundsCount );\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tindexArray = new Uint16Array( indices.length * boundsCount );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tconst indexLength = indices.length;\r\n\t\t\tfor ( let i = 0; i < boundsCount; i ++ ) {\r\n\r\n\t\t\t\tconst posOffset = i * 8;\r\n\t\t\t\tconst indexOffset = i * indexLength;\r\n\t\t\t\tfor ( let j = 0; j < indexLength; j ++ ) {\r\n\r\n\t\t\t\t\tindexArray[ indexOffset + j ] = posOffset + indices[ j ];\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\t// update the geometry\r\n\t\t\tgeometry.setIndex(\r\n\t\t\t\tnew BufferAttribute( indexArray, 1, false ),\r\n\t\t\t);\r\n\t\t\tgeometry.setAttribute(\r\n\t\t\t\t'position',\r\n\t\t\t\tnew BufferAttribute( positionArray, 3, false ),\r\n\t\t\t);\r\n\t\t\tthis.visible = true;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n}\r\n\r\nclass MeshBVHVisualizer extends Group {\r\n\r\n\tget color() {\r\n\r\n\t\treturn this.edgeMaterial.color;\r\n\r\n\t}\r\n\r\n\tget opacity() {\r\n\r\n\t\treturn this.edgeMaterial.opacity;\r\n\r\n\t}\r\n\r\n\tset opacity( v ) {\r\n\r\n\t\tthis.edgeMaterial.opacity = v;\r\n\t\tthis.meshMaterial.opacity = v;\r\n\r\n\t}\r\n\r\n\tconstructor( mesh, depth = 10 ) {\r\n\r\n\t\tsuper();\r\n\r\n\t\tthis.name = 'MeshBVHVisualizer';\r\n\t\tthis.depth = depth;\r\n\t\tthis.mesh = mesh;\r\n\t\tthis.displayParents = false;\r\n\t\tthis.displayEdges = true;\r\n\t\tthis._roots = [];\r\n\r\n\t\tconst edgeMaterial = new LineBasicMaterial( {\r\n\t\t\tcolor: 0x00FF88,\r\n\t\t\ttransparent: true,\r\n\t\t\topacity: 0.3,\r\n\t\t\tdepthWrite: false,\r\n\t\t} );\r\n\r\n\t\tconst meshMaterial = new MeshBasicMaterial( {\r\n\t\t\tcolor: 0x00FF88,\r\n\t\t\ttransparent: true,\r\n\t\t\topacity: 0.3,\r\n\t\t\tdepthWrite: false,\r\n\t\t} );\r\n\r\n\t\tmeshMaterial.color = edgeMaterial.color;\r\n\r\n\t\tthis.edgeMaterial = edgeMaterial;\r\n\t\tthis.meshMaterial = meshMaterial;\r\n\r\n\t\tthis.update();\r\n\r\n\t}\r\n\r\n\tupdate() {\r\n\r\n\t\tconst bvh = this.mesh.geometry.boundsTree;\r\n\t\tconst totalRoots = bvh ? bvh._roots.length : 0;\r\n\t\twhile ( this._roots.length > totalRoots ) {\r\n\r\n\t\t\tthis._roots.pop();\r\n\r\n\t\t}\r\n\r\n\t\tfor ( let i = 0; i < totalRoots; i ++ ) {\r\n\r\n\t\t\tif ( i >= this._roots.length ) {\r\n\r\n\t\t\t\tconst root = new MeshBVHRootVisualizer( this.mesh, this.edgeMaterial, this.depth, i );\r\n\t\t\t\tthis.add( root );\r\n\t\t\t\tthis._roots.push( root );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tconst root = this._roots[ i ];\r\n\t\t\troot.depth = this.depth;\r\n\t\t\troot.mesh = this.mesh;\r\n\t\t\troot.displayParents = this.displayParents;\r\n\t\t\troot.displayEdges = this.displayEdges;\r\n\t\t\troot.material = this.displayEdges ? this.edgeMaterial : this.meshMaterial;\r\n\t\t\troot.update();\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tupdateMatrixWorld( ...args ) {\r\n\r\n\t\tthis.position.copy( this.mesh.position );\r\n\t\tthis.rotation.copy( this.mesh.rotation );\r\n\t\tthis.scale.copy( this.mesh.scale );\r\n\r\n\t\tsuper.updateMatrixWorld( ...args );\r\n\r\n\t}\r\n\r\n\tcopy( source ) {\r\n\r\n\t\tthis.depth = source.depth;\r\n\t\tthis.mesh = source.mesh;\r\n\r\n\t}\r\n\r\n\tclone() {\r\n\r\n\t\treturn new MeshBVHVisualizer( this.mesh, this.depth );\r\n\r\n\t}\r\n\r\n\tdispose() {\r\n\r\n\t\tthis.edgeMaterial.dispose();\r\n\t\tthis.meshMaterial.dispose();\r\n\r\n\t\tconst children = this.children;\r\n\t\tfor ( let i = 0, l = children.length; i < l; i ++ ) {\r\n\r\n\t\t\tchildren[ i ].geometry.dispose();\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n}\r\n\r\n\r\nexport { MeshBVHVisualizer };\r\n","import { Box3, Vector3 } from 'three';\r\nimport { TRAVERSAL_COST, TRIANGLE_INTERSECT_COST } from '../core/Constants.js';\r\nimport { arrayToBox } from '../utils/ArrayBoxUtilities.js';\r\n\r\nconst _box1 = /* @__PURE__ */ new Box3();\r\nconst _box2 = /* @__PURE__ */ new Box3();\r\nconst _vec = /* @__PURE__ */ new Vector3();\r\n\r\n// https://stackoverflow.com/questions/1248302/how-to-get-the-size-of-a-javascript-object\r\nfunction getPrimitiveSize( el ) {\r\n\r\n\tswitch ( typeof el ) {\r\n\r\n\t\tcase 'number':\r\n\t\t\treturn 8;\r\n\t\tcase 'string':\r\n\t\t\treturn el.length * 2;\r\n\t\tcase 'boolean':\r\n\t\t\treturn 4;\r\n\t\tdefault:\r\n\t\t\treturn 0;\r\n\r\n\t}\r\n\r\n}\r\n\r\nfunction isTypedArray( arr ) {\r\n\r\n\tconst regex = /(Uint|Int|Float)(8|16|32)Array/;\r\n\treturn regex.test( arr.constructor.name );\r\n\r\n}\r\n\r\nfunction getRootExtremes( bvh, group ) {\r\n\r\n\tconst result = {\r\n\t\tnodeCount: 0,\r\n\t\tleafNodeCount: 0,\r\n\r\n\t\tdepth: {\r\n\t\t\tmin: Infinity, max: - Infinity\r\n\t\t},\r\n\t\ttris: {\r\n\t\t\tmin: Infinity, max: - Infinity\r\n\t\t},\r\n\t\tsplits: [ 0, 0, 0 ],\r\n\t\tsurfaceAreaScore: 0,\r\n\t};\r\n\r\n\tbvh.traverse( ( depth, isLeaf, boundingData, offsetOrSplit, count ) => {\r\n\r\n\t\tconst l0 = boundingData[ 0 + 3 ] - boundingData[ 0 ];\r\n\t\tconst l1 = boundingData[ 1 + 3 ] - boundingData[ 1 ];\r\n\t\tconst l2 = boundingData[ 2 + 3 ] - boundingData[ 2 ];\r\n\r\n\t\tconst surfaceArea = 2 * ( l0 * l1 + l1 * l2 + l2 * l0 );\r\n\r\n\t\tresult.nodeCount ++;\r\n\t\tif ( isLeaf ) {\r\n\r\n\t\t\tresult.leafNodeCount ++;\r\n\r\n\t\t\tresult.depth.min = Math.min( depth, result.depth.min );\r\n\t\t\tresult.depth.max = Math.max( depth, result.depth.max );\r\n\r\n\t\t\tresult.tris.min = Math.min( count, result.tris.min );\r\n\t\t\tresult.tris.max = Math.max( count, result.tris.max );\r\n\r\n\t\t\tresult.surfaceAreaScore += surfaceArea * TRIANGLE_INTERSECT_COST * count;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tresult.splits[ offsetOrSplit ] ++;\r\n\r\n\t\t\tresult.surfaceAreaScore += surfaceArea * TRAVERSAL_COST;\r\n\r\n\t\t}\r\n\r\n\t}, group );\r\n\r\n\t// If there are no leaf nodes because the tree hasn't finished generating yet.\r\n\tif ( result.tris.min === Infinity ) {\r\n\r\n\t\tresult.tris.min = 0;\r\n\t\tresult.tris.max = 0;\r\n\r\n\t}\r\n\r\n\tif ( result.depth.min === Infinity ) {\r\n\r\n\t\tresult.depth.min = 0;\r\n\t\tresult.depth.max = 0;\r\n\r\n\t}\r\n\r\n\treturn result;\r\n\r\n}\r\n\r\nfunction getBVHExtremes( bvh ) {\r\n\r\n\treturn bvh._roots.map( ( root, i ) => getRootExtremes( bvh, i ) );\r\n\r\n}\r\n\r\nfunction estimateMemoryInBytes( obj ) {\r\n\r\n\tconst traversed = new Set();\r\n\tconst stack = [ obj ];\r\n\tlet bytes = 0;\r\n\r\n\twhile ( stack.length ) {\r\n\r\n\t\tconst curr = stack.pop();\r\n\t\tif ( traversed.has( curr ) ) {\r\n\r\n\t\t\tcontinue;\r\n\r\n\t\t}\r\n\r\n\t\ttraversed.add( curr );\r\n\r\n\t\tfor ( let key in curr ) {\r\n\r\n\t\t\tif ( ! curr.hasOwnProperty( key ) ) {\r\n\r\n\t\t\t\tcontinue;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tbytes += getPrimitiveSize( key );\r\n\r\n\t\t\tconst value = curr[ key ];\r\n\t\t\tif ( value && ( typeof value === 'object' || typeof value === 'function' ) ) {\r\n\r\n\t\t\t\tif ( isTypedArray( value ) ) {\r\n\r\n\t\t\t\t\tbytes += value.byteLength;\r\n\r\n\t\t\t\t} else if ( value instanceof ArrayBuffer ) {\r\n\r\n\t\t\t\t\tbytes += value.byteLength;\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\tstack.push( value );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tbytes += getPrimitiveSize( value );\r\n\r\n\t\t\t}\r\n\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\treturn bytes;\r\n\r\n}\r\n\r\nfunction validateBounds( bvh ) {\r\n\r\n\tconst geometry = bvh.geometry;\r\n\tconst depthStack = [];\r\n\tconst index = geometry.index;\r\n\tconst position = geometry.getAttribute( 'position' );\r\n\tlet passes = true;\r\n\r\n\tbvh.traverse( ( depth, isLeaf, boundingData, offset, count ) => {\r\n\r\n\t\tconst info = {\r\n\t\t\tdepth,\r\n\t\t\tisLeaf,\r\n\t\t\tboundingData,\r\n\t\t\toffset,\r\n\t\t\tcount,\r\n\t\t};\r\n\t\tdepthStack[ depth ] = info;\r\n\r\n\t\tarrayToBox( 0, boundingData, _box1 );\r\n\t\tconst parent = depthStack[ depth - 1 ];\r\n\r\n\t\tif ( isLeaf ) {\r\n\r\n\t\t\t// check triangles\r\n\t\t\tfor ( let i = offset * 3, l = ( offset + count ) * 3; i < l; i += 3 ) {\r\n\r\n\t\t\t\tconst i0 = index.getX( i );\r\n\t\t\t\tconst i1 = index.getX( i + 1 );\r\n\t\t\t\tconst i2 = index.getX( i + 2 );\r\n\r\n\t\t\t\tlet isContained;\r\n\r\n\t\t\t\t_vec.fromBufferAttribute( position, i0 );\r\n\t\t\t\tisContained = _box1.containsPoint( _vec );\r\n\r\n\t\t\t\t_vec.fromBufferAttribute( position, i1 );\r\n\t\t\t\tisContained = isContained && _box1.containsPoint( _vec );\r\n\r\n\t\t\t\t_vec.fromBufferAttribute( position, i2 );\r\n\t\t\t\tisContained = isContained && _box1.containsPoint( _vec );\r\n\r\n\t\t\t\tconsole.assert( isContained, 'Leaf bounds does not fully contain triangle.' );\r\n\t\t\t\tpasses = passes && isContained;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tif ( parent ) {\r\n\r\n\t\t\t// check if my bounds fit in my parents\r\n\t\t\tarrayToBox( 0, boundingData, _box2 );\r\n\r\n\t\t\tconst isContained = _box2.containsBox( _box1 );\r\n\t\t\tconsole.assert( isContained, 'Parent bounds does not fully contain child.' );\r\n\t\t\tpasses = passes && isContained;\r\n\r\n\t\t}\r\n\r\n\t} );\r\n\r\n\treturn passes;\r\n\r\n}\r\n\r\n// Returns a simple, human readable object that represents the BVH.\r\nfunction getJSONStructure( bvh ) {\r\n\r\n\tconst depthStack = [];\r\n\r\n\tbvh.traverse( ( depth, isLeaf, boundingData, offset, count ) => {\r\n\r\n\t\tconst info = {\r\n\t\t\tbounds: arrayToBox( 0, boundingData, new Box3() ),\r\n\t\t};\r\n\r\n\t\tif ( isLeaf ) {\r\n\r\n\t\t\tinfo.count = count;\r\n\t\t\tinfo.offset = offset;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tinfo.left = null;\r\n\t\t\tinfo.right = null;\r\n\r\n\t\t}\r\n\r\n\t\tdepthStack[ depth ] = info;\r\n\r\n\t\t// traversal hits the left then right node\r\n\t\tconst parent = depthStack[ depth - 1 ];\r\n\t\tif ( parent ) {\r\n\r\n\t\t\tif ( parent.left === null ) {\r\n\r\n\t\t\t\tparent.left = info;\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tparent.right = info;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t} );\r\n\r\n\treturn depthStack[ 0 ];\r\n\r\n}\r\n\r\nexport { estimateMemoryInBytes, getBVHExtremes, validateBounds, getJSONStructure };\r\n","import { Ray, Matrix4, Mesh } from 'three';\r\nimport { convertRaycastIntersect } from './GeometryRayIntersectUtilities.js';\r\nimport { MeshBVH } from '../core/MeshBVH.js';\r\n\r\nconst ray = /* @__PURE__ */ new Ray();\r\nconst tmpInverseMatrix = /* @__PURE__ */ new Matrix4();\r\nconst origMeshRaycastFunc = Mesh.prototype.raycast;\r\n\r\nexport function acceleratedRaycast( raycaster, intersects ) {\r\n\r\n\tif ( this.geometry.boundsTree ) {\r\n\r\n\t\tif ( this.material === undefined ) return;\r\n\r\n\t\ttmpInverseMatrix.copy( this.matrixWorld ).invert();\r\n\t\tray.copy( raycaster.ray ).applyMatrix4( tmpInverseMatrix );\r\n\r\n\t\tconst bvh = this.geometry.boundsTree;\r\n\t\tif ( raycaster.firstHitOnly === true ) {\r\n\r\n\t\t\tconst hit = convertRaycastIntersect( bvh.raycastFirst( ray, this.material ), this, raycaster );\r\n\t\t\tif ( hit ) {\r\n\r\n\t\t\t\tintersects.push( hit );\r\n\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\r\n\t\t\tconst hits = bvh.raycast( ray, this.material );\r\n\t\t\tfor ( let i = 0, l = hits.length; i < l; i ++ ) {\r\n\r\n\t\t\t\tconst hit = convertRaycastIntersect( hits[ i ], this, raycaster );\r\n\t\t\t\tif ( hit ) {\r\n\r\n\t\t\t\t\tintersects.push( hit );\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t} else {\r\n\r\n\t\torigMeshRaycastFunc.call( this, raycaster, intersects );\r\n\r\n\t}\r\n\r\n}\r\n\r\nexport function computeBoundsTree( options ) {\r\n\r\n\tthis.boundsTree = new MeshBVH( this, options );\r\n\treturn this.boundsTree;\r\n\r\n}\r\n\r\nexport function disposeBoundsTree() {\r\n\r\n\tthis.boundsTree = null;\r\n\r\n}\r\n","import {\r\n\tDataTexture,\r\n\tFloatType,\r\n\tIntType,\r\n\tUnsignedIntType,\r\n\tByteType,\r\n\tUnsignedByteType,\r\n\tShortType,\r\n\tUnsignedShortType,\r\n\r\n\tRedFormat,\r\n\tRGFormat,\r\n\tRGBAFormat,\r\n\r\n\tRedIntegerFormat,\r\n\tRGIntegerFormat,\r\n\tRGBAIntegerFormat,\r\n\r\n\tNearestFilter,\r\n} from 'three';\r\n\r\nfunction countToStringFormat( count ) {\r\n\r\n\tswitch ( count ) {\r\n\r\n\t\tcase 1: return 'R';\r\n\t\tcase 2: return 'RG';\r\n\t\tcase 3: return 'RGBA';\r\n\t\tcase 4: return 'RGBA';\r\n\r\n\t}\r\n\r\n\tthrow new Error();\r\n\r\n}\r\n\r\nfunction countToFormat( count ) {\r\n\r\n\tswitch ( count ) {\r\n\r\n\t\tcase 1: return RedFormat;\r\n\t\tcase 2: return RGFormat;\r\n\t\tcase 3: return RGBAFormat;\r\n\t\tcase 4: return RGBAFormat;\r\n\r\n\t}\r\n\r\n}\r\n\r\nfunction countToIntFormat( count ) {\r\n\r\n\tswitch ( count ) {\r\n\r\n\t\tcase 1: return RedIntegerFormat;\r\n\t\tcase 2: return RGIntegerFormat;\r\n\t\tcase 3: return RGBAIntegerFormat;\r\n\t\tcase 4: return RGBAIntegerFormat;\r\n\r\n\t}\r\n\r\n}\r\n\r\nexport class VertexAttributeTexture extends DataTexture {\r\n\r\n\tconstructor() {\r\n\r\n\t\tsuper();\r\n\t\tthis.minFilter = NearestFilter;\r\n\t\tthis.magFilter = NearestFilter;\r\n\t\tthis.generateMipmaps = false;\r\n\t\tthis.overrideItemSize = null;\r\n\t\tthis._forcedType = null;\r\n\r\n\t}\r\n\r\n\tupdateFrom( attr ) {\r\n\r\n\t\tconst overrideItemSize = this.overrideItemSize;\r\n\t\tconst originalItemSize = attr.itemSize;\r\n\t\tconst originalCount = attr.count;\r\n\t\tif ( overrideItemSize !== null ) {\r\n\r\n\t\t\tif ( ( originalItemSize * originalCount ) % overrideItemSize !== 0.0 ) {\r\n\r\n\t\t\t\tthrow new Error( 'VertexAttributeTexture: overrideItemSize must divide evenly into buffer length.' );\r\n\r\n\t\t\t}\r\n\r\n\t\t\tattr.itemSize = overrideItemSize;\r\n\t\t\tattr.count = originalCount * originalItemSize / overrideItemSize;\r\n\r\n\t\t}\r\n\r\n\t\tconst itemSize = attr.itemSize;\r\n\t\tconst count = attr.count;\r\n\t\tconst normalized = attr.normalized;\r\n\t\tconst originalBufferCons = attr.array.constructor;\r\n\t\tconst byteCount = originalBufferCons.BYTES_PER_ELEMENT;\r\n\t\tlet targetType = this._forcedType;\r\n\t\tlet finalStride = itemSize;\r\n\r\n\t\t// derive the type of texture this should be in the shader\r\n\t\tif ( targetType === null ) {\r\n\r\n\t\t\tswitch ( originalBufferCons ) {\r\n\r\n\t\t\t\tcase Float32Array:\r\n\t\t\t\t\ttargetType = FloatType;\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase Uint8Array:\r\n\t\t\t\tcase Uint16Array:\r\n\t\t\t\tcase Uint32Array:\r\n\t\t\t\t\ttargetType = UnsignedIntType;\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase Int8Array:\r\n\t\t\t\tcase Int16Array:\r\n\t\t\t\tcase Int32Array:\r\n\t\t\t\t\ttargetType = IntType;\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\t// get the target format to store the texture as\r\n\t\tlet type, format, normalizeValue, targetBufferCons;\r\n\t\tlet internalFormat = countToStringFormat( itemSize );\r\n\t\tswitch ( targetType ) {\r\n\r\n\t\t\tcase FloatType:\r\n\t\t\t\tnormalizeValue = 1.0;\r\n\t\t\t\tformat = countToFormat( itemSize );\r\n\r\n\t\t\t\tif ( normalized && byteCount === 1 ) {\r\n\r\n\t\t\t\t\ttargetBufferCons = originalBufferCons;\r\n\t\t\t\t\tinternalFormat += '8';\r\n\r\n\t\t\t\t\tif ( originalBufferCons === Uint8Array ) {\r\n\r\n\t\t\t\t\t\ttype = UnsignedByteType;\r\n\r\n\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t\ttype = ByteType;\r\n\t\t\t\t\t\tinternalFormat += '_SNORM';\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\ttargetBufferCons = Float32Array;\r\n\t\t\t\t\tinternalFormat += '32F';\r\n\t\t\t\t\ttype = FloatType;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase IntType:\r\n\t\t\t\tinternalFormat += byteCount * 8 + 'I';\r\n\t\t\t\tnormalizeValue = normalized ? Math.pow( 2, originalBufferCons.BYTES_PER_ELEMENT * 8 - 1 ) : 1.0;\r\n\t\t\t\tformat = countToIntFormat( itemSize );\r\n\r\n\t\t\t\tif ( byteCount === 1 ) {\r\n\r\n\t\t\t\t\ttargetBufferCons = Int8Array;\r\n\t\t\t\t\ttype = ByteType;\r\n\r\n\t\t\t\t} else if ( byteCount === 2 ) {\r\n\r\n\t\t\t\t\ttargetBufferCons = Int16Array;\r\n\t\t\t\t\ttype = ShortType;\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\ttargetBufferCons = Int32Array;\r\n\t\t\t\t\ttype = IntType;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase UnsignedIntType:\r\n\t\t\t\tinternalFormat += byteCount * 8 + 'UI';\r\n\t\t\t\tnormalizeValue = normalized ? Math.pow( 2, originalBufferCons.BYTES_PER_ELEMENT * 8 - 1 ) : 1.0;\r\n\t\t\t\tformat = countToIntFormat( itemSize );\r\n\r\n\t\t\t\tif ( byteCount === 1 ) {\r\n\r\n\t\t\t\t\ttargetBufferCons = Uint8Array;\r\n\t\t\t\t\ttype = UnsignedByteType;\r\n\r\n\t\t\t\t} else if ( byteCount === 2 ) {\r\n\r\n\t\t\t\t\ttargetBufferCons = Uint16Array;\r\n\t\t\t\t\ttype = UnsignedShortType;\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\ttargetBufferCons = Uint32Array;\r\n\t\t\t\t\ttype = UnsignedIntType;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t\tbreak;\r\n\r\n\t\t}\r\n\r\n\t\t// there will be a mismatch between format length and final length because\r\n\t\t// RGBFormat and RGBIntegerFormat was removed\r\n\t\tif ( finalStride === 3 && ( format === RGBAFormat || format === RGBAIntegerFormat ) ) {\r\n\r\n\t\t\tfinalStride = 4;\r\n\r\n\t\t}\r\n\r\n\t\t// copy the data over to the new texture array\r\n\t\tconst dimension = Math.ceil( Math.sqrt( count ) );\r\n\t\tconst length = finalStride * dimension * dimension;\r\n\t\tconst dataArray = new targetBufferCons( length );\r\n\t\tfor ( let i = 0; i < count; i ++ ) {\r\n\r\n\t\t\tconst ii = finalStride * i;\r\n\t\t\tdataArray[ ii ] = attr.getX( i ) / normalizeValue;\r\n\r\n\t\t\tif ( itemSize >= 2 ) {\r\n\r\n\t\t\t\tdataArray[ ii + 1 ] = attr.getY( i ) / normalizeValue;\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( itemSize >= 3 ) {\r\n\r\n\t\t\t\tdataArray[ ii + 2 ] = attr.getZ( i ) / normalizeValue;\r\n\r\n\t\t\t\tif ( finalStride === 4 ) {\r\n\r\n\t\t\t\t\tdataArray[ ii + 3 ] = 1.0;\r\n\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif ( itemSize >= 4 ) {\r\n\r\n\t\t\t\tdataArray[ ii + 3 ] = attr.getW( i ) / normalizeValue;\r\n\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tthis.internalFormat = internalFormat;\r\n\t\tthis.format = format;\r\n\t\tthis.type = type;\r\n\t\tthis.image.width = dimension;\r\n\t\tthis.image.height = dimension;\r\n\t\tthis.image.data = dataArray;\r\n\t\tthis.needsUpdate = true;\r\n\r\n\t\tattr.itemSize = originalItemSize;\r\n\t\tattr.count = originalCount;\r\n\r\n\t}\r\n\r\n}\r\n\r\nexport class UIntVertexAttributeTexture extends VertexAttributeTexture {\r\n\r\n\tconstructor() {\r\n\r\n\t\tsuper();\r\n\t\tthis._forcedType = UnsignedIntType;\r\n\r\n\t}\r\n\r\n}\r\n\r\nexport class IntVertexAttributeTexture extends VertexAttributeTexture {\r\n\r\n\tconstructor() {\r\n\r\n\t\tsuper();\r\n\t\tthis._forcedType = IntType;\r\n\r\n\t}\r\n\r\n\r\n}\r\n\r\nexport class FloatVertexAttributeTexture extends VertexAttributeTexture {\r\n\r\n\tconstructor() {\r\n\r\n\t\tsuper();\r\n\t\tthis._forcedType = FloatType;\r\n\r\n\t}\r\n\r\n}\r\n","import {\r\n\tDataTexture,\r\n\tFloatType,\r\n\tUnsignedIntType,\r\n\tRGBAFormat,\r\n\tRGIntegerFormat,\r\n\tNearestFilter,\r\n} from 'three';\r\nimport {\r\n\tFloatVertexAttributeTexture,\r\n\tUIntVertexAttributeTexture,\r\n} from './VertexAttributeTexture.js';\r\nimport { BYTES_PER_NODE } from '../core/Constants.js';\r\nimport {\r\n\tBOUNDING_DATA_INDEX,\r\n\tCOUNT,\r\n\tIS_LEAF,\r\n\tRIGHT_NODE,\r\n\tOFFSET,\r\n\tSPLIT_AXIS,\r\n} from '../core/nodeBufferFunctions.js';\r\n\r\nfunction bvhToTextures( bvh, boundsTexture, contentsTexture ) {\r\n\r\n\tconst roots = bvh._roots;\r\n\r\n\tif ( roots.length !== 1 ) {\r\n\r\n\t\tthrow new Error( 'MeshBVHUniformStruct: Multi-root BVHs not supported.' );\r\n\r\n\t}\r\n\r\n\tconst root = roots[ 0 ];\r\n\tconst uint16Array = new Uint16Array( root );\r\n\tconst uint32Array = new Uint32Array( root );\r\n\tconst float32Array = new Float32Array( root );\r\n\r\n\t// Both bounds need two elements per node so compute the height so it's twice as long as\r\n\t// the width so we can expand the row by two and still have a square texture\r\n\tconst nodeCount = root.byteLength / BYTES_PER_NODE;\r\n\tconst boundsDimension = 2 * Math.ceil( Math.sqrt( nodeCount / 2 ) );\r\n\tconst boundsArray = new Float32Array( 4 * boundsDimension * boundsDimension );\r\n\r\n\tconst contentsDimension = Math.ceil( Math.sqrt( nodeCount ) );\r\n\tconst contentsArray = new Uint32Array( 2 * contentsDimension * contentsDimension );\r\n\r\n\tfor ( let i = 0; i < nodeCount; i ++ ) {\r\n\r\n\t\tconst nodeIndex32 = i * BYTES_PER_NODE / 4;\r\n\t\tconst nodeIndex16 = nodeIndex32 * 2;\r\n\t\tconst boundsIndex = BOUNDING_DATA_INDEX( nodeIndex32 );\r\n\t\tfor ( let b = 0; b < 3; b ++ ) {\r\n\r\n\t\t\tboundsArray[ 8 * i + 0 + b ] = float32Array[ boundsIndex + 0 + b ];\r\n\t\t\tboundsArray[ 8 * i + 4 + b ] = float32Array[ boundsIndex + 3 + b ];\r\n\r\n\t\t}\r\n\r\n\t\tif ( IS_LEAF( nodeIndex16, uint16Array ) ) {\r\n\r\n\t\t\tconst count = COUNT( nodeIndex16, uint16Array );\r\n\t\t\tconst offset = OFFSET( nodeIndex32, uint32Array );\r\n\r\n\t\t\tconst mergedLeafCount = 0xffff0000 | count;\r\n\t\t\tcontentsArray[ i * 2 + 0 ] = mergedLeafCount;\r\n\t\t\tcontentsArray[ i * 2 + 1 ] = offset;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tconst rightIndex = 4 * RIGHT_NODE( nodeIndex32, uint32Array ) / BYTES_PER_NODE;\r\n\t\t\tconst splitAxis = SPLIT_AXIS( nodeIndex32, uint32Array );\r\n\r\n\t\t\tcontentsArray[ i * 2 + 0 ] = splitAxis;\r\n\t\t\tcontentsArray[ i * 2 + 1 ] = rightIndex;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tboundsTexture.image.data = boundsArray;\r\n\tboundsTexture.image.width = boundsDimension;\r\n\tboundsTexture.image.height = boundsDimension;\r\n\tboundsTexture.format = RGBAFormat;\r\n\tboundsTexture.type = FloatType;\r\n\tboundsTexture.internalFormat = 'RGBA32F';\r\n\tboundsTexture.minFilter = NearestFilter;\r\n\tboundsTexture.magFilter = NearestFilter;\r\n\tboundsTexture.generateMipmaps = false;\r\n\tboundsTexture.needsUpdate = true;\r\n\r\n\tcontentsTexture.image.data = contentsArray;\r\n\tcontentsTexture.image.width = contentsDimension;\r\n\tcontentsTexture.image.height = contentsDimension;\r\n\tcontentsTexture.format = RGIntegerFormat;\r\n\tcontentsTexture.type = UnsignedIntType;\r\n\tcontentsTexture.internalFormat = 'RG32UI';\r\n\tcontentsTexture.minFilter = NearestFilter;\r\n\tcontentsTexture.magFilter = NearestFilter;\r\n\tcontentsTexture.generateMipmaps = false;\r\n\tcontentsTexture.needsUpdate = true;\r\n\r\n}\r\n\r\nexport class MeshBVHUniformStruct {\r\n\r\n\tconstructor() {\r\n\r\n\t\tthis.autoDispose = true;\r\n\t\tthis.index = new UIntVertexAttributeTexture();\r\n\t\tthis.position = new FloatVertexAttributeTexture();\r\n\t\tthis.bvhBounds = new DataTexture();\r\n\t\tthis.bvhContents = new DataTexture();\r\n\r\n\t\tthis.index.overrideItemSize = 3;\r\n\r\n\t}\r\n\r\n\tupdateFrom( bvh ) {\r\n\r\n\t\tconst { geometry } = bvh;\r\n\r\n\t\tbvhToTextures( bvh, this.bvhBounds, this.bvhContents );\r\n\r\n\t\tthis.index.updateFrom( geometry.index );\r\n\t\tthis.position.updateFrom( geometry.attributes.position );\r\n\r\n\t}\r\n\r\n\tdispose() {\r\n\r\n\t\tconst { index, position, bvhBounds, bvhContents } = this;\r\n\r\n\t\tif ( index ) index.dispose();\r\n\t\tif ( position ) position.dispose();\r\n\t\tif ( bvhBounds ) bvhBounds.dispose();\r\n\t\tif ( bvhContents ) bvhContents.dispose();\r\n\r\n\t}\r\n\r\n}\r\n","export const shaderStructs = /* glsl */`\r\n#ifndef TRI_INTERSECT_EPSILON\r\n#define TRI_INTERSECT_EPSILON 1e-5\r\n#endif\r\n\r\n#ifndef INFINITY\r\n#define INFINITY 1e20\r\n#endif\r\n\r\nstruct BVH {\r\n\r\n\tusampler2D index;\r\n\tsampler2D position;\r\n\r\n\tsampler2D bvhBounds;\r\n\tusampler2D bvhContents;\r\n\r\n};\r\n\r\n// Note that a struct cannot be used for the hit record including faceIndices, faceNormal, barycoord,\r\n// side, and dist because on some mobile GPUS (such as Adreno) numbers are afforded less precision specifically\r\n// when in a struct leading to inaccurate hit results. See KhronosGroup/WebGL#3351 for more details.\r\n`;\r\n\r\nexport const shaderIntersectFunction = /* glsl */`\r\n\r\nuvec4 uTexelFetch1D( usampler2D tex, uint index ) {\r\n\r\n\tuint width = uint( textureSize( tex, 0 ).x );\r\n\tuvec2 uv;\r\n\tuv.x = index % width;\r\n\tuv.y = index / width;\r\n\r\n\treturn texelFetch( tex, ivec2( uv ), 0 );\r\n\r\n}\r\n\r\nivec4 iTexelFetch1D( isampler2D tex, uint index ) {\r\n\r\n\tuint width = uint( textureSize( tex, 0 ).x );\r\n\tuvec2 uv;\r\n\tuv.x = index % width;\r\n\tuv.y = index / width;\r\n\r\n\treturn texelFetch( tex, ivec2( uv ), 0 );\r\n\r\n}\r\n\r\nvec4 texelFetch1D( sampler2D tex, uint index ) {\r\n\r\n\tuint width = uint( textureSize( tex, 0 ).x );\r\n\tuvec2 uv;\r\n\tuv.x = index % width;\r\n\tuv.y = index / width;\r\n\r\n\treturn texelFetch( tex, ivec2( uv ), 0 );\r\n\r\n}\r\n\r\nvec4 textureSampleBarycoord( sampler2D tex, vec3 barycoord, uvec3 faceIndices ) {\r\n\r\n\treturn\r\n\t\tbarycoord.x * texelFetch1D( tex, faceIndices.x ) +\r\n\t\tbarycoord.y * texelFetch1D( tex, faceIndices.y ) +\r\n\t\tbarycoord.z * texelFetch1D( tex, faceIndices.z );\r\n\r\n}\r\n\r\nvoid ndcToCameraRay(\r\n\tvec2 coord, mat4 cameraWorld, mat4 invProjectionMatrix,\r\n\tout vec3 rayOrigin, out vec3 rayDirection\r\n) {\r\n\r\n\t// get camera look direction and near plane for camera clipping\r\n\tvec4 lookDirection = cameraWorld * vec4( 0.0, 0.0, - 1.0, 0.0 );\r\n\tvec4 nearVector = invProjectionMatrix * vec4( 0.0, 0.0, - 1.0, 1.0 );\r\n\tfloat near = abs( nearVector.z / nearVector.w );\r\n\r\n\t// get the camera direction and position from camera matrices\r\n\tvec4 origin = cameraWorld * vec4( 0.0, 0.0, 0.0, 1.0 );\r\n\tvec4 direction = invProjectionMatrix * vec4( coord, 0.5, 1.0 );\r\n\tdirection /= direction.w;\r\n\tdirection = cameraWorld * direction - origin;\r\n\r\n\t// slide the origin along the ray until it sits at the near clip plane position\r\n\torigin.xyz += direction.xyz * near / dot( direction, lookDirection );\r\n\r\n\trayOrigin = origin.xyz;\r\n\trayDirection = direction.xyz;\r\n\r\n}\r\n\r\nfloat intersectsBounds( vec3 rayOrigin, vec3 rayDirection, vec3 boundsMin, vec3 boundsMax ) {\r\n\r\n\t// https://www.reddit.com/r/opengl/comments/8ntzz5/fast_glsl_ray_box_intersection/\r\n\t// https://tavianator.com/2011/ray_box.html\r\n\tvec3 invDir = 1.0 / rayDirection;\r\n\r\n\t// find intersection distances for each plane\r\n\tvec3 tMinPlane = invDir * ( boundsMin - rayOrigin );\r\n\tvec3 tMaxPlane = invDir * ( boundsMax - rayOrigin );\r\n\r\n\t// get the min and max distances from each intersection\r\n\tvec3 tMinHit = min( tMaxPlane, tMinPlane );\r\n\tvec3 tMaxHit = max( tMaxPlane, tMinPlane );\r\n\r\n\t// get the furthest hit distance\r\n\tvec2 t = max( tMinHit.xx, tMinHit.yz );\r\n\tfloat t0 = max( t.x, t.y );\r\n\r\n\t// get the minimum hit distance\r\n\tt = min( tMaxHit.xx, tMaxHit.yz );\r\n\tfloat t1 = min( t.x, t.y );\r\n\r\n\t// set distance to 0.0 if the ray starts inside the box\r\n\tfloat dist = max( t0, 0.0 );\r\n\r\n\treturn t1 >= dist ? dist : INFINITY;\r\n\r\n}\r\n\r\nbool intersectsTriangle(\r\n\tvec3 rayOrigin, vec3 rayDirection, vec3 a, vec3 b, vec3 c,\r\n\tout vec3 barycoord, out vec3 norm, out float dist, out float side\r\n) {\r\n\r\n\t// https://stackoverflow.com/questions/42740765/intersection-between-line-and-triangle-in-3d\r\n\tvec3 edge1 = b - a;\r\n\tvec3 edge2 = c - a;\r\n\tnorm = cross( edge1, edge2 );\r\n\r\n\tfloat det = - dot( rayDirection, norm );\r\n\tfloat invdet = 1.0 / det;\r\n\r\n\tvec3 AO = rayOrigin - a;\r\n\tvec3 DAO = cross( AO, rayDirection );\r\n\r\n\tvec4 uvt;\r\n\tuvt.x = dot( edge2, DAO ) * invdet;\r\n\tuvt.y = - dot( edge1, DAO ) * invdet;\r\n\tuvt.z = dot( AO, norm ) * invdet;\r\n\tuvt.w = 1.0 - uvt.x - uvt.y;\r\n\r\n\t// set the hit information\r\n\tbarycoord = uvt.wxy; // arranged in A, B, C order\r\n\tdist = uvt.z;\r\n\tside = sign( det );\r\n\tnorm = side * normalize( norm );\r\n\r\n\t// add an epsilon to avoid misses between triangles\r\n\tuvt += vec4( TRI_INTERSECT_EPSILON );\r\n\r\n\treturn all( greaterThanEqual( uvt, vec4( 0.0 ) ) );\r\n\r\n}\r\n\r\nbool intersectTriangles(\r\n\tBVH bvh, vec3 rayOrigin, vec3 rayDirection, uint offset, uint count,\r\n\tinout float minDistance,\r\n\r\n\t// output variables\r\n\tout uvec4 faceIndices, out vec3 faceNormal, out vec3 barycoord,\r\n\tout float side, out float dist\r\n) {\r\n\r\n\tbool found = false;\r\n\tvec3 localBarycoord, localNormal;\r\n\tfloat localDist, localSide;\r\n\tfor ( uint i = offset, l = offset + count; i < l; i ++ ) {\r\n\r\n\t\tuvec3 indices = uTexelFetch1D( bvh.index, i ).xyz;\r\n\t\tvec3 a = texelFetch1D( bvh.position, indices.x ).rgb;\r\n\t\tvec3 b = texelFetch1D( bvh.position, indices.y ).rgb;\r\n\t\tvec3 c = texelFetch1D( bvh.position, indices.z ).rgb;\r\n\r\n\t\tif (\r\n\t\t\tintersectsTriangle( rayOrigin, rayDirection, a, b, c, localBarycoord, localNormal, localDist, localSide )\r\n\t\t\t&& localDist < minDistance\r\n\t\t) {\r\n\r\n\t\t\tfound = true;\r\n\t\t\tminDistance = localDist;\r\n\r\n\t\t\tfaceIndices = uvec4( indices.xyz, i );\r\n\t\t\tfaceNormal = localNormal;\r\n\r\n\t\t\tside = localSide;\r\n\t\t\tbarycoord = localBarycoord;\r\n\t\t\tdist = localDist;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\treturn found;\r\n\r\n}\r\n\r\nfloat intersectsBVHNodeBounds( vec3 rayOrigin, vec3 rayDirection, BVH bvh, uint currNodeIndex ) {\r\n\r\n\tvec3 boundsMin = texelFetch1D( bvh.bvhBounds, currNodeIndex * 2u + 0u ).xyz;\r\n\tvec3 boundsMax = texelFetch1D( bvh.bvhBounds, currNodeIndex * 2u + 1u ).xyz;\r\n\treturn intersectsBounds( rayOrigin, rayDirection, boundsMin, boundsMax );\r\n\r\n}\r\n\r\nbool bvhIntersectFirstHit(\r\n\tBVH bvh, vec3 rayOrigin, vec3 rayDirection,\r\n\r\n\t// output variables\r\n\tout uvec4 faceIndices, out vec3 faceNormal, out vec3 barycoord,\r\n\tout float side, out float dist\r\n) {\r\n\r\n\t// stack needs to be twice as long as the deepest tree we expect because\r\n\t// we push both the left and right child onto the stack every traversal\r\n\tint ptr = 0;\r\n\tuint stack[ 60 ];\r\n\tstack[ 0 ] = 0u;\r\n\r\n\tfloat triangleDistance = 1e20;\r\n\tbool found = false;\r\n\twhile ( ptr > - 1 && ptr < 60 ) {\r\n\r\n\t\tuint currNodeIndex = stack[ ptr ];\r\n\t\tptr --;\r\n\r\n\t\t// check if we intersect the current bounds\r\n\t\tfloat boundsHitDistance = intersectsBVHNodeBounds( rayOrigin, rayDirection, bvh, currNodeIndex );\r\n\t\tif ( boundsHitDistance == INFINITY || boundsHitDistance > triangleDistance ) {\r\n\r\n\t\t\tcontinue;\r\n\r\n\t\t}\r\n\r\n\t\tuvec2 boundsInfo = uTexelFetch1D( bvh.bvhContents, currNodeIndex ).xy;\r\n\t\tbool isLeaf = bool( boundsInfo.x & 0xffff0000u );\r\n\r\n\t\tif ( isLeaf ) {\r\n\r\n\t\t\tuint count = boundsInfo.x & 0x0000ffffu;\r\n\t\t\tuint offset = boundsInfo.y;\r\n\r\n\t\t\tfound = intersectTriangles(\r\n\t\t\t\tbvh, rayOrigin, rayDirection, offset, count, triangleDistance,\r\n\t\t\t\tfaceIndices, faceNormal, barycoord, side, dist\r\n\t\t\t) || found;\r\n\r\n\t\t} else {\r\n\r\n\t\t\tuint leftIndex = currNodeIndex + 1u;\r\n\t\t\tuint splitAxis = boundsInfo.x & 0x0000ffffu;\r\n\t\t\tuint rightIndex = boundsInfo.y;\r\n\r\n\t\t\tbool leftToRight = rayDirection[ splitAxis ] >= 0.0;\r\n\t\t\tuint c1 = leftToRight ? leftIndex : rightIndex;\r\n\t\t\tuint c2 = leftToRight ? rightIndex : leftIndex;\r\n\r\n\t\t\t// set c2 in the stack so we traverse it later. We need to keep track of a pointer in\r\n\t\t\t// the stack while we traverse. The second pointer added is the one that will be\r\n\t\t\t// traversed first\r\n\t\t\tptr ++;\r\n\t\t\tstack[ ptr ] = c2;\r\n\r\n\t\t\tptr ++;\r\n\t\t\tstack[ ptr ] = c1;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\treturn found;\r\n\r\n}\r\n\r\n`;\r\n"],"names":["boundingBox"],"mappings":"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AAC,OAAO,EAAE,CAAC;AAC/B,EAAE,KAAK,QAAQ,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;AACrC,EAAE,KAAK,SAAS,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC;AACvC,EAAE,KAAK,WAAW,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC;AAC3C;AACA,EAAE;AACF;AACA;;AC3IY,MAAC,aAAa,aAAa,CAAC;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;AACF;AACY,MAAC,uBAAuB,aAAa,CAAC;AAClD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;"} \ No newline at end of file diff --git a/three-triangle-intersection.js b/three-triangle-intersection.js deleted file mode 100644 index 90e2422..0000000 --- a/three-triangle-intersection.js +++ /dev/null @@ -1,570 +0,0 @@ -import { Vector2, Vector3 } from 'three'; -const _v1 = new Vector3(); -const _v2 = new Vector3(); -const _v3 = new Vector3(); - -// https://github.com/benardp/contours/blob/master/freestyle/view_map/triangle_triangle_intersection.c -function triangleIntersectsTriangle(triangleA, triangleB, additions = { coplanar: false, source: new Vector3(), target: new Vector3() }) { - let p1 = triangleA.a; - let q1 = triangleA.b; - let r1 = triangleA.c; - - let p2 = triangleB.a; - let q2 = triangleB.b; - let r2 = triangleB.c; - - // Compute distance signs of p1, q1 and r1 - // to the plane of triangleB (p2,q2,r2) - - // _v1.copy(triangleB.a).sub(triangleB.c); - // _v2.copy(triangleB.b).sub(triangleB.c); - _v1.copy(p2).sub(r2); - _v2.copy(q2).sub(r2); - let N2 = (new Vector3()).copy(_v1).cross(_v2); - - _v1.copy(p1).sub(r2); - let dp1 = _v1.dot(N2); - _v1.copy(q1).sub(r2); - let dq1 = _v1.dot(N2); - _v1.copy(r1).sub(r2); - let dr1 = _v1.dot(N2); - - if (((dp1 * dq1) > 0) && ((dp1 * dr1) > 0)) { - // console.log("test 1 out"); - return false; - } - - // Compute distance signs of p2, q2 and r2 - // to the plane of triangleA (p1,q1,r1) - _v1.copy(q1).sub(p1); - _v2.copy(r1).sub(p1); - let N1 = (new Vector3()).copy(_v1).cross(_v2); - - _v1.copy(p2).sub(r1); - let dp2 = _v1.dot(N1); - _v1.copy(q2).sub(r1); - let dq2 = _v1.dot(N1); - _v1.copy(r2).sub(r1); - let dr2 = _v1.dot(N1); - - if (((dp2 * dq2) > 0) & ((dp2 * dr2) > 0)) { - // console.log("test 2 out"); - return false; - } - - - // test - // if (zero_test(dp1) || zero_test(dq1) || zero_test(dr1) || zero_test(dp2) || zero_test(dq2) || zero_test(dr2)) { - // additions.coplanar = 1; - // return false; - // } - - additions.N2 = N2; - additions.N1 = N1; - - if (dp1 > 0) { - if (dq1 > 0) { - return tri_tri_intersection(r1, p1, q1, p2, r2, q2, dp2, dr2, dq2, additions); - } - else if (dr1 > 0) { - return tri_tri_intersection(q1, r1, p1, p2, r2, q2, dp2, dr2, dq2, additions); - } - else { - return tri_tri_intersection(p1, q1, r1, p2, q2, r2, dp2, dq2, dr2, additions); - } - } - else if (dp1 < 0) { - if (dq1 < 0) { - return tri_tri_intersection(r1, p1, q1, p2, q2, r2, dp2, dq2, dr2, additions); - } - else if (dr1 < 0) { - return tri_tri_intersection(q1, r1, p1, p2, q2, r2, dp2, dq2, dr2, additions); - } - else { - return tri_tri_intersection(p1, q1, r1, p2, r2, q2, dp2, dr2, dq2, additions); - } - } - else { - if (dq1 < 0) { - if (dr1 >= 0) { - return tri_tri_intersection(q1, r1, p1, p2, r2, q2, dp2, dr2, dq2, additions); - } - else { - return tri_tri_intersection(p1, q1, r1, p2, q2, r2, dp2, dq2, dr2, additions); - } - } - else if (dq1 > 0) { - if (dr1 > 0) { - return tri_tri_intersection(p1, q1, r1, p2, r2, q2, dp2, dr2, dq2, additions); - } - else { - return tri_tri_intersection(q1, r1, p1, p2, q2, r2, dp2, dq2, dr2, additions); - } - } - else { - if (dr1 > 0) { - return tri_tri_intersection(r1, p1, q1, p2, q2, r2, dp2, dq2, dr2, additions); - } - else if (dr1 < 0) { - return tri_tri_intersection(r1, p1, q1, p2, r2, q2, dp2, dr2, dq2, additions); - } - else { - // triangles are co-planar - additions.coplanar = true; - return coplanar_tri_tri3d(p1, q1, r1, p2, q2, r2, N1, N2); - } - } - } - - -} - -function zero_test(x) { - return (x == 0); -} -function tri_tri_intersection(p1, q1, r1, p2, q2, r2, dp2, dq2, dr2, additions) { - if (dp2 > 0) { - if (dq2 > 0) { - return construct_intersection(p1, r1, q1, r2, p2, q2, additions); - } - else if (dr2 > 0) { - return construct_intersection(p1, r1, q1, q2, r2, p2, additions); - } - else { - return construct_intersection(p1, q1, r1, p2, q2, r2, additions); - } - } - else if (dp2 < 0) { - if (dq2 < 0) { - return construct_intersection(p1, q1, r1, r2, p2, q2, additions); - } - else if (dr2 < 0) { - return construct_intersection(p1, q1, r1, q2, r2, p2, additions); - } - else { - return construct_intersection(p1, r1, q1, p2, q2, r2, additions); - } - } - else { - if (dq2 < 0) { - if (dr2 >= 0) { - return construct_intersection(p1, r1, q1, q2, r2, p2, additions); - } - else { - return construct_intersection(p1, q1, r1, p2, q2, r2, additions); - } - } - else if (dq2 > 0) { - if (dr2 > 0) { - return construct_intersection(p1, r1, q1, p2, q2, r2, additions); - } - else { - return construct_intersection(p1, q1, r1, q2, r2, p2, additions); - } - } - else { - if (dr2 > 0) { - return construct_intersection(p1, q1, r1, r2, p2, q2, additions); - } - else if (dr2 < 0) { - return construct_intersection(p1, r1, q1, r2, p2, q2, additions); - } - else { - additions.coplanar = true; - // return coplanar_tri_tri3d(p1, q1, r1, p2, q2, r2, additions); - return coplanar_tri_tri3d(p1, q1, r1, p2, q2, r2, additions.N1, additions.N2); - } - } - } -} - -function coplanar_tri_tri3d(p1, q1, r1, p2, q2, r2, normal_1, normal_2) { - let P1 = new Vector2(), Q1 = new Vector2(), R1 = new Vector2(); - let P2 = new Vector2(), Q2 = new Vector2(), R2 = new Vector2(); - let n_x, n_y, n_z; - - n_x = normal_1.x < 0 ? -normal_1.x : normal_1.x; - n_y = normal_1.y < 0 ? -normal_1.y : normal_1.y; - n_z = normal_1.z < 0 ? -normal_1.z : normal_1.z; - - /* Projection of the triangles in 3D onto 2D such that the area of - the projection is maximized. */ - - if ((n_x > n_z) && (n_x >= n_y)) { // Project onto plane YZ - P1.x = q1.z, P1.y = q1.y; - Q1.x = p1.z, Q1.y = p1.y; - R1.x = r1.z, R1.y = r1.y; - - P2.x = q2.z, P2.y = q2.y; - Q2.x = p2.z, Q2.y = p2.y; - R2.x = r2.z, R2.y = r2.y; - } - else if ((n_y > n_z) && (n_y >= n_x)) { // Project onto plane XZ - P1.x = q1.x, P1.y = q1.z; - Q1.x = p1.x, Q1.y = p1.z; - R1.x = r1.x, R1.y = r1.z; - - P2.x = q2.x, P2.y = q2.z; - Q2.x = p2.x, Q2.y = p2.z; - R2.x = r2.x, R2.y = r2.z; - } - else { // Project onto plane XY - P1.x = p1.x, P1.y = p1.y; - Q1.x = q1.x, Q1.y = q1.y; - R1.x = r1.x, R1.y = r1.y; - - P2.x = p2.x, P2.y = p2.y; - Q2.x = q2.x, Q2.y = q2.y; - R2.x = r2.x, R2.y = r2.y; - } - - return tri_tri_overlap_test_2d(P1, Q1, R1, P2, Q2, R2); - -} - -function tri_tri_overlap_test_2d(p1, q1, r1, p2, q2, r2) { - if (ORIENT_2D(p1, q1, r1) < 0) { - if (ORIENT_2D(p2, q2, r2) < 0) { - return ccw_tri_tri_intersection_2d(p1, r1, q1, p2, r2, q2); - } - else { - return ccw_tri_tri_intersection_2d(p1, r1, q1, p2, q2, r2); - } - } - else { - if (ORIENT_2D(p2, q2, r2) < 0) { - return ccw_tri_tri_intersection_2d(p1, q1, r1, p2, r2, q2); - } - else { - return ccw_tri_tri_intersection_2d(p1, q1, r1, p2, q2, r2); - } - } -} - -function ORIENT_2D(a, b, c) { - return ((a.x - c.x) * (b.y - c.y) - (a.y - c.y) * (b.x - c.y)); -} - -function ccw_tri_tri_intersection_2d(p1, q1, r1, p2, q2, r2) { - if (ORIENT_2D(p2, q2, p1) >= 0) { - if (ORIENT_2D(q2, r2, p1) >= 0) { - if (ORIENT_2D(r2, p2, p1) >= 0) { - return true; - } - else { - return intersection_test_edge(p1, q1, r1, p2, q2, r2); - } - } - else { - if (ORIENT_2D(r2, p2, p1) >= 0) { - return intersection_test_edge(p1, q1, r1, r2, p2, q2); - } - else { - return intersection_test_vertex(p1, q1, r1, p2, q2, r2) - } - } - } - else { - if (ORIENT_2D(q2, r2, p1) >= 0) { - if (ORIENT_2D(r2, p2, p1) >= 0) { - return intersection_test_edge(p1, q1, r2, q2, r2, p2); - } - else { - return intersection_test_vertex(p1, q1, r1, q2, r2, p2); - } - } - else { - return intersection_test_vertex(p1, q1, r1, r2, p2, q2); - } - } -} - -function intersection_test_edge(P1, Q1, R1, P2, Q2, R2) { - if (ORIENT_2D(R2, P2, Q1) >= 0) { - if (ORIENT_2D(P1, P2, Q1) >= 0) { - if (ORIENT_2D(P1, Q1, R2) >= 0) { - return true; - } - else { - return false; - } - } - else { - if (ORIENT_2D(Q1, R1, P2) >= 0) { - if (ORIENT_2D(R1, P1, P2) >= 0) { - return true; - } - else { - return false; - } - } - else { - return false; - } - } - } else { - if (ORIENT_2D(R2, P2, R1) >= 0) { - if (ORIENT_2D(P1, P2, R1) >= 0) { - if (ORIENT_2D(P1, R1, R2) >= 0) { - return true; - } - else { - if (ORIENT_2D(Q1, R1, R2) >= 0) { - return true; - } - else { - return false; - } - } - } - else { - return false; - } - } - else { - return false; - } - } -} - -function intersection_test_vertex(P1, Q1, R1, P2, Q2, R2) { - if (ORIENT_2D(R2, P2, Q1) >= 0) { - if (ORIENT_2D(R2, Q2, Q1) <= 0) { - if (ORIENT_2D(P1, P2, Q1) > 0) { - if (ORIENT_2D(P1, Q2, Q1) <= 0) { - return true; - } - else { - return false; - } - } - else { - if (ORIENT_2D(P1, P2, R1) >= 0) { - if (ORIENT_2D(Q1, R1, P2) >= 0) { - return true; - } - else { - return false; - } - } - else { - return false; - } - } - } - else { - if (ORIENT_2D(P1, Q2, Q1) <= 0) { - if (ORIENT_2D(R2, Q2, R1) <= 0) { - if (ORIENT_2D(Q1, R1, Q2) >= 0) { - return true; - } - else { - return false; - } - } - else { - return false; - } - } - else { - return false; - } - } - } - else { - if (ORIENT_2D(R2, P2, R1) >= 0) { - if (ORIENT_2D(Q1, R1, R2) >= 0) { - if (ORIENT_2D(P1, P2, R1) >= 0) { - return true; - } - else { - return false; - } - } - else { - if (ORIENT_2D(Q1, R1, Q2) >= 0) { - if (ORIENT_2D(R2, R1, Q2) >= 0) { - return true; - } - else { - return false; - } - } - else { - return false; - } - } - } - else { - return false; - } - } -}; -function construct_intersection(p1, q1, r1, p2, q2, r2, additions) { - let alpha; - let N = new Vector3(); - _v1.subVectors(q1, p1); - _v2.subVectors(r2, p1); - N.copy(_v1).cross(_v2); - _v3.subVectors(p2, p1); - if (_v3.dot(N) > 0) { - _v1.subVectors(r1, p1); - N.copy(_v1).cross(_v2); - if (_v3.dot(N) <= 0) { - _v2.subVectors(q2, p1); - N.copy(_v1).cross(_v2); - if (_v3.dot(N) > 0) { - _v1.subVectors(p1, p2); - _v2.subVectors(p1, r1); - alpha = _v1.dot(additions.N2) / _v2.dot(additions.N2); - _v1.copy(_v2).multiplyScalar(alpha); - additions.source.subVectors(p1, _v1); - _v1.subVectors(p2, p1); - _v2.subVectors(p2, r2); - alpha = _v1.dot(additions.N1) / _v2.dot(additions.N1); - _v1.copy(_v2).multiplyScalar(alpha); - additions.target.subVectors(p2, _v1); - return true; - } - else { - _v1.subVectors(p2, p1); - _v2.subVectors(p2, q2); - alpha = _v1.dot(additions.N1) / _v2.dot(additions.N1); - _v1.copy(_v2).multiplyScalar(alpha); - additions.source.subVectors(p2, _v1); - _v1.subVectors(p2, p1); - _v2.subVectors(p2, r2); - alpha = _v1.dot(additions.N1) / _v2.dot(additions.N1); - _v1.copy(_v2).multiplyScalar(alpha); - additions.target.subVectors(p2, _v1); - return true; - } - } - else { - return false; - } - } - else { - _v2.subVectors(q2, p1); - N.copy(_v1).cross(_v2); - if (_v3.dot(N) < 0) { - return false; - } - else { - _v1.subVectors(r1, p1); - N.copy(_v1).cross(_v2); - if (_v3.dot(N) >= 0) { - _v1.subVectors(p1, p2); - _v2.subVectors(p1, r1); - alpha = _v1.dot(additions.N2) / _v2.dot(additions.N2); - _v1.copy(_v2).multiplyScalar(alpha); - additions.source.subVectors(p1, _v1); - _v1.subVectors(p1, p2); - _v2.subVectors(p1, q1); - alpha = _v1.dot(additions.N2) / _v2.dot(additions.N2); - _v1.copy(_v2).multiplyScalar(alpha); - additions.target.subVectors(p1, _v1); - return true; - } - else { - _v1.subVectors(p2, p1); - _v2.subVectors(p2, q2); - alpha = _v1.dot(additions.N1) / _v2.dot(additions.N1); - _v1.copy(_v2).multiplyScalar(alpha); - additions.source.subVectors(p2, _v1); - _v1.subVectors(p1, p2); - _v2.subVectors(p1, q1); - alpha = _v1.dot(additions.N2) / _v2.dot(additions.N2); - _v1.copy(_v2).multiplyScalar(alpha); - additions.target.subVectors(p1, _v1); - return true; - } - } - } -} -function pointOnLine(line, point) { - let ab = _v1.copy(line.end).sub(line.start); - let ac = _v2.copy(point).sub(line.start); - let area = _v3.copy(ab).cross(ac).length(); - let CD = area / ab.length(); - return CD; -} -function lineIntersects(line1, line2, points) { - const r = (new Vector3()).copy(line1.end).sub(line1.start); - const s = (new Vector3()).copy(line2.end).sub(line2.start); - const q = (new Vector3()).copy(line1.start).sub(line2.start); - // const w = _v3.copy( line2.start ).sub( line1.start ); - - let dotqr = q.dot(r); - let dotqs = q.dot(s); - let dotrs = r.dot(s); - let dotrr = r.dot(r); - let dotss = s.dot(s); - - let denom = (dotrr * dotss) - (dotrs * dotrs); - let numer = (dotqs * dotrs) - (dotqr * dotss); - - let t = numer / denom; - let u = (dotqs + t * dotrs) / dotss; - - let p0 = r.multiplyScalar(t).add(line1.start); - let p1 = s.multiplyScalar(u).add(line2.start); - - let onSegment = false; - let intersects = false; - - if ((0 <= t) && (t <= 1) && (0<= u) && (u<=1)) { - onSegment = true; - } - let p0p1Length = _v1.copy(p0).sub(p1).length(); - if (p0p1Length <= 1e-5) { - intersects = true; - } - // console.log("lineIntersects?", intersects, onSegment, p0, p1, denom, numer, t, u); - if (!(intersects && onSegment)) { - // return []; - return false; - } - points && points.push(p0, p1); - // return [p0, p1]; - return true; -} -function getLines(triangle) { - return [ - { start: triangle.a, end: triangle.b }, - { start: triangle.b, end: triangle.c }, - { start: triangle.c, end: triangle.a } - ]; -} - -function checkTrianglesIntersection(triangle1, triangle2, additions = { coplanar: false, source: new Vector3(), target: new Vector3() }) { - // let additions = { - // coplanar: false, - // source: new Vector3(), - // target: new Vector3() - // }; - let triangleIntersects = triangleIntersectsTriangle(triangle1, triangle2, additions); - // console.log("??? 1", triangleIntersects, additions); - additions.triangleCheck = triangleIntersects; - if (!triangleIntersects && additions.coplanar) { - // console.log("check failed, checking lines"); - let triangle1Lines = getLines(triangle1); - let triangle2Lines = getLines(triangle2); - let intersects = false; - for (let i = 0; i < 3; i++) { - intersects = false; - for (let j = 0; j < 3; j++) { - intersects = lineIntersects(triangle1Lines[i], triangle2Lines[j]); - if (intersects) { - break; - } - } - if (intersects) { - break; - } - } - return intersects; - } - return triangleIntersects; -} -export { triangleIntersectsTriangle, checkTrianglesIntersection, getLines, lineIntersects }; \ No newline at end of file