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

Three.js如何实现16x16平面几何体分段独立设色及透明效果

方案结论

完全不需要将每个分段渲染为独立的平面几何体。拆分为256个独立网格属于性能最差的实现方式,Three.js本身支持给单几何体的每个面绑定独立颜色、透明度属性,仅用一个网格就能实现需求,是兼顾性能、可维护性的最优方案。

实现步骤
  • 创建对应分段的平面几何体
    初始化平面时直接指定分段参数即可,16x16尺寸、16x16个分段的平面初始化代码为new THREE.PlaneGeometry(16, 16, 15, 15),注意分段参数为格子数减1,16格对应15段切割。创建后调用.toNonIndexed()转为非索引几何体,避免顶点共享导致的颜色、透明度插值问题,方便逐块赋值。
  • 给几何体绑定逐顶点的颜色、透明度属性
    非索引模式下每个四边形分段对应2个三角形、共6个独立顶点,你可以给几何体新增两个自定义顶点属性,同一个分段的6个顶点填相同的颜色、透明度值,就能实现单块纯色、独立透明度的效果。核心代码参考:
    // 初始化16x16分段的平面,转非索引几何体
    const geom = new THREE.PlaneGeometry(16, 16, 15, 15).toNonIndexed();
    const cellCount = 16 * 16;
    // 颜色属性:每个顶点3个RGB值,每个块6个顶点
    const colors = new Float32Array(cellCount * 6 * 3);
    // 透明度属性:每个顶点1个alpha值
    const alphas = new Float32Array(cellCount * 6);
    
    // 遍历所有格子赋值
    for (let y = 0; y < 16; y++) {
      for (let x = 0; x < 16; x++) {
        const cellIdx = y * 16 + x;
        // 给当前格子对应的6个顶点填值
        for (let v = 0; v < 6; v++) {
          const attrIdx = cellIdx * 6 + v;
          // 替换为你需要的颜色逻辑
          colors[attrIdx * 3] = Math.random();
          colors[attrIdx * 3 + 1] = Math.random();
          colors[attrIdx * 3 + 2] = Math.random();
          // 替换为你需要的透明度逻辑,例:奇偶格半透明
          alphas[attrIdx] = (x + y) % 2 === 0 ? 1 : 0.3;
        }
      }
    }
    
    // 把属性绑定到几何体
    geom.setAttribute('color', new THREE.BufferAttribute(colors, 3));
    geom.setAttribute('alpha', new THREE.BufferAttribute(alphas, 1));
    
  • 编写支持逐顶点颜色、透明度的材质
    可以直接用自定义ShaderMaterial实现,必须开启transparent: true才能正常渲染透明效果,参考代码:
    const cellMat = new THREE.ShaderMaterial({
      transparent: true,
      side: THREE.DoubleSide,
      vertexShader: `
        attribute vec3 color;
        attribute float alpha;
        varying vec3 vColor;
        varying float vAlpha;
        void main() {
          vColor = color;
          vAlpha = alpha;
          gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
        }
      `,
      fragmentShader: `
        varying vec3 vColor;
        varying float vAlpha;
        void main() {
          gl_FragColor = vec4(vColor, vAlpha);
        }
      `
    });
    
  • 动态修改单块属性
    后续需要调整某个格子的颜色、透明度时,只需要根据格子坐标算出对应属性在数组中的索引位置,修改值后将属性的needsUpdate标记设为true即可实时生效,不需要重建几何体或网格。
不推荐拆分独立平面的原因
  • 256个独立网格会产生大量额外Draw Call,哪怕做合批处理,性能也远低于单几何体方案
  • 独立网格的坐标对齐、整体变换、交互拾取维护成本更高
  • 内存开销随分段数上涨更快,如果后续要扩展到更高分辨率的像素块,性能差距会被进一步放大

补充:如果需要做鼠标拾取交互,用Raycaster拾取时可以直接通过命中的面索引计算出对应格子坐标,交互体验和独立网格没有差异。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 07:51:28