D3D光照总结

在D3D中,顶点的颜色除了在创建的时候主动的声明之外,还有一种实现的方式就是通过光照和材质的相互作用关系。我们知道自然界中光是由红绿蓝三种原色光组成的白光,如果这个白光照射在某种吸收蓝光的物体上,那么反射出来的光就只含有绿色和红色,当这个只包含着绿色和红色的光到达我们的眼睛的时候,我们就觉得这个物体是黄色的。在D3D中,我们用光照和材质这两个东西来模拟上述的行为。“光照”中指定模拟光线中红绿蓝三色的比例,材质是模拟光照射的物体的一种对于光线的反射(或者吸收)的能力。这个就和自然中的光线效果一致了。在D3D中还对光照进行了细化,用三种光来模拟自然世界中的光线:分别是环境光、漫反射光和镜面光,通过这三种光线的组合可以模拟出大多数光源的效果。当然,这些都是局部光照,而不是全局光照。不管是那种光,他们都是由红绿蓝三色组成的,一般用向量D3DXCOLOR(1.0,1.0f,1.0f,1.0f)来标识白光,其他颜色的光表达类似。

三种光:

 (1)环境光的可以理解为不知道何处发来的光线弥漫于整个环境中,使得整个环境的角角落落都被照亮了。经过环境光的作用之后,物体表面的颜色应满足的公式是:

            f = Ca * Ma        ------------------------------------------------------------------------------------(1)

其中Ca代表环境光,如D3DXCOLOR(1.0f,0.0,0.0,1.0f)表示环境中弥漫着红色的光;Ma表示物体对环境光的材质属性,如D3DXCOLOR(0.0f,1.0f,0.0f,1.0f)表示该物体只反射绿色的光,换句话说,该物体会将所有的红光吸收。那么在红色环境光的照射下,我们其实看见的物体是白色的。

 (2)漫反射光可以理解为当有光线照射到某表面时,由于表面的不光滑,会造成向四面八方反射的现象,这些反射光到达我们的眼睛,我们看见了表面的存在。这里,有一个问题要考虑,即光线到达表面时的入射角度。因为,如果光线垂直射向表面,那么几乎所有的反射光都会沿原路返回;若光线与表面成锐角摄入,某些光线会由于折射等各种原因损耗掉,那么反射出来光就会少些。所以,对于漫反射来说,除了与环境光相似的计算部分外,还要把入射角度的影响因子考虑进去。lambert定律就是用来描述入射角度的影响的:

          DiffuseFactor = max(dot(-lightVec, normal),0)   --------------------------------------------------------------------(2)

其中,lightVec是光线的入射向量,normal是入射点的顶点法线。所以,物体经过漫反射作用之后,物体表面的颜色应满足的公式为:

                  f = DiffuseFactor * Cd * Md 

Cd代表漫反射光,Md代表物体对漫反射光的材质属性,解释和环境光相似。

 (3)镜面光可以理解为当有光线照射到某表面时,由于表面绝对光滑,光线基本没有损耗,会直接反射出去。这种反射与漫反射不同之处在于,镜面反射光是有一个范围的,一般认为是一个圆锥形,如果眼睛没有在这个圆锥之类,就根本看不见有任何光;如果眼睛离圆锥的中心线(即反射光线)越近看见的光线越强,否则越弱。因而在计算镜面光对物体表面颜色的影响时,必须把视点和入射点的射线和圆锥体的中心线之间的角度考虑进去。同样,这也相当于镜面光的一个影响因子。可以用lambert定律来描述:

       specularFacotr = max(dot(reflectLight,vertexToEye),0) --------------------------------------------------------------------(3)

一般会对该影响因子做乘方以更好的控制该因子,因此镜面光的影响因子是

                specularFacotr = pow(max(dot(reflectLight,vertexToEye),0),p)

类似于环境光和漫反射光,当物体经过镜面光作用之后,物体表面的颜色公式应满足:

                f = specularFactor * Cs * Ms

其中,Cs是镜面光,Ms是物体对镜面光的材质属性。

三种光源:

  光源产生的效果就是上述三种光的综合作用效果。一般来说,有三种光源可以模拟:平行光源,如现实世界中的太阳到地球;点光源,如现实世界中的灯泡;聚光灯,如现实世界中的手电筒。我们模拟的光源发出的光自然包含有“环境光”、“漫反射光”、“镜面光”三种模拟光在里面。因此,计算一种光源对物体颜色的影响就是计算其包含的三种模拟光对物体颜色的影响,然后再加上它们自身的性质的一些影响,因为它们三种光源有是不同的性质的。光源对物体颜色的影响也可以叫做某种光源的光照模型。

  (1)平行光源只有光的方向,没有光源的位置。在平行光源中,环境光的计算依然使用公式(1);对于漫反射光的计算,公式(2)中的lightVec就是平行光源的光的方向。由于光的方向是一定的,所以所有顶点的光照计算都只用一个方向即可,换句话说,shader中不需要进行额外的入射光方向的计算。在程序初始化的时候,平行光的光方向已经确定,只需要传入shader中即可;对于镜面光的计算,公式(3)中的reflectLight就是平行光的光方向的发射光线,vertexToEye需要在shader中逐点计算。因此,平行光的光照模型是:

       f = Ca * Ma + max(dot(-lightVec,normal),0) * Cd * Md + pow(max(dot(reflectLight, vertexToEye),0),p) * Cs * Ms

  平行光与点光源和聚光灯最大的区别就是:平行光没有衰减,而其他两个是有衰减的。一般我们通过线性关系来描述这种衰减。

        d = distance(VertexPos,lightPos)  

        A = a0 + a1 * d + a2 * d * d

其中,A就是某顶点和光源之间的衰减,随着距离越大衰减越严重。

  引入了衰减之后,点光源和聚光灯的光照模型就可以加入衰减的影响。

  (2)点光源只有光的位置,没有光的方向。在点光源中,环境光的计算依然使用公式(1);对于漫反射光的计算,公式(2)中的lightVec是逐点计算的从顶点到光源的位置。主程序中无法进行该向量值的计算,只有在shader中逐点计算。换句话说,不需要从主程序传递该值到shader;对于镜面光的计算,公式(3)中的reflectLight和vertexToEye向量是需要在shader中逐点计算的。点光源的光照模型仅仅比平行光多了一个衰减而已,为:

                f = Ca * Ma + (max(dot(-lightVec,normal),0) * Cd * Md + pow(max(dot(reflectLight, vertexToEye),0),p) * Cs * Ms) / A

 (3)聚光灯比起点光源又加入了一个自己的影响因子。因为聚光灯既有方向又有位置。聚光灯的位置类似于点光源的位置,聚光灯的方向类似于镜面光的方向,即如果顶点不在聚光灯光线的圆锥体内,那么这个顶点肯定是不会被看到的。因此,聚光灯影响因子为:

          spotFactor = max(dot(lightDir, lightPosToVertex),0),通常也用乘方修饰。

聚光灯的光照模型为:

        f = spot * [Ca * Ma + (max(dot(-lightVec,normal),0) * Cd * Md + pow(max(dot(reflectLight, vertexToEye),0),p) * Cs * Ms) / A]

如下左图的点光源和下右图的聚光灯的效果。

 

posted @ 2013-07-25 19:41  兜兜转转  阅读(823)  评论(0编辑  收藏  举报