在Three.js中无法改变三角形的朝向

前端开发 2026-07-08

我有一个八面体,其顶点坐标是通过计算得到的。我用BufferGeometry和 MeshStandardMaterial构建这个对象(见下方代码)。

结果对象有4 个面片,显然法线指向对象内部。我通过计算从对象中心到三角形中心的向量与三角形法线的点积来识别这些三角形。

我尝试了三种策略来改变这些三角形的朝向,但都没起作用:下半部总是出现三个较暗的三角形,上半部只有一个。我的错误在哪里?

const material = new MeshStandardMaterial({
    side: DoubleSide,
    roughness: 0.5,
    metalness: 0.6,
    color: "#00FF00"
});

const geometry = new BufferGeometry();
geometry.setAttribute("position", new Float32BufferAttribute(vertices, 3));

// First strategy: compute the vertex normals and change their sign for the "wrong" triangles
geometry.setAttribute("normal", new Float32BufferAttribute(normals, 3));
const index = [];
for(let i=0; i < 24; ++i) index.push(i);
geometry.setIndex(index);

// Second strategy: let ThreeJS compute the vertex normals but swap two of the triangles vertices index entries
geometry.computeVertexNormals();
const index = [];
for(let i=0; i < 24; i+=3) {
    if(triangle is correct)
        index.push(i, i+1, i+2);
    else
        index.push(i, i+2, i+1);
geometry.setIndex(index);

// Third strategy: like the 2nd one but removed the geometry.computeVertexNormals() call.

const shape = new Mesh(geometry, material);

// To test these are the vertices of the triangles
const vertices = [
    0.08, 0, 0,
    0, 0.08, 0,
    0, 0, 0.08,
    0, 0, 0.08,
    -0.08, 0, 0,
    0, 0.08, 0,
    0, 0, 0.08,
    0, -0.08, 0,
    0.08, 0, 0,
    -0.08, 0, 0,
    0, 0, 0.08,
    0, -0.08, 0,
    -0.08, 0, 0,
    0, 0, -0.08,
    0, -0.08, 0,
    0, -0.08, 0,
    0.08, 0, 0,
    0, 0, -0.08,
    -0.08, 0, 0,
    0, 0.08, 0,
    0, 0, -0.08,
    0, 0.08, 0,
    0, 0, -0.08,
    0.08, 0, 0
];

解决方案

第一步:确保每个三角形的顶点顺序一致

所有三角形都必须遵循相同的顶点绕序(从外部看为CCW)

第二步:让Three.js计算法线

const geometry = new THREE.BufferGeometry();

geometry.setAttribute(
  "position",
  new THREE.Float32BufferAttribute(vertices, 3)
);

// ✅ Important step
geometry.computeVertexNormals();

const mesh = new THREE.Mesh(geometry, material);

由于你的顶点是通过程序生成的,请在渲染之前修正它们:

for (let i = 0; i < vertices.length; i += 9) {
    const a = new THREE.Vector3(vertices[i], vertices[i+1], vertices[i+2]);
    const b = new THREE.Vector3(vertices[i+3], vertices[i+4], vertices[i+5]);
    const c = new THREE.Vector3(vertices[i+6], vertices[i+7], vertices[i+8]);

    const ab = b.clone().sub(a);
    const ac = c.clone().sub(a);

    const normal = new THREE.Vector3().crossVectors(ab, ac);

    const center = a.clone().add(b).add(c).divideScalar(3);

    // If normal points inward → flip triangle
    if (normal.dot(center) < 0) {
        // swap b and c
        for (let j = 0; j < 3; j++) {
            [vertices[i+3+j], vertices[i+6+j]] =
            [vertices[i+6+j], vertices[i+3+j]];
        }
    }
}
  1. 问题:三角形的绕序不一致
  2. 这不是法线/材质的问题
  3. 解决办法:始终以一致的顺序重新排列三角形顶点(CCW)
  4. 最佳做法:使用叉积和点积自动纠正
  5. 然后调用 computeVertexNormals()
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章