Frequencies
在 Illumination 中,我们仅仅只是详细分析了对一个 Shading point 进行着色的过程,要使整个空间中的三维物体显示出着色的效果,我们需要对三维物体的每一个 Shading point 进行着色。
前面我们说一个 Shading point 可以认为是一个单位平面。我们会根据实际的需求去定义一个单位平面代表的是什么,有多大。通常它有以下三种情况:
- 代表多边形整个面(Flat shading)
- 代表多边形的每个顶点(Gouraud shading)
- 代表每个像素(Phong shading)
举个例子,比如我们经过三维建模的过程之后,拿到了一个球的几何表示,对这个球分别应用上面三个方法可以得出下列结果:
图一:从左到右依次是:面、顶点、像素
我们可以很直观地看到三种方法进行着色后效果差异很大,这是因为由于三者的着色频率不同导致的,下面具体分析一下每种方法的着色频率。
Flat shading
三维空间的物体大多是由许多个多边形组成,其中以三角形最为常用。当我们以空间中每一个三角形作为一个 Shading point 时,由前面的知识我们知道要对一个 Shading point 进行着色,需要知道它的法线。组成三维空间中物体的每个三角形的法线很好计算,取其中两条边做叉积然后归一化成单位向量就可以了。之后再根据 Blinn-Phong 反射模型对每一个三角形面进行着色即可。
Gouraud shading
以多边形的顶点作为 Shading point 时,我们要如何计算三维空间中物体顶点的法线呢?
如上图二,我们要计算一个顶点的法线,可以用组成该顶点的所有多边形的法线求平均(即所有法线向量相加)。然后再归一化成单位向量:
为了更接近真实的效果,还可以对多边形的法线进行加权(比如按多边形的面积作为权重)后再计算顶点法线。
计算出每个顶点的法线,也就相当于计算出了每个三角形三个顶点的法线。那要如何给整个三角形进行着色呢?方法肯定要有别于 Flat shading,即不会对整个三角形面进行统一着色。这里使用的方法是对三角形三个顶点进行着色后,再根据三个顶点的颜色,使用插值的方法计算出三角形内部每个位置的颜色,最终使整个三角形出现某种渐变的效果(见图一中间的球)。具体的插值方案见 Barycentric Coordinates。
Phong shading
这里的 Phong shading 说的是着色频率,注意不要跟上一章节所讲的 Blinn-Phong 反射模型相混淆。
把每个像素都当作一个 Shading point,就意味着我们需要对每个像素都应用一遍 Blinn-Phong 反射模型的操作。也就是说,我们需要知道三维空间中每个三角形绘制到屏幕时对应的每个像素的法线,这个要如何计算?
在 Gouraud shading 的方案中我们知道了如何计算三角形每个顶点的法线。在这里,我们可以使用重心插值(Barycentric interpolation)的方法去计算出每个像素的法线(注意区别:Gouraud shading 插值的结果是直接计算出颜色)。如下图三,当我们知道两个顶点的法线后,可以通过插值的方法计算出两个顶点之间的每个像素的法线,并使其有一个平滑的过渡。具体的插值操作见 Barycentric Coordinates。
对比
图一给我们的直观感觉是,Phong shading 效果要比前两种方案要好。事实上,选择什么方案进行着色是需要分情况的,其中一个重要的参考是三维物体的顶点数。比如:
- 顶点数较少时,Phong shading 展现出更好的效果(图四行一:因为它是像素级别的应用,因此也是计算量最大的)
- 顶点数较多时(比如比肩像素数),三种方案的效果几乎看不出区别(图四行三:此时计算量的消耗可能是不好权衡的,因为一个是顶点多,一个是像素多)
- 随着顶点数量增多,Flat shading 效果变化最明显(图四列一),而 Phong shading 效果变化最不明显(图四列三)