概念
Phong模型是一种局部光照的经验模型。由犹他大学的美国越南裔学者Bui Tuong Phong在其1975年的博士论文中提出。
Phong模型认为物体表面反射光线由三部分组成:
- 环境光(Ambient):场景中的其他间接光照
- 漫反射(Diffuse):散射部分(大但不光亮)
- 高光反射(Specular):镜面反射部分(小而亮)
(在上图中,光线是白色的,环境光和漫反射部分是蓝色的,高光部分是白色的。)
可以看到,高光部分反射的光区域比较小,但强度很大;漫反射部分的强度根据物体表面方向的不同而不同;而环境光部分是跟方向无关的。
公式
光源部分:
lights
:所有光源的集合,对于每盏光,可分为高光和漫反射两部分,如下:i_s
:光源高光部分的强度(可以理解为就是RGB)i_d
:光源漫反射部分的强度(可以理解为就是RGB)i_a
:环境光部分的强度(可以理解为就是RGB)
场景中材质的参数:
k_s
:对入射光的高光反射常数k_d
:对入射光的漫反射常数k_a
:对环境光的反射常数\alpha
:材质的光泽度,或叫反光度,也是常数。表面越光泽则\alpha
越大,表面的亮点就越小。
几个向量(全部归一化):
\hat{L_m}
:物体表面某点指向光源m的位置的向量\hat{N}
:物体表面某点的法线\hat{R_m}
:光源在物体表面某点发生镜面反射的方向\hat{V}
:物体表面某点指向摄像机位置的向量
完整公式:
其中,\hat{R_m}
可由\hat{L_m}
和\hat{N}
计算出来:
根据公式可以看出,漫反射部分是跟视角(\hat{V}
)无关的;而视角方向与反射方向的夹角越小,则高光部分越强;光泽度\alpha
越大,则亮点越小(两个归一化的向量点乘等于其夹角的cos值,小于1,幂越大,则越快趋近于0)。
对于上述公式中的高光和漫反射部分,有一点需要说明的是,每一部分的点乘结果是正数的时候,才应该将这一部分计算进去;而且漫反射部分的点乘为正时,高光部分才应该被计算进去。
以上公式是对颜色的R、G、B通道单独建模的,也就是说,允许RGB通道有不同的k_a
、k_d
和k_s
。
变种:Blinn–Phong shading model
Blinn–Phong模型是Direct3D 10和~OpenGL 3.1之前的固定管线默认使用的着色模型。逐顶点计算,顶点间的像素通过Gouraud shading插值。
首先,计算视角方向和光源方向之间的中途向量H
:
然后,用N \cdot H
代替R \cdot V
。N
、H
的夹角刚好是R
、 V
夹角的一半(前提是V
、L
、N
、R
在同一平面内,不在同一平面内时也近似满足这种关系,尤其是夹角很小的时候)。
最后再找一个大于\alpha
的\alpha'
,以使(N \cdot H)^{\alpha'}
接近Phong模型中的(R \cdot V)^{\alpha}
。
对于正面的光照,\alpha'=4\alpha
可以得到比较近似于Phong模型的高光部分。
对于平坦的表面,Phong模型的反射总是圆形的,而当视角几乎平行于表面时,Blinn-Phong反射会变成椭圆形(想像一下日落时在水面的倒影):
Phong光照模型
Blinn-Phong光照模型
效率
当观察者的位置和光源离物体非常远时(比如平行光),Blinn-Phong的效率要高于Phong。因为H
是取决于观察者位置的方向以及光源位置的方向的,两者都很远时H
可以被认为是常量,跟位置以及表面的曲率没关系,每帧对每个光源计算一次即可。而Phong却要根据表面曲率去逐顶点或逐像素计算反射向量R
。