概念

Phong模型是一种局部光照的经验模型。由犹他大学的美国越南裔学者Bui Tuong Phong在其1975年的博士论文中提出。

Phong模型认为物体表面反射光线由三部分组成:

  • 环境光(Ambient):场景中的其他间接光照
  • 漫反射(Diffuse):散射部分(大但不光亮)
  • 高光反射(Specular):镜面反射部分(小而亮)

img

(在上图中,光线是白色的,环境光和漫反射部分是蓝色的,高光部分是白色的。)

可以看到,高光部分反射的光区域比较小,但强度很大;漫反射部分的强度根据物体表面方向的不同而不同;而环境光部分是跟方向无关的。

公式

光源部分:

  • lights:所有光源的集合,对于每盏光,可分为高光和漫反射两部分,如下:
  • i_s:光源高光部分的强度(可以理解为就是RGB)
  • i_d:光源漫反射部分的强度(可以理解为就是RGB)
  • i_a:环境光部分的强度(可以理解为就是RGB)

场景中材质的参数:

  • k_s:对入射光的高光反射常数
  • k_d:对入射光的漫反射常数
  • k_a:对环境光的反射常数
  • \alpha:材质的光泽度,或叫反光度,也是常数。表面越光泽则\alpha越大,表面的亮点就越小。

img

几个向量(全部归一化):

  • \hat{L_m}:物体表面某点指向光源m的位置的向量
  • \hat{N}:物体表面某点的法线
  • \hat{R_m}:光源在物体表面某点发生镜面反射的方向
  • \hat{V}:物体表面某点指向摄像机位置的向量

完整公式:

I_p = k_a i_a + \sum_{m \in lights} (k_d(\hat{L_m} \cdot \hat{N})i_{m,d} + k_{s}(\hat{R_m} \cdot \hat{V})^\alpha i_{m,s})

其中,\hat{R_m}可由\hat{L_m}\hat{N}计算出来:

\hat{R_m} = 2(\hat{L_m} \cdot \hat{N})\hat{N} - \hat{L_m}

根据公式可以看出,漫反射部分是跟视角(\hat{V})无关的;而视角方向与反射方向的夹角越小,则高光部分越强;光泽度\alpha越大,则亮点越小(两个归一化的向量点乘等于其夹角的cos值,小于1,幂越大,则越快趋近于0)。

对于上述公式中的高光和漫反射部分,有一点需要说明的是,每一部分的点乘结果是正数的时候,才应该将这一部分计算进去;而且漫反射部分的点乘为正时,高光部分才应该被计算进去。

以上公式是对颜色的R、G、B通道单独建模的,也就是说,允许RGB通道有不同的k_ak_dk_s

变种:Blinn–Phong shading model

Blinn–Phong模型是Direct3D 10和~OpenGL 3.1之前的固定管线默认使用的着色模型。逐顶点计算,顶点间的像素通过Gouraud shading插值。

首先,计算视角方向和光源方向之间的中途向量H:

H = \frac{L+V}{\left\|L+V\right\|}

然后,用N \cdot H代替R \cdot VNH的夹角刚好是RV夹角的一半(前提是VLNR在同一平面内,不在同一平面内时也近似满足这种关系,尤其是夹角很小的时候)。

最后再找一个大于\alpha\alpha',以使(N \cdot H)^{\alpha'}接近Phong模型中的(R \cdot V)^{\alpha}

对于正面的光照,\alpha'=4\alpha可以得到比较近似于Phong模型的高光部分。

对于平坦的表面,Phong模型的反射总是圆形的,而当视角几乎平行于表面时,Blinn-Phong反射会变成椭圆形(想像一下日落时在水面的倒影):

img

Phong光照模型

img

Blinn-Phong光照模型

img

效率

当观察者的位置和光源离物体非常远时(比如平行光),Blinn-Phong的效率要高于Phong。因为H是取决于观察者位置的方向以及光源位置的方向的,两者都很远时H可以被认为是常量,跟位置以及表面的曲率没关系,每帧对每个光源计算一次即可。而Phong却要根据表面曲率去逐顶点或逐像素计算反射向量R