一致地确定面法线的方向?

2024-05-15 22:00:29 发布

您现在位置:Python中文网/ 问答频道 /正文

我是计算机图形学的新手,所以如果我的一些语言不准确或者问题遗漏了一些基本的东西,我道歉

在给定顶点列表和如下所示的面列表的情况下,是否可以正确计算面法线:

v1: x_1, y_1, z_1
v2: x_2, y_2, z_2
...
v_n: x_n, y_n, z_n
f1: v1,v2,v3
f2: v4,v2,v5
...
f_m: v_j, v_k, v_l

每个x_i, y_i , z_i指定顶点在三维空间中的位置(但不一定是矢量)

每个f_i包含指定它的三个顶点的索引

我知道你可以用一个面两边的叉积得到一条法线,但是法线的方向取决于边的顺序和选择(据我所知)

鉴于这是我仅有的数据,是否有可能正确确定法线的方向?或者是否有可能至少一致地确定它们?(所有法线可能指向错误方向?)


Tags: 语言列表计算机情况v3方向v2f2
2条回答

在CG中,它是由多边形缠绕规则完成的。这意味着所有面都已定义,因此当直接在面上查看时,点按CW(或CCW)顺序排列。然后使用叉积将导致一致的法线

但是,许多网格不符合缠绕规则(有些面是CW的,有些面是CCW的,但不完全相同),对于这些网格来说,这是一个问题。我知道有两种方法:

  1. 对于简单形状(不太凹)

    你的face_normalface_center-cube_center的点积符号将告诉你法线是指向对象的内部还是外部

    dot

    if ( dot( face_normal , face_center-cube_center ) >= 0.0 ) normal_points_out
    

    您甚至可以使用面上的任意点,而不是面中心。无论如何,对于更复杂的凹面形状,这将无法正常工作

  2. 测试表面上方的点是否在内部

    只需沿法线方向将面中心移动一小段距离(不要太大),然后测试该点是否位于多边形网格内:

    displacement

    if ( !inside( face_center+0.001*face_normal ) ) normal_points_out
    

    要检查点是否在内部,可以使用hit test

但是,如果法线仅用于照明计算,则其使用通常在点积中。因此,我们可以使用它的abs值来代替,这将解决所有照明问题,而不管正常侧如何。例如:

output_color = face_color * abs(dot(face_normal,light_direction))

一些gfx API已经实现了这一点(查找双面材质或法线,打开它们通常使用abs值…),例如在OpenGL中:

glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);

一般来说,无法在一组3d面上“一致”指定法线。。。以著名的M比比斯带为例……p>

Möbius strip image

您会注意到,如果您在一个循环后开始在其上行走,您将到达相同的点,但位于相反的一侧。换句话说,这条带没有两个面,只有一个面。如果你用一条三角形来构建这样一个形状,当然没有办法以一致的方式指定法线,你必然会得到两个相邻的三角形,法线指向相反的方向

这就是说,如果三角形集合确实是可定向的(即,实际上存在一个一致的法线赋值),则解决方案是从一个三角形开始,然后像洪水填充算法一样传播到邻居。例如,在Python中,它看起来像:

active = [triangles[0]]
oriented = set([triangles[0]])
while active:
    next_active = []
    for tri in active:
        for other in neighbors(tri):
            if other not in oriented:
                if not agree(tri, other):
                    flip(other)
                oriented.add(other)
                next_active.append(other)
    active = next_active

相关问题 更多 >