Three.js: How to flip normals after negative scale

爷,独闯天下 提交于 2019-11-28 01:18:07
WestLangley

I would advise against negative scale for a whole host of reasons, as explained in this link: Transforming vertex normals in three.js

You can instead apply an inversion matrix to your geometry like so

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

As explained in the link, a consequence to doing this, however, is the geometry faces will no longer have counterclockwise winding order, but clockwise.

You can manually traverse your geometry and flip the winding order of each face. This may work for you -- if you do not have a texture applied and are not using UVs. If your geometry is to be textured, the UVs will need to be corrected, too.

Actually, a geometry inversion utility would be a nice addition to three.js. Currently, what you want to do is not supported by the library.

three.js r.72

This question is two years old, but in case anyone passes by. Here is a non-destructive way of doing this:

You can enter the "dirty vertices/normals" mode, and flip the normals manually:

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, I suggest you never use negative scale.

It is fixed !!

The flip of an object with a negative scale object.scale.x = -1 also reverse the normals since three.js r89 (see: Support reflection matrices. #12787).

(But I have to upgrade to r91 to solve my normal issue.)

Just dumping this here. I found somewhere flipNormals and translated it for BufferGeometry

Flip normals, flip UVs, Inverse Face winding

Version for 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;
}

For old style Geometry

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();
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!