我有一个具有 3D 65.000 位置坐标的 3D 闭合网格对象。出于照明目的,我需要一个 3D 表面法线提取器。
你能帮我拿下吗。
谢谢。
理查德
好的,这是执行此任务的通用算法的尝试,与您使用的语言和图形库无关。
现在,我必须强调,这是对需要完成的工作的粗略描述,为了提高效率,可以削减某些角落。我要说的是,您不需要先计算所有三角形法线,然后再计算所有顶点法线——这两个步骤可以混合使用以提高效率。
一些伪代码可能看起来像这样
Vector verts[65000]; // 65000 vertex positions
Triangle faces[87000]; // as an example, 87000 triangles
Vector normals[65000]; // 1 normal per vertex - initialised to (0, 0, 0)
// loop over all faces to calculate vertex normals
for (int i=0 ; i<87000 ; i++)
{
Vector v1 = verts[faces[i].vertex1];
Vector v2 = verts[faces[i].vertex2];
Vector v3 = verts[faces[i].vertex3];
Vector edge1 = v2 - v1;
Vector edge2 = v3 - v1;
Vector normal = edge1.CrossProduct(edge2); // or edge2.CrossProduct(edge1)
normal.Normalise();
normals[faces[i].vertex1] += normal;
normals[faces[i].vertex2] += normal;
normals[faces[i].vertex3] += normal;
}
// vertex normals need to be normalised
for (int i=0 ; i<65000 ; i++)
{
normals.Normalise();
}
关于绕线顺序的其他一些评论 - 如果你弄错了,法线将指向内部,而不是向外。如上所述,这可以通过简单地更改叉积的顺序来解决。
因为你有索引,我假设它是一个三角形列表/条形或扇形。阅读每个三角形。通过取三角形的 2 个向量的叉积来计算法线。你有1个问题。如果您不知道三角形的缠绕顺序,那么您可能会得到相反的值。哪个软件创建了网格?您能否在数据文件或软件中检查缠绕顺序是什么?它是左撇子还是右手?
您需要的只是构成三角形两侧的向量的叉积,归一化为单位向量。
正如 Andrew Keith 在他的评论中所说,当您从“外部”查看三角形时,您最好知道三角形是顺时针或逆时针定义的。如果你不能保证一致性,你的手就会一团糟。但可能(或至少希望)创建对象的代码是理智的。
Steg 的回答指向了正确的方向。但是,如果您需要高质量的法线,请查看论文Discrete Differential-Geometry Operators for Triangulated 2-Manifolds。余切公式 (8) 即使对于三角形面积等估计值失效的不规则网格也能提供良好的结果。