Babylon.js 第34章 合并网格

发布于:2022-12-21 ⋅ 阅读:(843) ⋅ 点赞:(0)

 

目录

一、合并网格方法

二、详细内容


一、合并网格方法

轻松地将多个网格合并到单个网格,请使用类的MergeMeshes静态Mesh

var newMesh = BABYLON.Mesh.MergeMeshes(options)

options的参数:

属性 描述
arrayOfMeshes 一组网格。它们都应该是相同的材料。
disposeSource(可选) 当为 true(默认)时,源网格将在完成后被处理。
allow32BitsIndices(可选) 当顶点的总和 > 64k 时,必须将其设置为 true。
meshSubclass 可选) 设置后,顶点插入此网格。然后可以将网格合并到一个网格子类中。
subdivideWithSubMeshes(可选) 当为真(默认为假)时,将网格细分为具有网格源的子网格数组。
multiMultiMaterials(可选) 当为 true(默认为 false)时,细分网格并接受多个多材质,忽略 subdivideWithSubMeshes。

由于multiMultiMaterials默认为 false,因此生成的合并网格将仅应用一个材质(取自第一个网格)

注意:当你合并克隆的网格时,你需要在调用函数之前用 computeWorldMatrix 更新网格的世界矩阵。

二、详细内容

注意:本文介绍了内部合并过程。您还可以使用BABYLON.VertexDataobject 及其merge()函数来获得更简单的解决方案。

var mergeMeshes = function (meshName, arrayObj, scene) {
  var arrayPos = [];
  var arrayNormal = [];
  var arrayUv = [];
  var arrayUv2 = [];
  var arrayColor = [];
  var arrayMatricesIndices = [];
  var arrayMatricesWeights = [];
  var arrayIndice = [];
  var savedPosition = [];
  var savedNormal = [];
  var newMesh = new BABYLON.Mesh(meshName, scene);
  var UVKind = true;
  var UV2Kind = true;
  var ColorKind = true;
  var MatricesIndicesKind = true;
  var MatricesWeightsKind = true;

  for (var i = 0; i != arrayObj.length; i++) {
    if (!arrayObj[i].isVerticesDataPresent([BABYLON.VertexBuffer.UVKind])) UVKind = false;
    if (!arrayObj[i].isVerticesDataPresent([BABYLON.VertexBuffer.UV2Kind])) UV2Kind = false;
    if (!arrayObj[i].isVerticesDataPresent([BABYLON.VertexBuffer.ColorKind])) ColorKind = false;
    if (!arrayObj[i].isVerticesDataPresent([BABYLON.VertexBuffer.MatricesIndicesKind])) MatricesIndicesKind = false;
    if (!arrayObj[i].isVerticesDataPresent([BABYLON.VertexBuffer.MatricesWeightsKind])) MatricesWeightsKind = false;
  }

  for (i = 0; i != arrayObj.length; i++) {
    var ite = 0;
    var iter = 0;
    arrayPos[i] = arrayObj[i].getVerticesData(BABYLON.VertexBuffer.PositionKind);
    arrayNormal[i] = arrayObj[i].getVerticesData(BABYLON.VertexBuffer.NormalKind);
    if (UVKind) arrayUv = arrayUv.concat(arrayObj[i].getVerticesData(BABYLON.VertexBuffer.UVKind));
    if (UV2Kind) arrayUv2 = arrayUv2.concat(arrayObj[i].getVerticesData(BABYLON.VertexBuffer.UV2Kind));
    if (ColorKind) arrayColor = arrayColor.concat(arrayObj[i].getVerticesData(BABYLON.VertexBuffer.ColorKind));
    if (MatricesIndicesKind) arrayMatricesIndices = arrayMatricesIndices.concat(arrayObj[i].getVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind));
    if (MatricesWeightsKind) arrayMatricesWeights = arrayMatricesWeights.concat(arrayObj[i].getVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind));

    var maxValue = savedPosition.length / 3;

    arrayObj[i].computeWorldMatrix(true);
    var worldMatrix = arrayObj[i].getWorldMatrix();

    for (var ite = 0; ite != arrayPos[i].length; ite += 3) {
      var vertex = BABYLON.Vector3.TransformCoordinates(new BABYLON.Vector3(arrayPos[i][ite], arrayPos[i][ite + 1], arrayPos[i][ite + 2]), worldMatrix);
      savedPosition.push(vertex.x);
      savedPosition.push(vertex.y);
      savedPosition.push(vertex.z);
    }

    for (var iter = 0; iter != arrayNormal[i].length; iter += 3) {
      var vertex = BABYLON.Vector3.TransformNormal(new BABYLON.Vector3(arrayNormal[i][iter], arrayNormal[i][iter + 1], arrayNormal[i][iter + 2]), worldMatrix);
      savedNormal.push(vertex.x);
      savedNormal.push(vertex.y);
      savedNormal.push(vertex.z);
    }

    var tmp = arrayObj[i].getIndices();
    for (it = 0; it != tmp.length; it++) {
      arrayIndice.push(tmp[it] + maxValue);
    }
    arrayIndice = arrayIndice.concat(tmp);

    arrayObj[i].dispose(false);
  }

  newMesh.setVerticesData(BABYLON.VertexBuffer.PositionKind, savedPosition, false);
  newMesh.setVerticesData(BABYLON.VertexBuffer.NormalKind, savedNormal, false);
  if (arrayUv.length > 0) newMesh.setVerticesData(BABYLON.VertexBuffer.UVKind, arrayUv, false);
  if (arrayUv2.length > 0) newMesh.setVerticesData(BABYLON.VertexBuffer.UV2Kind, arrayUv, false);
  if (arrayColor.length > 0) newMesh.setVerticesData(BABYLON.VertexBuffer.ColorKind, arrayUv, false);
  if (arrayMatricesIndices.length > 0) newMesh.setVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind, arrayUv, false);
  if (arrayMatricesWeights.length > 0) newMesh.setVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind, arrayUv, false);

  newMesh.setIndices(arrayIndice);
  return newMesh;
};

还可以使用CSG类的subtractinverseunionintersect方法构造复杂的网格。

假设要创建一个具有内径和外径的“管道”形状(,不仅仅是一个“管”网格,它是一个没有“厚度”的曲面)。这可以通过首先创建一个“圆柱”网格,然后从它的内部减去一个“管”网格来构建。

function createPipe(diamInner: number, diamOuter: number, length: number, scene: BABYLON.Scene): BABYLON.Mesh {
  // Create the outer wall using a Cylinder mesh
  const mOuter = BABYLON.MeshBuilder.CreateCylinder(
    "mOuter",
    {
      diameter: diamOuter,
      height: length,
    },
    scene,
  );
  // Create the inner wall using a Tube mesh
  const mInner = BABYLON.MeshBuilder.CreateTube(
    "mInner",
    {
      path: [new BABYLON.Vector3(0, -length / 2, 0), new BABYLON.Vector3(0, length / 2, 0)],
      radius: diamInner / 2,
      sideOrientation: BABYLON.Mesh.DOUBLESIDE,
    },
    scene,
  );
  // Create CSG objects from each mesh
  const outerCSG = BABYLON.CSG.FromMesh(mOuter);
  const innerCSG = BABYLON.CSG.FromMesh(mInner);
  // Create a new CSG object by subtracting the inner tube from the outer cylinder
  const pipeCSG = outerCSG.subtract(innerCSG);
  // Create the resulting mesh from the new CSG object
  const mPipe = pipeCSG.toMesh("mPipe", null, scene);
  // Dispose of the meshes, no longer needed
  mInner.dispose();
  mOuter.dispose();
  scene.removeMesh(mInner);
  scene.removeMesh(mOuter);
  // Return the result
  return mPipe;
}