我已经克隆并翻转了一个对象,使用了负比例尺,导致了我的单面面孔被反转。我的问题是,如何翻转法线呢?
我不想使用material.side = THREE.DoubleSide,原因是:1)它不能正常工作(一些阴影从内部绘制),2)我想尽可能地保持性能,所以DoubleSide对我来说不是一个选择。
这就是我的对象被翻转的样子。
mesh.scale.x = - scale_width;
提前感谢!
我已经克隆并翻转了一个对象,使用了负比例尺,导致了我的单面面孔被反转。我的问题是,如何翻转法线呢?
我不想使用material.side = THREE.DoubleSide,原因是:1)它不能正常工作(一些阴影从内部绘制),2)我想尽可能地保持性能,所以DoubleSide对我来说不是一个选择。
这就是我的对象被翻转的样子。
mesh.scale.x = - scale_width;
提前感谢!
geometry.scale( - 1, 1, 1 );
如链接中所解释的,这样做的一个后果是几何面将不再具有逆时针的绕序,而是顺时针的。
您可以手动遍历您的几何体并翻转每个面的绕序。如果您没有应用纹理并且没有使用UV,则这可能适用于您。如果要对几何体进行纹理处理,则还需要校正UV。
实际上,three.js 中的一个几何反转实用程序将是一个不错的补充。目前,该库不支持您想要做的操作。
three.js r.72
我把这个放在这里。我在某个地方找到了flipNormals并为BufferGeometry进行了翻译。
翻转法线,翻转UV,反向面绕组
适用于索引BufferGeometry的版本
function flipBufferGeometryNormalsIndexed(geometry) {
const index = geometry.index.array
for (let i = 0, il = index.length / 3; i < il; i++) {
let x = index[i * 3]
index[i * 3] = index[i * 3 + 2]
index[i * 3 + 2] = x
}
geometry.index.needsUpdate = true
}
非索引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();
}
if (geometry.index) {}
这个问题已经两年了,但是如果有人路过的话,请注意。以下是一种非破坏性的方式:
您可以进入“脏点/法线”模式,并手动翻转法线:
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,我建议您永远不要使用负缩放。
已经修复!!
自three.js r89版本开始,当一个对象的缩放值为负数时object.scale.x = -1
,法线也会翻转(参见:#12787支持反射矩阵。)
(但是我必须升级到r91版本来解决我的法线问题。)
如果您有一个已索引的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;
}