6

我克隆了一个对象,然后使用负比例翻转了一个对象,这导致我的单面反转。我的问题是,我怎样才能翻转法线呢?

我不想使用 material.side = THREE.DoubleSide,原因是:1) 不能正常工作(一些阴影是从内部绘制的)和 2) 想保持尽可能多的性能。所以 DoubleSide 不是我的选择。

这就是我的对象翻转的方式。

mesh.scale.x = - scale_width;

提前致谢!

4

5 回答 5

7

出于多种原因,我建议不要使用负比例,如以下链接所述:Transforming vertex normals in three.js

您可以像这样将反演矩阵应用于您的几何图形

geometry.scale( - 1, 1, 1 );

正如链接中所解释的,这样做的结果是,几何面将不再具有逆时针缠绕顺序,而是顺时针。

您可以手动遍历几何体并翻转每个面的缠绕顺序。这可能对你有用——如果你没有应用纹理并且没有使用 UV。如果要对几何体进行纹理处理,则也需要校正 UV。

实际上,几何反转实用程序将是 three.js 的一个很好的补充。目前,该库不支持您想要执行的操作。

三.js r.72

于 2013-05-30T15:35:07.407 回答
3

这个问题是两年前的问题,但以防万一有人路过。这是一种非破坏性的方法:

您可以进入“脏顶点/法线”模式,并手动翻转法线:

mesh.geometry.dynamic = true
mesh.geometry.__dirtyVertices = true;
mesh.geometry.__dirtyNormals = true;

mesh.flipSided = true;

//flip every vertex normal in mesh by multiplying normal by -1
for(var i = 0; i<mesh.geometry.faces.length; i++) {
    mesh.geometry.faces[i].normal.x = -1*mesh.geometry.faces[i].normal.x;
    mesh.geometry.faces[i].normal.y = -1*mesh.geometry.faces[i].normal.y;
    mesh.geometry.faces[i].normal.z = -1*mesh.geometry.faces[i].normal.z;
}

mesh.geometry.computeVertexNormals();
mesh.geometry.computeFaceNormals();

+1 @WestLangley,我建议你永远不要使用负比例。

于 2015-04-09T12:31:38.077 回答
3

它是固定的!

自three.js r89以来,具有负比例的对象的翻转object.scale.x = -1也会反转法线(请参阅:支持反射矩阵。#12787)。

(但我必须升级到r91才能解决我的正常问题。)

于 2018-03-16T13:11:49.560 回答
3

只是把这个扔在这里。我在某处找到了 flipNormals 并将其翻译为 BufferGeometry

翻转法线、翻转 UV、反面缠绕

BufferGeometry 版本

export function flipBufferGeometryNormals(geometry) {
  const tempXYZ = [0, 0, 0];

  // flip normals
  for (let i = 0; i < geometry.attributes.normal.array.length / 9; i++) {
    // cache a coordinates
    tempXYZ[0] = geometry.attributes.normal.array[i * 9];
    tempXYZ[1] = geometry.attributes.normal.array[i * 9 + 1];
    tempXYZ[2] = geometry.attributes.normal.array[i * 9 + 2];

    // overwrite a with c
    geometry.attributes.normal.array[i * 9] =
      geometry.attributes.normal.array[i * 9 + 6];
    geometry.attributes.normal.array[i * 9 + 1] =
      geometry.attributes.normal.array[i * 9 + 7];
    geometry.attributes.normal.array[i * 9 + 2] =
      geometry.attributes.normal.array[i * 9 + 8];

    // overwrite c with stored a values
    geometry.attributes.normal.array[i * 9 + 6] = tempXYZ[0];
    geometry.attributes.normal.array[i * 9 + 7] = tempXYZ[1];
    geometry.attributes.normal.array[i * 9 + 8] = tempXYZ[2];
  }

  // change face winding order
  for (let i = 0; i < geometry.attributes.position.array.length / 9; i++) {
    // cache a coordinates
    tempXYZ[0] = geometry.attributes.position.array[i * 9];
    tempXYZ[1] = geometry.attributes.position.array[i * 9 + 1];
    tempXYZ[2] = geometry.attributes.position.array[i * 9 + 2];

    // overwrite a with c
    geometry.attributes.position.array[i * 9] =
      geometry.attributes.position.array[i * 9 + 6];
    geometry.attributes.position.array[i * 9 + 1] =
      geometry.attributes.position.array[i * 9 + 7];
    geometry.attributes.position.array[i * 9 + 2] =
      geometry.attributes.position.array[i * 9 + 8];

    // overwrite c with stored a values
    geometry.attributes.position.array[i * 9 + 6] = tempXYZ[0];
    geometry.attributes.position.array[i * 9 + 7] = tempXYZ[1];
    geometry.attributes.position.array[i * 9 + 8] = tempXYZ[2];
  }

  // flip UV coordinates
  for (let i = 0; i < geometry.attributes.uv.array.length / 6; i++) {
    // cache a coordinates
    tempXYZ[0] = geometry.attributes.uv.array[i * 6];
    tempXYZ[1] = geometry.attributes.uv.array[i * 6 + 1];

    // overwrite a with c
    geometry.attributes.uv.array[i * 6] =
      geometry.attributes.uv.array[i * 6 + 4];
    geometry.attributes.uv.array[i * 6 + 1] =
      geometry.attributes.uv.array[i * 6 + 5];

    // overwrite c with stored a values
    geometry.attributes.uv.array[i * 6 + 4] = tempXYZ[0];
    geometry.attributes.uv.array[i * 6 + 5] = tempXYZ[1];
  }

  geometry.attributes.normal.needsUpdate = true;
  geometry.attributes.position.needsUpdate = true;
  geometry.attributes.uv.needsUpdate = true;
}

对于旧式几何

export function flipNormals (geometry) {
  let temp = 0;
  let face;

  // flip every vertex normal in geometry by multiplying normal by -1
  for (let i = 0; i < geometry.faces.length; i++) {
    face = geometry.faces[i];
    face.normal.x = -1 * face.normal.x;
    face.normal.y = -1 * face.normal.y;
    face.normal.z = -1 * face.normal.z;
  }

  // change face winding order
  for (let i = 0; i < geometry.faces.length; i++) {
    const face = geometry.faces[i];
    temp = face.a;
    face.a = face.c;
    face.c = temp;
  }

  // flip UV coordinates
  const faceVertexUvs = geometry.faceVertexUvs[0];
  for (let i = 0; i < faceVertexUvs.length; i++) {
    temp = faceVertexUvs[i][0];
    faceVertexUvs[i][0] = faceVertexUvs[i][2];
    faceVertexUvs[i][2] = temp;
  }

  geometry.verticesNeedUpdate = true;
  geometry.normalsNeedUpdate = true;

  geometry.computeFaceNormals();
  geometry.computeVertexNormals();
  geometry.computeBoundingSphere();
}
于 2019-02-02T18:38:04.977 回答
1

如果你有一个索引BufferGeometry,那么像这样重新排序索引就足够了:

    let temp;
    for ( let i = 0; i < geometry.index.array.length; i += 3 ) {
      // swap the first and third values
      temp = geometry.index.array[ i ];
      geometry.index.array[ i ] = geometry.index.array[ i + 2 ];
      geometry.index.array[ i + 2 ] = temp;
    }

于 2020-09-02T15:01:34.040 回答