How to slice and remove a mesh from boolean

Hello, I am sort of new to using boolean

I am using three.bvh.csg

and i have this

what I am wondering is if it is possible to boolean the meshes, and then extract each split so that i have separate meshes?

I looked into groups but I dont think thats the way. Any one know how to do this?

const calcParts = (result: THREE.Mesh) => {
  let parts: THREE.BufferGeometry[] = []
  const posMap = {}
  const positions = result.geometry.attributes.position
  if (positions.count === 0) return []
  const normals = result.geometry.attributes.normal
  const uvs = result.geometry.attributes.uv
  const cache = {}
  const hashify = (i) => {
    if (cache[i]) return cache[i]
    cache[i] = positions.getX(i).toFixed(2) + positions.getY(i).toFixed(2) + positions.getZ(i).toFixed(2)
    return cache[i]
  }
  for (let i = 0; i < positions.count; i += 3) {
    const vert1 = hashify(i)
    const vert2 = hashify(i + 1)
    const vert3 = hashify(i + 2)
    if (!posMap[vert1]) posMap[vert1] = []
    if (!posMap[vert2]) posMap[vert2] = []
    if (!posMap[vert3]) posMap[vert3] = []
    posMap[vert1].push(vert2, vert3)
    posMap[vert2].push(vert1, vert3)
    posMap[vert3].push(vert1, vert2)
  }
  let noPoses = {}
  while (Object.keys(noPoses).length < positions.count) {
    const availableIs: number[] = [] //Array(positions.length).fill()
    for (let i = 0; i < positions.count; i++) {
      if (!noPoses[hashify(i)]) availableIs.push(i)
    }
    if (availableIs.length === 0) break
    const randomPos = hashify(availableIs[0])
    const posesCollected = {}
    const posesToGoThrough = [randomPos]
    while (true) {
      if (posesToGoThrough.length === 0) break
      const pos = posesToGoThrough.pop()
      posesCollected[pos] = true
      const cs = posMap[pos]
      for (let i = 0; i < cs.length; i++) {
        if (!posesCollected[cs[i]]) posesToGoThrough.push(cs[i])
      }
    }
    const part = new THREE.BufferGeometry()
    const newPositions: number[] = []
    const newNormals: number[] = []
    const newUvs: number[] = []
    const madeTries: { [key: string]: boolean } = {}
    for (let i = 0; i < positions.count; i += 3) {
      const vert1 = hashify(i)
      const vert2 = hashify(i + 1)
      const vert3 = hashify(i + 2)
      const combined = vert1 + vert2 + vert3
      if (posesCollected[vert1] && posesCollected[vert2] && posesCollected[vert3] && !madeTries[combined]) {
        madeTries[vert1 + vert2 + vert3] = true
        madeTries[vert2 + vert3 + vert1] = true
        madeTries[vert3 + vert1 + vert2] = true
        noPoses[vert1] = true
        noPoses[vert2] = true
        noPoses[vert3] = true
        newPositions.push(positions.getX(i), positions.getY(i), positions.getZ(i))
        newPositions.push(positions.getX(i + 1), positions.getY(i + 1), positions.getZ(i + 1))
        newPositions.push(positions.getX(i + 2), positions.getY(i + 2), positions.getZ(i + 2))
        newNormals.push(normals.getX(i), normals.getY(i), normals.getZ(i))
        newNormals.push(normals.getX(i + 1), normals.getY(i + 1), normals.getZ(i + 1))
        newNormals.push(normals.getX(i + 2), normals.getY(i + 2), normals.getZ(i + 2))
        newUvs.push(uvs.getX(i), uvs.getY(i))
        newUvs.push(uvs.getX(i + 1), uvs.getY(i + 1))
        newUvs.push(uvs.getX(i + 2), uvs.getY(i + 2))
      }
    }
    part.setAttribute('position', new THREE.BufferAttribute(new Float32Array(newPositions), 3))
    part.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(newNormals), 3))
    part.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(newUvs), 3))
    parts.push(part)
  }
  return parts
}

you use it like this:

const meshes = calcParts(mergedMesh)

real world example, it’s using csg to slice suzi, and then uses calcParts to obtain the resulting fragments:
https://codesandbox.io/p/sandbox/csg-slice-k4qfiz?file=%2Fsrc%2Fparts.tsx

2 Likes

witchcraft!! :smiley: