天天看点

DirectX11 镜面光镜面光

镜面光

1. 什么是镜面光?

考虑下图所示的光滑表面。当灯照射在这样一个表面上时,光线会在一个由反射系数描述的圆锥体区域内形成锐利的反射;我们将这种反射称为镜面高光反射(specular reflection,或直译为镜面反射)。与漫反射不同,高光可能不会传入眼睛,因为它只在一个特定的方向上反射;高光的计算过程与观察点的位置相关。也就是说,当场景中的观察点位置发生变化时,我们看到的高光强度也会跟着变化。

DirectX11 镜面光镜面光

这里的入射光向量I是指入射光的方向(它与光线向量L的方向相反) 。镜面反射不会在所有的方向上散开,它只会将反射光集中在一个由反射系数描述的圆锥体区域内。当v在圆锥体内时,我们可以看到高光;反之,看不到高光。v与r的夹角越小,我们看到的高光就越强。

2. 镜面光模型函数推导

镜面反射的圆锥体区域由一个反射向量r和一个角度ϕmax来定义。简单来说,反射光的强度可由反射向量r和观察向量v=E−P∥E−P∥ (即,从表面点P到观察点位置E的单位向量)之间的夹角ϕ来决定。我们约定:当ϕ =0时,高光强度最大;当ϕ逐渐接近于时,高光强度逐渐降低为0。为了以数学方式来描述一过程,我们需要对使用兰伯特余弦定理的函数做一些修改。下图说明了使用不同幂时的余弦函数曲线图,其中p≥1。本质上,通过为p指定不同的值,我们可以间接地控制当高光强度降低为0时的圆锥体角度ϕmax。参数p可以用来控制表面的平滑程度;也就是,非常精细的表面比缺乏光泽的表面的反射系数小(反射光更锐利)。所以,我们应该为光滑表面指定一个比不光滑表面更大的p值。

DirectX11 镜面光镜面光

(使用不同幂时的余弦函数曲线图,其中p≥1。)

注意,因为v和r是单位向量,所以cosϕ = v•r。

我们现在定义照模型中的高光项:

DirectX11 镜面光镜面光

其中:

DirectX11 镜面光镜面光

颜色ls指定了光源发出的高光总量。镜面材质颜色ms指定了表面反射和吸收的入射高光总量。系数ks根据r和v之间的夹角来决定高光强度。图7.13说明了一个表面可能接收不到漫反射光(L•n <0),但是却可以接收到高光。不过,在这种情况下,它收到的高光是毫无意义的,我们应该将ks设为0。

DirectX11 镜面光镜面光

(虽然光线照射的是物体背面,但是在观察点上还是可以看到高光。是错误的结果。当出现一问题时,我们必须将ks设为0。)

注意:高光幂p的取值应该总是大于1的。

新的光照模型为:

DirectX11 镜面光镜面光

注意:反射向量r = I − 2(n•I)n(参见下图及其推导)。(这里假设n是一个单位向量。)不过,我们在着色器程序中总是使用HLSL的内置函数reflect来计算。

DirectX11 镜面光镜面光

3. 附:反射向量r = I − 2(n•I)n的推导

将R平移一下,与向量N的延长线相交。
DirectX11 镜面光镜面光

由于入射角和反射角相等,且I和R的长度也相等,所以三角形ION是等腰三角形。故有

ON = 2S

所以有

R = I + 2S

而S是-I在N上的投影,所以有

DirectX11 镜面光镜面光

(投影公式在后面证明)

由于N是单位向量,简化一下得到

DirectX11 镜面光镜面光
所以
DirectX11 镜面光镜面光

投影公式证明:

DirectX11 镜面光镜面光

若v向量为单位向量,则结果为 uv向量的点积 * v向量.

即: 某个方向力u, 在v方向上的分量.

参考资料:

求反射向量:http://www.cnblogs.com/graphics/archive/2013/02/21/2920627.html

向量在另一个向量上的投影:http://blog.csdn.net/zhanglei0107/article/details/8235430

继续阅读