我主要看到三种计算生成形状的法线的方法。
分析法线
在某些情况下,您具有有关曲面的足够信息以生成法线。例如,球体上任何点的法线对于计算而言都是微不足道的。简而言之,当您知道函数的导数时,您也就知道法线。
如果您的案例足够狭窄,可以使用分析法线,则它们可能会在精度方面提供最佳结果。但是,该技术的伸缩性不太好:如果还需要处理无法使用解析法线的案例,那么保留处理一般案例的技术并完全放弃解析可能会更容易。
顶点法线
两个向量的叉积给出一个垂直于它们所属平面的向量。因此,获得三角形的法线很简单:
vec3 computeNormal(vec3 a, vec3 b, vec3 c)
{
return normalize(crossProduct(b - a, c - a));
}
此外,在上述示例中,叉积的长度与abc内的面积成比例。因此,可以通过对叉积求和并归一化(最后一步),从而按每个三角形的面积加权,来计算由多个三角形共享的顶点处的平滑法线。
vec3 computeNormal(vertex a)
{
vec3 sum = vec3(0, 0, 0);
list<vertex> adjacentVertices = getAdjacentVertices(a);
for (int i = 1; i < adjacentVertices; ++i)
{
vec3 b = adjacentVertices[i - 1];
vec3 c = adjacentVertices[i];
sum += crossProduct(b - a, c - a);
}
if (norm(sum) == 0)
{
// Degenerate case
return sum;
}
return normalize(sum);
}
如果使用四边形,可以使用一个不错的技巧:对于四边形abcd,请使用crossProduct(c - a, d - b)
,它将很好地处理四边形实际上是三角形的情况。
Iñigoquilez就该主题写了几篇简短的文章:网格的聪明归一化,以及n边多边形的法线和面积。
来自偏导数的法线
可以在片段着色器中根据偏导数计算法线。除了这次是在屏幕空间中完成之外,后面的数学是相同的。Angelo Pesce的这篇文章介绍了该技术:没有法线的法线。