【问题标题】:Three.js - can I detect geometry 'islands' when importing?Three.js - 我可以在导入时检测几何“岛屿”吗?
【发布时间】:2015-01-07 02:39:02
【问题描述】:

我将 .3DS 模型导入 Blender 2.72b,然后使用 Three.js 导入/导出插件导出它们。这些模型有多个几何“岛”(连接面和顶点的单独组),每个都有自己的材料。我希望能够将每种材料与其对应的岛配对,而不必创建单独的 THREE.Geometry 对象。经过一番挖掘,我找到了this question,它建议使用 THREE.MeshFaceMaterial 为一个对象实现多种材质。唯一的问题是该示例中的几何图形是一个简单的立方体,而我的模型有数百个面分布在 2-5 个岛屿上。

Three.js 是否具有识别网格中几何“孤岛”的功能?

【问题讨论】:

    标签: three.js


    【解决方案1】:

    没有。 three.js 没有识别网格中几何“孤岛”的功能。

    当使用MeshFaceMaterial 时,WebGLRenderer 无论如何都会将几何体分成块——每种材料一个块。这样做是因为 WebGL 支持每个几何图形一个着色器。

    我不会合并你所有的几何图形,然后使用MeshFaceMaterial,只是为了让渲染器将单个几何图形分开。

    如果您愿意,可以合并共享单一材质的几何图形。

    three.js r.69

    【讨论】:

    • 谢谢。我想我要走 SceneLoader 路线。我会将每个对象视为一个场景(并将其从 Blender 中导出),然后当我加载每个场景时,我会将不同的部分组合在一起并将每个组视为一个对象。
    【解决方案2】:

    我尝试了一个函数,但仍然不准确,它产生的几何图形比非连接几何图形多:

    如果有人可以看一看,那就太棒了。

    function groupGeometryIntoNonConnectedGeometries(geometry) {
            const material = new THREE.MeshBasicMaterial({
                side: THREE.DoubleSide,
                vertexColors: THREE.VertexColors
            });
            let geometryArray = [];
            const indexArray = geometry.index.array;
            const positionArray = geometry.attributes.position.array;
            const positionCount = geometry.attributes.position.count;
            const color = new THREE.Vector3(geometry.attributes.color.array[0], geometry.attributes.color.array[1], geometry.attributes.color.array[2]);
            const totalTriangles = indexArray.length / 3;
            let geometryCount = 0;
            let indexValueAlreadyVisited = new Uint8Array(indexArray.length);   
            let structure = [];
                /*
                 * indexValue: {
                 *  child: [ [indexval0, indexval1], [] ],
                 *  parent: null
                 * }
                 */
            // Initialize Structure:
            for (var vextexIdx=0; vextexIdx<positionCount; vextexIdx++) {
                structure[vextexIdx] = {
                    child: [],
                    parent: null
                }
            }   
            
            for (idx=0; idx<totalTriangles; idx++) {
                const geoIndex1 = indexArray[idx*3];
                const geoIndex2 = indexArray[idx*3+1];
                const geoIndex3 = indexArray[idx*3+2];
                const triangleIndexVertexArray = [ geoIndex1, geoIndex2, geoIndex3 ].sort(function(a, b) { 
                    return a - b; 
                });
                structure[ triangleIndexVertexArray[0] ].child.push(triangleIndexVertexArray[1], triangleIndexVertexArray[2]);
                structure[ triangleIndexVertexArray[1] ].parent = triangleIndexVertexArray[0];
                structure[ triangleIndexVertexArray[2] ].parent = triangleIndexVertexArray[0];              
            }
            let count = 0;
            let currentCount = 0;
            let geometryStructureArray = [];
            
            for (let strIdx=0; strIdx<structure.length; strIdx++) {
                if (structure[strIdx].parent == null) {
                    currentCount = count;
                    geometryStructureArray[currentCount] = {
                        name: "G_" + currentCount,
                        indexMap: {},
                        currentIndex: 0,
                        indexArray: [],
                        positionArray: [],
                        colorArray: []
                    };
                    count += 1;
                }
                if (structure[strIdx].child.length > 0) {
                    const childLen = structure[strIdx].child.length / 2;
                    for (let childIdx=0; childIdx<childLen; childIdx++) {
                        const vertexIndex0 = strIdx;
                        const vertexIndex1 = structure[strIdx].child[childIdx*2];
                        const vertexIndex2 = structure[strIdx].child[childIdx*2+1];
                        const v0 = new THREE.Vector3( positionArray[strIdx*3], positionArray[strIdx*3+1], positionArray[strIdx*3+2] );
                        const v1 = new THREE.Vector3( positionArray[vertexIndex1*3], positionArray[vertexIndex1*3+1], positionArray[vertexIndex1*3+2] );
                        const v2 = new THREE.Vector3( positionArray[vertexIndex2*3], positionArray[vertexIndex2*3+1], positionArray[vertexIndex2*3+2] );
                        
                        // check vertex0
                        if (geometryStructureArray[currentCount].indexMap[vertexIndex0] == undefined) {
                            geometryStructureArray[currentCount].indexMap[vertexIndex0] = geometryStructureArray[currentCount].currentIndex;
                            geometryStructureArray[currentCount].indexArray.push(geometryStructureArray[currentCount].currentIndex);
                            geometryStructureArray[currentCount].positionArray.push(v0.x, v0.y, v0.z);
                            geometryStructureArray[currentCount].colorArray.push(color.x, color.y, color.z);
                            geometryStructureArray[currentCount].currentIndex += 1;
                        } else {
                            geometryStructureArray[currentCount].indexArray.push(geometryStructureArray[currentCount].indexMap[vertexIndex0]);
                        }
                        
                        // check vertex1
                        if (geometryStructureArray[currentCount].indexMap[vertexIndex1] == undefined) {
                            geometryStructureArray[currentCount].indexMap[vertexIndex1] = geometryStructureArray[currentCount].currentIndex;
                            geometryStructureArray[currentCount].indexArray.push(geometryStructureArray[currentCount].currentIndex);
                            geometryStructureArray[currentCount].positionArray.push(v1.x, v1.y, v1.z);
                            geometryStructureArray[currentCount].colorArray.push(color.x, color.y, color.z);
                            geometryStructureArray[currentCount].currentIndex += 1;
                        } else {
                            geometryStructureArray[currentCount].indexArray.push(geometryStructureArray[currentCount].indexMap[vertexIndex1]);
                        }
                        
                        // check vertex1
                        if (geometryStructureArray[currentCount].indexMap[vertexIndex2] == undefined) {
                            geometryStructureArray[currentCount].indexMap[vertexIndex2] = geometryStructureArray[currentCount].currentIndex;
                            geometryStructureArray[currentCount].indexArray.push(geometryStructureArray[currentCount].currentIndex);
                            geometryStructureArray[currentCount].positionArray.push(v2.x, v2.y, v2.z);
                            geometryStructureArray[currentCount].colorArray.push(color.x, color.y, color.z);
                            geometryStructureArray[currentCount].currentIndex += 1;
                        } else {
                            geometryStructureArray[currentCount].indexArray.push(geometryStructureArray[currentCount].indexMap[vertexIndex2]);
                        }
                        
                    }
                }   
            }
            
            // Convert to geometryArray:
            const geometryStructureArrayLen = geometryStructureArray.length;
            const object3d = new THREE.Object3D();
            
            for (let geoIdx=0; geoIdx<geometryStructureArrayLen; geoIdx++) {
                const geo = new THREE.BufferGeometry();
                geo.name = "G_" + geoIdx;
                const geoPositions = new Float32Array(geometryStructureArray[geoIdx].positionArray);
                const geoColors = new Float32Array(geometryStructureArray[geoIdx].colorArray);
                const geoIndices = new Uint32Array(geometryStructureArray[geoIdx].indexArray);
                //console.log(geoIdx, "geoPositions: ", geoPositions);
                //console.log(geoIdx, "geoColors: ", geoColors);
                //console.log(geoIdx, "geoIndices: ", geoIndices);
                geo.index = new THREE.BufferAttribute(geoIndices, 1, false);
                
                geo.attributes.position = new THREE.BufferAttribute(geoPositions, 3, false);
                geo.attributes.color = new THREE.BufferAttribute(geoColors, 3, true);
                geo.computeBoundingSphere();
                geo.computeBoundingBox();
                
                const mesh = new THREE.Mesh(geo, material);
                mesh.name = "M_" + geoIdx;
                object3d.add(mesh);
            }
            //return [structure, geometryStructureArray, object3d, count];
            return object3d;
        }
    

    最好的问候

    【讨论】:

      【解决方案3】:

      这是我认为正确的方法:

      function unmergeGeometryArray(geometry) {
              // Asumptions:
              // geometry is BufferGeometry 
              // The geometry has no index duplicates (2 equal positions with different index) neither empty triangles, the geometry has been processed with mergeVertices function
              // normal attribute is discarded, can be recomputed after, only color and position attributes are taken into account
              
              const material = new THREE.MeshBasicMaterial({
                  side: THREE.DoubleSide,
                  vertexColors: THREE.VertexColors
              });
              
              const indexArray = geometry.index.array;
              const positionArray = geometry.attributes.position.array;
              const positionCount = geometry.attributes.position.count;
              const totalTriangles = indexArray.length / 3;
              
              let triangleVisitedArray = new Uint8Array(totalTriangles);
              let indexVisitedArray = new Uint8Array(positionCount);
              let indexToTriangleIndexMap = [];
              
              let missingVertices = positionCount;
              let missingTriangles = totalTriangles;
              
              // Functions:
              function computeTrianglesRecursive(index, out){ 
                  //console.log("- start of computeTriangles with index:", index);    
                  if (indexVisitedArray[index] === 1 || missingVertices === 0 || missingTriangles === 0) {
                      return;
                  }       
                  indexVisitedArray[index] = 1;
                  missingVertices -= 1;       
                  let triangleIndexArray = indexToTriangleIndexMap[index];        
                  for(let i=0; i<indexToTriangleIndexMap[index].length; i++) {
                      let triangleIndex = indexToTriangleIndexMap[index][i];
                      if (triangleVisitedArray[triangleIndex] === 0) {
                          triangleVisitedArray[triangleIndex] = 1
                          missingTriangles -= 1;
                          //console.log("-- index: ", index, "; i: ", i, "; triangleIndex: ", triangleIndex);
                          out.push(triangleIndex);
                          childIndex1 = indexArray[triangleIndex*3+1];
                          computeTriangles(childIndex1, out);
                          childIndex2 = indexArray[triangleIndex*3+2];
                          computeTriangles(childIndex2, out);
                      }
                  }
              }
              
              function computeTriangles(indexTocheck){
                  let out = [];
                  let startIndex = indexTocheck;  
                  let indexToCheckArray = [indexTocheck];
                  let i = 0;
                  
                  while (i<indexToCheckArray.length) {
                      let index = indexToCheckArray[i];
                      if (indexVisitedArray[index] == 0) {
                          indexVisitedArray[index] = 1;
                          missingVertices -= 1;   
                          let triangleIndexArray = indexToTriangleIndexMap[index];
                          for(let j=0; j<indexToTriangleIndexMap[index].length; j++) {
                              let triangleIndex = indexToTriangleIndexMap[index][j];
                              if (triangleVisitedArray[triangleIndex] === 0) {
                                  triangleVisitedArray[triangleIndex] = 1;
                                  missingTriangles -= 1;
                                  out.push(triangleIndex);
                                  let rootIndex = indexArray[triangleIndex*3];
                                  let child1Index = indexArray[triangleIndex*3+1];
                                  let child2Index = indexArray[triangleIndex*3+2];
                                  
                                  if (indexToCheckArray.indexOf(rootIndex) === -1) {
                                      indexToCheckArray.push(rootIndex);
                                  }
                                  
                                  if (indexToCheckArray.indexOf(child1Index) === -1) {
                                      indexToCheckArray.push(child1Index);
                                  }
                                  
                                  if (indexToCheckArray.indexOf(child2Index) === -1) {
                                      indexToCheckArray.push(child2Index);
                                  }
                              }
                          }
                      }
                      i +=1;
                  }
                  return out;
              }
              
              // In the first loop we reorder indices asc order + generate map
              for (triangleIndex=0; triangleIndex<totalTriangles; triangleIndex++) {
                  const geoIndex1 = indexArray[triangleIndex*3];
                  const geoIndex2 = indexArray[triangleIndex*3+1];
                  const geoIndex3 = indexArray[triangleIndex*3+2];
                  const triangleIndexVertexArray = [ geoIndex1, geoIndex2, geoIndex3 ].sort(function(a, b) { 
                      return a - b; 
                  });
                  if (indexToTriangleIndexMap[geoIndex1] === undefined) {
                      indexToTriangleIndexMap[geoIndex1] = [triangleIndex];
                  } else {
                      indexToTriangleIndexMap[geoIndex1].push(triangleIndex);
                  }
                  if (indexToTriangleIndexMap[geoIndex2] === undefined) {
                      indexToTriangleIndexMap[geoIndex2] = [triangleIndex];
                  } else {
                      indexToTriangleIndexMap[geoIndex2].push(triangleIndex);
                  }
                  if (indexToTriangleIndexMap[geoIndex3] === undefined) {
                      indexToTriangleIndexMap[geoIndex3] = [triangleIndex];
                  } else {
                      indexToTriangleIndexMap[geoIndex3].push(triangleIndex);
                  }
                  //indexArray[triangleIndex*3] = triangleIndexVertexArray[0];
                  //indexArray[triangleIndex*3+1] = triangleIndexVertexArray[1];
                  //indexArray[triangleIndex*3+2] = triangleIndexVertexArray[2];
              }
              
              let geometryTriangleArray = [];
              let index = 0;
              while (index<indexToTriangleIndexMap.length && missingVertices>0 && missingTriangles>0){
                  let out = [];
                  if (indexVisitedArray[index] === 0) {
                      out = computeTriangles(index);
                  }
                  if (out.length > 0) {
                      geometryTriangleArray.push(out);
                  }
                  index += 1;
              }
              
              let geometryArray = [];
              for (let i=0; i<geometryTriangleArray.length; i++) {
                  let out = {
                      positionArray: [],
                      colorArray: [],
                      indexArray: [],
                      indexMap: [],
                      currentIndex: 0
                  }
                  let triangleArray = geometryTriangleArray[i];
                  
                  for (let j=0; j<triangleArray.length; j++) {
                      let triangleIndex = triangleArray[j];
                      let rootIndex = indexArray[triangleIndex*3];
                      if (out.indexMap[rootIndex] === undefined) {
                          out.indexMap[rootIndex] = out.currentIndex;
                          // add vertex position and color
                          out.positionArray.push(
                              geometry.attributes.position.array[rootIndex*3],
                              geometry.attributes.position.array[rootIndex*3+1],
                              geometry.attributes.position.array[rootIndex*3+2]
                          );
                          if (geometry.attributes.color != undefined) {
                              out.colorArray.push(
                                  geometry.attributes.color.array[rootIndex*3],
                                  geometry.attributes.color.array[rootIndex*3+1],
                                  geometry.attributes.color.array[rootIndex*3+2]
                              );
                          }
                          out.currentIndex += 1;
                      }
                      
                      let child1Index = indexArray[triangleIndex*3+1];
                      if (out.indexMap[child1Index] === undefined) {
                          out.indexMap[child1Index] = out.currentIndex;
                          // add vertex position and color
                          out.positionArray.push(
                              geometry.attributes.position.array[child1Index*3],
                              geometry.attributes.position.array[child1Index*3+1],
                              geometry.attributes.position.array[child1Index*3+2]
                          );
                          if (geometry.attributes.color != undefined) {
                              out.colorArray.push(
                                  geometry.attributes.color.array[child1Index*3],
                                  geometry.attributes.color.array[child1Index*3+1],
                                  geometry.attributes.color.array[child1Index*3+2]
                              );
                          }
                          
                          out.currentIndex += 1;
                      }
                      
                      let child2Index = indexArray[triangleIndex*3+2];
                      if (out.indexMap[child2Index] === undefined) {
                          out.indexMap[child2Index] = out.currentIndex;
                          // add vertex position and color
                          out.positionArray.push(
                              geometry.attributes.position.array[child2Index*3],
                              geometry.attributes.position.array[child2Index*3+1],
                              geometry.attributes.position.array[child2Index*3+2]
                          );
                          if (geometry.attributes.color != undefined) {
                              out.colorArray.push(
                                  geometry.attributes.color.array[child2Index*3],
                                  geometry.attributes.color.array[child2Index*3+1],
                                  geometry.attributes.color.array[child2Index*3+2]
                              );
                          }
                          
                          out.currentIndex += 1;
                      }
                      
                      // Add indices:
                      out.indexArray.push(out.indexMap[rootIndex], out.indexMap[child1Index], out.indexMap[child2Index]);
                  }
                  
                  const geoPositions = new Float32Array(out.positionArray);
                  const geoColors = new Float32Array(out.colorArray);
                  const geoIndices = new Uint32Array(out.indexArray);
                  const geo = new THREE.BufferGeometry();
                  geo.name = "G_" + i;
                  geo.index = new THREE.BufferAttribute(geoIndices, 1, false);
                  geo.attributes.position = new THREE.BufferAttribute(geoPositions, 3, false);
                  geo.attributes.color = new THREE.BufferAttribute(geoColors, 3, true);
                  geo.computeBoundingSphere();
                  geo.computeBoundingBox();
                  geometryArray.push(geo);
              }
              return geometryArray;
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多