生成点法线(Generating Vertex Normals)

预备知识

熟悉线性代数的术语和概念,以及向量和向量空间背后的思想。

约定

向量和点使用粗体字母表示,如un 。读者可以根据上下文辨别出点和向量。标量使用非粗体字母表示。对于一个向量u ,我经常简短地使用ux , uy , uz 来表示该向量的各个分量。

点法线 vs. 面法线

我们都知道面法线是什么(如果你不知道,那么我来告诉你。面法线是表面所在平面的法线)。那么,一个顶点怎么能有法线呢?严格上来说,一个顶点不可能有法线。但当使用Phong或Gouraud着色过程进行光照计算时,点法线提供了模拟光滑表面的一种方式。想象一个人体的多边形网格模型:这个模型只是一些多边形。但是这个网格模型能模拟一个人体。如果一个多边形里面的所有像素都使用相同的颜色着色,那么这个多边形看起来会非常平坦;但是通过使用点法线,我们能够对三角形的不同顶点应用不同的光照,这样就能够产生比较光滑的显示效果。

点法线背后的直觉

让我们仔细回顾一下传统多边形网格中的光照过程:扫描线光栅化技术(例如应用于显卡和实时渲染中的技术)。每个顶点都需要应用光照计算,其中面法线和光线方向的点积将用于调整光的颜色强度(光照模型的这部分为散射光)。这个调整的光照颜色就被添加到一个之前已经计算的常量顶点颜色上。当使用三角面网格模型时,对于三角形的三个顶点,光线方向和表面法线向量的的点积都是相同的。当对三个顶点使用相同的法线时,我们的前提是我们模拟的表面是平的,但是我们知道实际情况不是这样的。原因是我们使用一个采样点为三个顶点计算法线。但是,想象一下,我们其实可以在三个顶点上采样到“真正”的表面;然后在这些点法线中得到更多的变体,进而创建一个散射光变体。但是,我们怎样才能够采样真正的表面呢?

不幸的是,我们做不到。尽管如此,基于一个顶点被多个三角形公用,我们可以得到近似的点法线。因此,不是使用顶点所在三角形的面法线,而是首先检测邻接三角形(共用一个相同顶点的三角形),进而对这些邻接的三角形面法线求平均,所得结果即为点法线。这样就提供了点法线背后的直觉,因为点法线并没有严格的定义(有多种技术用于计算点法线,但是没有一个是真正“正确的”)。

算法

既然我们已经知道什么是点法线,那么设计一个算法来计算它。本节首先设计一个标准算法,然后给出该算法的一些变体,这些变体得出的点法线可以用于产生较好的显示效果。

算法的思想是:对于一个给定的顶点,对共用该顶点的所有多边形的面法线求平均。回忆一下,在标准的光栅化技术中,我们能够访问一个三角形列表;因为对于一个给定的顶点,都被该顶点所在三角形所包含,因此这个三角形列表包含重复的顶点。通常,通过使用索引的三角形(保存一个顶点列表。每个三角形都由三个顶点列表索引组成)列表就可以消除重复,但是为了保持简单性,我们假定使用非索引的三角形列表,其中顶点列表中的第i个三角形使用三个顶点的坐标v[i*3].p, v[i*3 + 1].p和v[i*3 + 2].p定义。这样,我们的任务就是对于每一个顶点,找到共用该顶点的三角形。每当我们找到一个共用该顶点的三角形,就计算该三角形的面法线,然后与点法线相加。然后,单位化点法线,并将它和顶点存储在一起。

伪码如下:

其中Normalize(v, j)返回三角形向外的面法线,三角形采用上面描述的索引方案。

上述方法的一个问题就是:对于实际上不平滑的表面(如立方体网格),结果看起来会非常奇怪;在折角处,光照会显得很平滑,很显然这不是我们想要的。

解决该问题的一种方式是利用一个阈值来决定是否将一个三角形的法线用于求平均。具体来讲,就是当我们在处理第i个顶点时,缓存该顶点从技术角度所属三角形的面法线(相对于三角形列表中,其他共用该顶点拷贝的三角形)。然后,当找到另外一个共用该顶点的三角形时,计算缓存的面法线和当前三角形面法线的点积;如果点积小于某个阈值(可以称之为epsilon,通常比0大一点),那么当前三角形的面法线将不被用于计算点法线。那么工作原理是什么呢?回忆一下,点积对应于两个法线夹角的余弦。说得直接一点:如果两个面的夹角大于某个值,那么不要将他们的面法线求平均。

新的伪码如下:

对该算法的另一个可能的改进基于这样一个事实:当一个顶点被多个三角形共用时,这些三角形可能有不同的大小。一些人建议:当对面法线应用求平均过程时,使用三角形的面积作为加权因子。我们只需要加入一个新的过程,该过程以三角形的三个顶点作为输入,计算三角形的面积。

最终版本的伪码如下:

 


 

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值