我们获得了一组三角形。每个三角形都是三个点。每个点都是实数的三元组。我们可以计算每个三角形的曲面法线。但是对于Gouraud着色,我们需要顶点法线。因此,我们必须访问每个顶点并查看共享该顶点的三角形,平均它们的表面法线并使顶点正常。
实现此目的的最有效算法和数据结构是什么?
这是一种天真的方法(伪python代码):
MAP = dict()
for T in triangles:
for V in T.vertices:
key = hash(V)
if MAP.has(key):
MAP[key].append(T)
else:
MAP[key] = []
MAP[key].append(T)
VNORMALS = dict()
for key in MAP.keys():
VNORMALS[key] = avg([T.surface_normal for T in MAP[key]])
有更有效的方法吗?
答案 0 :(得分:4)
访问每个三角形,计算每个三角形的法线,将每个三角形的顶点加到顶点法线上 然后在最后,规范化每个顶点的法线。
然后至少你只需要遍历三角形,你只存储一个普通/顶点。
答案 1 :(得分:3)
每个顶点属于一个或多个面(通常是三角形,有时是四边形 - 我会在这个答案中使用三角形)。
未附加到任何其他三角形的三角形无法“平滑”。它很平坦。只有当一张脸有邻居时,你才可以推理将它们放在一起。
对于多个面相交的顶点,计算每个面的法线。两个向量的叉积返回一个垂直(正常)向量,这就是我们想要的。
A --- B
\ /
C
v1 = B - A
v2 = C - A
normal = v1 cross v2
小心地在所有面上一致地计算这些向量,否则你的法线可能与你需要的方向相反。
因此,在多个面相交的顶点处,对面的法线求和,对结果矢量进行标准化,并将其应用于顶点。
有时你会有一个网格,其中某些部分要平滑,而其他部分则没有。一个易于拍摄的例子是由三角形组成的圆柱体。圆柱体的圆形表面可以很好地平滑,但是如果你考虑在尖锐脊部周围的顶点处的平坦端部的三角形,它将看起来很奇怪。为了避免这种情况,你可以引入一个规则来忽略面部的法线,这些法线与你正在计算的面部的法线偏差太远。
编辑有一个非常好的video showing technique for calculating Gourad shading,虽然它没有讨论实际的算法。
您可能想看看Three.js的来源。具体来说,computeVertexNormals
功能。它不支持保持锋利的边缘。算法的效率在很大程度上取决于您对基元进行建模的方式。