You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何自动生成THREE.js平面网格的交错镜像索引?

网格图案自动化生成(隔行镜像实现)

我已经做出了目标图案,现在要把这个生成过程自动化,核心要求是每隔一个正方形做镜像处理。下面是我目前手动写死索引的代码,想改成自动生成的逻辑,也欢迎提供更简洁的实现思路。

当前手动实现代码

// 生成顶点
for (let x = 0; x < world.plane.widthSegments; x++){
   for (let y = 0; y < world.plane.heightSegments; y++){
   vertices.push(x, y, 0)      // 0, 4, 8,  12, 16, 20, 24, 28, 32, 
   vertices.push(x+1, y, 0)    // 1, 5, 9,  13, 17, 21, 25, 29, 33, 
   vertices.push(x+1, y+1, 0)  // 2, 6, 10, 14, 18, 22, 26, 30, 34, 
   vertices.push(x, y+1, 0)    // 3, 7, 11, 15, 19, 23, 27, 31, 35, 
   }
}
planeMesh.geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(vertices), 3))

// 手动写死的索引,需要改成自动生成
planeMesh.geometry.setIndex([  
   0,  1,   3,   3,  1,  2,  // 1
   2,  6,   3,   3,  6,  7,  // 2    
   7,  6,  11,  11,  6, 10,  // 3
   10, 14, 11,  11, 14, 15,  // 4
    
   1,  17, 18,  18,  2,  1,  // 5
   2,  18,  6,   6, 18, 22,  // 6
   6,  22, 26,  26, 10,  6,  // 7
   10, 26, 14,  14, 26, 30,  // 8
    
   17, 33, 18,  18, 33, 34,  // 9
   18, 34, 38,  38, 22, 18,  // 10
   22, 38, 26,  26, 38, 42,  // 11
   26, 42, 46,  46, 30, 26,  // 12
    
   33, 49, 50,  50, 34, 33,  // 13
   34, 50, 38,  38, 50, 54,  // 14
   38, 54, 58,  58, 42, 38,  // 15
   42, 58, 46,  46, 58, 62,  // 16
]);

自动化生成索引的实现方案

第一步:优化顶点生成(避免重复)

你当前的顶点生成逻辑存在大量重复顶点,会浪费内存。建议改成和THREE.js官方PlaneGeometry一致的顶点生成方式,每个顶点只生成一次:

const vertices = [];
const widthSegments = world.plane.widthSegments;
const heightSegments = world.plane.heightSegments;
const gridX = widthSegments + 1; // 横向顶点数 = 分段数 + 1
const gridY = heightSegments + 1; // 纵向顶点数 = 分段数 + 1

for (let y = 0; y < gridY; y++) {
  for (let x = 0; x < gridX; x++) {
    vertices.push(x, y, 0);
  }
}
planeMesh.geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(vertices), 3));

此时每个(x,y)位置的顶点索引为 y * gridX + x,逻辑更清晰,内存占用大幅降低。

第二步:自动生成镜像索引

根据"每隔一个正方形镜像"的要求,我们可以通过判断网格单元的坐标奇偶性,自动切换三角形的拆分顺序:

const indices = [];

for (let y = 0; y < heightSegments; y++) {
  for (let x = 0; x < widthSegments; x++) {
    // 获取当前正方形的四个顶点索引
    const a = y * gridX + x;          // (x, y)
    const b = y * gridX + x + 1;      // (x+1, y)
    const c = (y + 1) * gridX + x + 1;// (x+1, y+1)
    const d = (y + 1) * gridX + x;    // (x, y+1)
    
    // 根据(x+y)的奇偶性判断是否镜像
    if ((x + y) % 2 === 0) {
      // 正常顺序拆分三角形
      indices.push(a, b, d);
      indices.push(b, c, d);
    } else {
      // 镜像顺序拆分三角形
      indices.push(b, a, c);
      indices.push(a, d, c);
    }
  }
}

planeMesh.geometry.setIndex(indices);

如果你的镜像规则是"横向每隔一行镜像",只需把判断条件改成 x % 2 === 0 即可。

额外优化建议

  1. 直接复用PlaneGeometry:可以跳过手动生成顶点,直接基于官方PlaneGeometry修改索引:
    const planeGeo = new THREE.PlaneGeometry(1, 1, widthSegments, heightSegments);
    const indices = [];
    const gridX = widthSegments + 1;
    // 用上面的索引生成逻辑填充indices
    planeGeo.setIndex(indices);
    planeMesh.geometry = planeGeo;
    
  2. Shader实现视觉镜像(可选):如果只是需要视觉上的镜像效果,不需要修改几何形状,可以用片元着色器根据UV坐标的奇偶性翻转纹理/颜色,性能更高且无需修改几何索引。

内容的提问来源于stack exchange,提问作者caf9

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 17:52:12