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
相关产品推荐
相关产品推荐

