Three.js r130版本中非索引BufferGeometry如何实现法向量平滑?
问题根因
Three.js r130 之后BufferGeometryUtils.mergeVertices()的默认逻辑是只有所有顶点属性(position、normal、uv等)完全一致的顶点才会被合并。你用的BoxGeometry默认生成的顶点,哪怕空间位置完全相同,所属面的法向量、UV坐标都是不同的,所以调用mergeVertices()时没有任何顶点被合并,最终还是非索引几何体,computeVertexNormals()只能按独立面计算法向量,自然得到平着色效果。
解决方案
合并顶点前先移除除position外的其他顶点属性,让方法仅按空间位置判断是否合并顶点,合并完成后再重新计算法向量即可。
修改后的可运行代码
// Scene const scene = new THREE.Scene(); // Geometry const boxGeometry = new THREE.BoxGeometry(.7,.7,.7); // Materials const shadedMaterial = new THREE.MeshStandardMaterial(); shadedMaterial.metalness = 0.4; shadedMaterial.roughness = 0.4; shadedMaterial.color = new THREE.Color(0xffffff); // 平滑处理核心逻辑 const tempGeometry = new THREE.BufferGeometry().copy(boxGeometry); // 移除干扰合并的属性,仅保留position用于判断顶点是否重合 tempGeometry.deleteAttribute('normal'); tempGeometry.deleteAttribute('uv'); // 合并顶点,第二个参数为容差,可根据实际场景调整浮点误差阈值 const smoothBoxGeometry = BufferGeometryUtils.mergeVertices(tempGeometry, 1e-3); // 重新计算法向量,此时共享顶点的法向量会自动平均得到平滑效果 smoothBoxGeometry.computeVertexNormals(); const box = new THREE.Mesh(smoothBoxGeometry, shadedMaterial); scene.add(box);
补充说明
- 如果你需要保留部分硬边,可以使用
computeVertexNormals()的第二个参数(平着色角度阈值),大于该角度的边会被保留为硬边。 - 示例用立方体做测试的话,平滑处理后会得到圆角软化的立方体效果,这是法向量平均的正常表现,如果是曲面几何体(比如导出的无索引模型)会得到自然的平滑效果。
内容的提问来源于stack exchange,提问作者Myro
相关产品推荐
相关产品推荐

