文章目录
-
- 第四章 基本的光照模型
-
- 4.1 光源对物体照明的分类
-
- 4.1.1 间接照明
- 4.1.2 直接照明
- 4.2 照明的计算方式:光照模型
-
- 4.2.1 漫反射和Lambert
- 4.2.2 镜面高光和Phong
- 4.2.3 半角向量和BlinnPhong
第四章 基本的光照模型
4.1 光源对物体照明的分类
4.1.1 间接照明
在物体所处的环境中,我们可以把照射到物体上的光源简单地分为直接照明和间接照明。间接照明是光在物体间传播后,最终又对物体形成照明。知道3DMAX的人一定会对诸如VRay渲染器渲染出的效果图倍感惊讶,那是因为渲染器在漫长的几十分钟甚至几小时的时间内,通过光线追踪真实的计算了光源的直接照明和间接照明。但是对于3D游戏来说,最大的特点是实时交互,玩家或用户不可能等上半个小时让渲染器把场景渲染好了再做下一个动作,因此对这部分照明进行实时计算在目前是不可能实现的。在实际应用中,这种照明一般是通过预先烘焙得到的。烘焙在后面我们再说,对于实时计算,间接照明一般作为一个常量。
4.1.2 直接照明
如果不考虑光线在物体间的传播,也不考虑光线在物体内部的传播,则光线对物体直接照明,我们把照明的结果分为漫反射和镜面反射两种,其中镜面反射会形成强力的高光。直接照明是实时渲染的重点。
4.2 照明的计算方式:光照模型
4.2.1 漫反射和Lambert
对于粗糙物体表面上的某一点,其亮度应该和入射光线与该点的垂直程度有关,也就是入射光线与此点法线的夹角相关。如果我们用L表示单位长度的入射光线,用C表示到达此点的光线的强度和颜色,用N表示此点的法线,那么,物体表面此点的亮度Lum就可以用下面的公式来表示:
Lum = C*max(0,cos<L,N>)
<L,N>表示的是方向矢量L和N之间的夹角,其cos值也就是这两个方向矢量的点积,在实际计算时,通过Cg标准函数库dot(L,N)来完成。这个值对于背向光线的点来说为负,其实就是对其照明为0,因此,使用标准函数库中的max(0,value)来对结果进行一些控制
如果计算到此为止,可以把按照这种方式对物体进行照明计算的模型叫做Lambert。在Unity的Surface Shader中,有两个内置的Lighting Model函数,分别为LightLambert()和LightingLambert_PrePass(),并分别表示了Forward和Deferred渲染路径下的这种简单照明方式。下图就是一Lambert照明的例子
4.2.2 镜面高光和Phong
下面我们就来考虑一下镜面高光的问题,可以很直接的计算某一光线ray在某一法线为normal的点经反射后的光线,这个反射可以通过Cg标准函数库中的reflect(ray,normal)来完成。如果用R表示光线在此点的单位长反射方向向量,V表示视线的单位方向向量,那么高光部分Spec的计算表示为:
Spec = pow(max(0,cos<R,V>),gloss)
<R,V>表示方向矢量I和N之间的夹角,gloss表示其表面的镜面光滑程度。
再加上前面在Lambert部分提到的对漫反射的计算,就可以得到一个被渲染出的高光物体。如下图所示:
4.2.3 半角向量和BlinnPhong
在上面的高光计算方式中,我们确实计算了一次入射光线的反射,然后考虑此反射光线进入视野的程度。还有一种更简单更易于调节的方法是使用入射光线和视线的中间平均值,即半角向量,然后使用此半角向量和法线计算出一个和视角相关的高光,这种高光计算方式即为BlinnPhong。对于Unity的Surface Shader,Unity在Lighting.cginc中提供了两个BlinnPhong的实现,分别对应于Forward和Deferred渲染路径。实例如下图所示:
注:半角向量
该图片引用于It136022740的博客,如果博主对此感到不适在此表示歉意,并留言我会删除