3D 表面法线提取器

发布于 2024-08-12 05:30:51 字数 108 浏览 3 评论 0原文

我有一个 3D 闭合网格对象,它具有 3D 65.000 位置坐标。 出于照明目的,我需要一个 3D 表面法线提取器。

你能帮我得到它吗?

谢谢。

理查德

I have a 3D closed mesh object that has 3D 65.000 position coordinates.
For lighting purposes, I need a 3D surface normal extractor.

Could you help me to have it.

Thanks.

Richard

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

扛起拖把扫天下 2024-08-19 05:30:51

好的,这里介绍了执行此任务的通用算法,与您使用的语言和图形库无关。

  1. 我假设你想计算顶点法线,即你最终会得到每个顶点 1 个法线
  2. 以及你的 65000 个顶点位置,我还假设你有一些定义网格中三角形的索引列表,例如三角形 1网格由顶点 3、7 和 3 组成。 24. 无论您有三角形列表、条带还是网格面的其他描述,它们基本上都相当于同一件事:它们描述了某种用于确定哪些顶点位于特定面中的方法。这些方法之间的差异通常与效率有关,但它并没有真正改变该算法背后的基本思想。
  3. 您需要做的第一件事是计算网格中每个三角形的法线。对于具有顶点位置向量 a、b 和 a 的三角形, c,计算三角形中 2 条边的边向量,例如边 1 = b - a,边 2 = c - a。然后计算这两个向量的叉积即可得到该三角形的法向量。叉积的结果是需要标准化的向量。
  4. 计算完所有三角形法线后,通过对顶点所属的每个三角形的法线求平均值来计算顶点的法线。您可以对法线进行直接未加权平均,即如果一个顶点是法线为 n1、n2 和 n2 的 3 个面的一部分。 n3,顶点法线就是 (n1 + n2 + n3)/3。您还可以进行加权平均,其中总和中的每个三角形法线均按某些重要因素(例如该三角形的面积)进行加权。这里没有正确的方法,你可以尝试不同的方法。无论哪种方式,一旦计算出平均值,还需要对其进行标准化。然而,这可以在 1 步中完成,因为对于 3 个向量 n1、n2 和n3,归一化(n1 + n2 + n3)==归一化((n1 + n2 + n3)/3)。

现在,我必须强调,这是对需要完成的工作的粗略描述,为了实现这一目标,可以省掉某些角落以提高效率。我的意思是,您不需要先计算所有三角形法线,然后计算所有顶点法线 - 这两个步骤可以混合在一起来制作更有效率。

一些伪代码可能看起来像这样

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();
}

关于关于缠绕顺序的其他一些注释 - 如果你弄错了,法线将指向内,而不是向外。如上所述,这可以通过简单地更改叉积的顺序来解决。

OK, here's a stab at a general algorithm to carry out this task, independent of what language and graphics library you are using.

  1. I am going to assume you want to calculate vertex normals i.e. you will end up with 1 normal per vertex
  2. As well as your 65000 vertex positions, I am also assuming you have some list of indices which define the triangles in the mesh e.g. triangle 1 in the mesh is made of vertices 3, 7 & 24. Whether you have a triangle list or strip or some other description of the meshes faces, they all basically amount to the same thing: they describe some sort of method for determining which vertices are in a particular face. The difference between such methods is often relating to efficiency, but it does not really change the basic idea behind this algorithm.
  3. The first thing you need to do is calculate the normal for each triangle in the mesh. For a triangle with vertex position vectors a, b & c, you calculate the edge vectors for 2 of the edges in the triangle e.g. edge1 = b - a, edge2 = c - a. You then take the cross product of these 2 vectors to get the normal vector to this triangle. The result of the cross product is a vector that will need to be normalised.
  4. Once all triangle normals have been calculated, the normal for a vertex is calculated by averaging the normals for each triangle that the vertex belongs to. You can just do a straight unweighted average of the normals i.e. if a vertex is part of 3 faces with normals n1, n2 & n3, the vertex normal is simply (n1 + n2 + n3)/3. You can also do a weighted average, where each of the triangle normals in the sum are weighted by some importance factor like the area of that triangle. There's no correct way here and you can play around with different things. Either way, once the average has been calculated, it also needs to be normalised. This however can be done in 1 step since, for 3 vectors n1, n2 & n3, normalised(n1 + n2 + n3) == normalised((n1 + n2 + n3)/3).

Now, I must stress that this is a rough description of what needs to be accomplished in order to do this there are certain corners that can be cut for efficiency. What I'm getting at is that you don't need to calculate all triangle normals first and then calculate all vertex normals - the 2 steps can be mixed in to make things more efficient.

Some pseudo code might look this

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();
}

Regarding some of the other comments about winding order - if you get this wrong, the normals will point inwards, rather than outwards. This can be fixed by simply changing the order of the cross product, as noted above.

撩发小公举 2024-08-19 05:30:51

since you have the indices, i am assuming its either a triangle list / strip or fan. Read each triangle. Compute the normal by taking the cross product of 2 of the vectors of the triangle. You have 1 problem though. If you dont know the winding order of the triangles, then you might get the opposite value. Which software created the mesh ? Can you inspect within the data file or software what the winding order was ? is it left or right handed ?

只有一腔孤勇 2024-08-19 05:30:51

您需要的只是构成三角形两侧的向量的叉积,并标准化为单位向量。

正如安德鲁·基思(Andrew Keith)在他的评论中所说,当您从“外部”看三角形时,您最好知道三角形是顺时针或逆时针定义的。如果你不能保证一致性,那么你的手上就会一片混乱。但可能(或者至少希望)创建该对象的代码是正常的。

What you need is simply the cross-product of the vectors that make up two sides of the triangle, normalized to a unit vector.

As Andrew Keith said in his comment, you'd better know that the triangles are defined either clockwise or counterclockwise when you look at the triangle from the "outside." If you can't guarantee consistency, you have a mess on your hands. But probably (or at least hopefully) the code that created the object is sane.

不忘初心 2024-08-19 05:30:51

Steg 的回答指出了正确的方向。但是,如果您需要高质量的法线,请查看论文 Discrete微分几何算子
对于三角2-流形
。即使对于三角形面积等估计值不合格的不规则网格,余切公式 (8) 也能提供良好的结果。

Steg's answer points into the right direction. However, if you need high-quality normals, have a look at the paper Discrete Differential-Geometry Operators
for Triangulated 2-Manifolds
. The cotangent formula (8) gives you good results even for irregular meshes where estimates such as the triangle area break down.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文