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

Graphics 一致地确定面法线的方向?,graphics,3d,game-physics,3d-modelling,Graphics,3d,Game Physics,3d Modelling,我是计算机图形学的新手,所以如果我的一些语言不准确或者问题遗漏了一些基本的东西,我道歉 在给定顶点列表和如下所示的面列表的情况下,是否可以正确计算面法线: 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包含指定它的三个顶点的索引 我知道你可以用一

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

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

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
包含指定它的三个顶点的索引

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


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

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

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

  • 对于简单形状(不太凹)

    face\u normal
    face\u center-cube\u center
    的点积符号将告诉您法线是指向对象的内部还是外部

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

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

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

    若要检查点是否在内部,您可以使用

  • 但是,如果法线仅用于照明计算,则其使用通常在点积中。因此,我们可以使用它的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比比斯带为例,

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

    这就是说,如果三角形集合确实是可定向的(即,实际上存在一个一致的法线赋值),则解决方案是从一个三角形开始,然后像洪水填充算法一样传播到邻居。例如,在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
    

    谢谢你的回答,如果可能的话,我也会赞同的!
    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
    
    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