如何自动生成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 即可。
额外优化建议
- 直接复用PlaneGeometry:可以跳过手动生成顶点,直接基于官方PlaneGeometry修改索引:
const planeGeo = new THREE.PlaneGeometry(1, 1, widthSegments, heightSegments); const indices = []; const gridX = widthSegments + 1; // 用上面的索引生成逻辑填充indices planeGeo.setIndex(indices); planeMesh.geometry = planeGeo; - Shader实现视觉镜像(可选):如果只是需要视觉上的镜像效果,不需要修改几何形状,可以用片元着色器根据UV坐标的奇偶性翻转纹理/颜色,性能更高且无需修改几何索引。
内容的提问来源于stack exchange,提问作者caf9
相关产品推荐
相关产品推荐

