Three.js 具有三个CSG的三维布尔运算

Three.js 具有三个CSG的三维布尔运算,three.js,autodesk-forge,autodesk-viewer,csg,threecsg,Three.js,Autodesk Forge,Autodesk Viewer,Csg,Threecsg,下面的示例如下: 使用Three.js with,我试图对模型中的节点执行3D布尔运算。例如,如果我有一个带窗的墙,我想对它执行invert(),只得到窗 我有一个函数,返回一个节点的多边形的所有顶点,下面是一个没有孔的对象顶点的例子 我使用三个CSG,如下所示: const geometryThree = new THREE.Geometry(); geometryThree.vertices.push( ...vertices ); co

下面的示例如下:

使用Three.js with,我试图对模型中的节点执行3D布尔运算。例如,如果我有一个带窗的墙,我想对它执行
invert()
,只得到窗

我有一个函数,返回一个节点的多边形的所有顶点,下面是一个没有孔的对象顶点的例子

我使用三个CSG,如下所示:

    const geometryThree = new THREE.Geometry();

    geometryThree.vertices.push(
        ...vertices
    );

    const geometryCsg = new ThreeBSP(geometryThree);
但这正是我在《geometryCsg》中得到的:

"{
    "matrix": {
        "elements": {
            "0": 1,
            "1": 0,
            "2": 0,
            "3": 0,
            "4": 0,
            "5": 1,
            "6": 0,
            "7": 0,
            "8": 0,
            "9": 0,
            "10": 1,
            "11": 0,
            "12": 0,
            "13": 0,
            "14": 0,
            "15": 1
        }
    },
    "tree": {
        "polygons": []
    }
}"
我想是因为

如何使顶点数组成为适当的
Three.Geometry
,使面不会为空?不起作用


是否有一个示例使用形状的多边形作为矢量数组并将其转换为csg?

我刚刚使用三个csg制作了一个演示:查看器网格有一个顶点索引数组,因此无法直接从中创建BSP。另外,我的代码使用web worker处理网格,以保持UI对大型模型的响应,因此我需要首先将网格数据发送给worker并重建一个简单的三网格。在worker端,代码如下所示:

// Sends component geometry to the web worker  
postComponent (dbId) {

  const geometry = this.getComponentGeometry(dbId)

  const msg = {
    boundingBox: this.getComponentBoundingBox(dbId),
    matrixWorld: geometry.matrixWorld,
    nbMeshes: geometry.meshes.length,
    msgId: 'MSG_ID_COMPONENT',
    dbId
  }

  geometry.meshes.forEach((mesh, idx) => {

    msg['positions' + idx] = mesh.positions
    msg['indices' + idx] = mesh.indices
    msg['stride' + idx] = mesh.stride
  })

  this.worker.postMessage(msg)
}

// get geometry for all fragments in a component
getComponentGeometry (dbId) {

  const fragIds = Toolkit.getLeafFragIds(
    this.viewer.model, dbId)

  let matrixWorld = null

  const meshes = fragIds.map((fragId) => {

    const renderProxy = this.viewer.impl.getRenderProxy(
      this.viewer.model,
      fragId)

    const geometry = renderProxy.geometry

    const attributes = geometry.attributes

    const positions = geometry.vb
      ? geometry.vb
      : attributes.position.array

    const indices = attributes.index.array || geometry.ib

    const stride = geometry.vb ? geometry.vbstride : 3

    const offsets = geometry.offsets

    matrixWorld = matrixWorld ||
    renderProxy.matrixWorld.elements

    return {
      positions,
      indices,
      offsets,
      stride
    }
  })

  return {
    matrixWorld,
    meshes
  }
}


// On the worker side reconstruct THREE.Mesh
// from received data and create ThreeBSP
function buildComponentMesh (data) {

  const vertexArray = []

  for (let idx=0; idx < data.nbMeshes; ++idx) {

    const meshData = {
      positions: data['positions' + idx],
      indices: data['indices' + idx],
      stride: data['stride' + idx]
    }

    getMeshGeometry (meshData, vertexArray)
  }

  const geometry = new THREE.Geometry()

  for (var i = 0; i < vertexArray.length; i += 3) {

    geometry.vertices.push(vertexArray[i])
    geometry.vertices.push(vertexArray[i + 1])
    geometry.vertices.push(vertexArray[i + 2])

    const face = new THREE.Face3(i, i + 1, i + 2)

    geometry.faces.push(face)
  }

  const matrixWorld = new THREE.Matrix4()

  matrixWorld.fromArray(data.matrixWorld)

  const mesh = new THREE.Mesh(geometry)

  mesh.applyMatrix(matrixWorld)

  mesh.boundingBox = data.boundingBox

  mesh.bsp = new ThreeBSP(mesh)

  mesh.dbId = data.dbId

  return mesh
}

function getMeshGeometry (data, vertexArray) {

  const offsets = [{
    count: data.indices.length,
    index: 0,
    start: 0}
  ]

  for (var oi = 0, ol = offsets.length; oi < ol; ++oi) {

    var start = offsets[oi].start
    var count = offsets[oi].count
    var index = offsets[oi].index

    for (var i = start, il = start + count; i < il; i += 3) {

      const a = index + data.indices[i]
      const b = index + data.indices[i + 1]
      const c = index + data.indices[i + 2]

      const vA = new THREE.Vector3()
      const vB = new THREE.Vector3()
      const vC = new THREE.Vector3()

      vA.fromArray(data.positions, a * data.stride)
      vB.fromArray(data.positions, b * data.stride)
      vC.fromArray(data.positions, c * data.stride)

      vertexArray.push(vA)
      vertexArray.push(vB)
      vertexArray.push(vC)
    }
  }
}
//将组件几何图形发送给web工作程序
后置组件(dbId){
const geometry=this.getComponentGeometry(dbId)
常数msg={
boundingBox:this.getComponentBoundingBox(dbId),
matrixWorld:geometry.matrixWorld,
NBMESH:geometry.meshes.length,
msgId:'MSG_ID_COMPONENT',
dbId
}
geometry.mesh.forEach((mesh,idx)=>{
msg['positions'+idx]=网格位置
msg['index'+idx]=网格索引
msg['stride'+idx]=mesh.stride
})
this.worker.postMessage(msg)
}
//获取组件中所有碎片的几何图形
getComponentGeometry(dbId){
const fragIds=Toolkit.getLeafFragIds(
this.viewer.model,dbId)
设matrixWorld=null
常量网格=fragIds.map((fragId)=>{
const renderProxy=this.viewer.impl.getRenderProxy(
这个.viewer.model,
弗拉基德)
常量几何体=renderProxy.geometry
常量属性=geometry.attributes
常量位置=geometry.vb
?geometry.vb
:attributes.position.array
常量索引=attributes.index.array | | geometry.ib
常量步长=geometry.vb?geometry.vb步长:3
常量偏移=几何体。偏移
matrixWorld=matrixWorld||
renderProxy.matrixWorld.elements
返回{
位置,
指数
抵消,
大步走
}
})
返回{
matrixWorld,
网格
}
}
//在工人侧重建三个网格
//从接收到的数据创建三个BSP
函数buildComponentMesh(数据){
常量顶点阵列=[]
对于(让idx=0;idx

我的示例的完整代码就在那里:还有实时演示。

这个示例对模型中的所有节点都有效吗?这就是为什么你需要一个网络工作者的原因吗?不是所有的节点,只有墙和地板,但如果你处理一个大型模型,它需要大量的CPU。使用web worker可以防止浏览器崩溃和UI响应。将单个节点转换为3BSP的部分就是我刚才发布的全部代码。仔细看看它在做什么。您可以看到,它在“buildComponentMesh”方法的末尾创建了一个新的3BSP。如果您不想使用工人,那么调整逻辑应该相当简单。我明白了,非常感谢。你试过使用csg减法吗?我在这里得到了一个错误:当我尝试像这样反转几何体时,除法器未定义:
let a=new ThreeBSP(new THREE.geometry());a、 subtract(geometryCsg)
您是在向新几何体添加一些顶点/面,还是仅此代码?你正在从一个空的几何体中减去一些东西,我不确定这是否有效。上的3个示例运行良好,因此问题一定是您的输入。我想反转形状,它们在原始CSG中有一个反转方法:但看起来ThreeCSG没有此方法。