【问题标题】:Determing the direction of face normals consistently?始终如一地确定面部法线的方向?
【发布时间】:2019-12-17 10:59:54
【问题描述】:

我是计算机图形学的新手,所以如果我的语言不准确或问题遗漏了一些基本内容,我深表歉意。

如果给定一个顶点列表和一个这样的面列表,是否可以正确计算面法线:

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 指定顶点在 3d 空间中的位置(但不一定是向量)

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

我知道您可以使用面部两侧的叉积来获得法线,但该法线的方向取决于边的顺序和选择(据我了解)。

鉴于这是我拥有的唯一数据,是否可以正确确定法线的方向?或者是否有可能至少始终如一地确定它们? (所有法线都可能指向错误的方向?)

【问题讨论】:

    标签: graphics 3d game-physics 3d-modelling


    【解决方案1】:

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

    但是,那里的许多网格不符合缠绕规则(有些面是顺时针,而另一些是逆时针,并不完全相同),对于那些来说,这是一个问题。我知道有两种方法:

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

      face_normalface_center-cube_center 的点积符号将告诉您法线点是在对象内部还是外部。

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

      您甚至可以使用任何面部点来代替面部中心。无论如何,对于更复杂的凹面形状,这将无法正常工作。

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

      简单地将面的中心在法线方向上移动一小段距离(不太大),然后测试该点是否在多边形网格内:

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

    【讨论】:

      【解决方案2】:

      一般来说,没有办法在一组 3D 面中“一致地”分配法线...以著名的莫比乌斯带为例...

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

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

      【讨论】:

      • 感谢您的回答,如果可能的话,我也会赞同这一点!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-09
      • 1970-01-01
      • 2015-07-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多