真实图形学(光照模型)(4/10)
1、光照模型
当物体的几何形态确定之后,光照决定了整个场景的显示结果 。因此,真实感图形的生成取决于如何建立一个合适的光照模型(illumination model)。光照明模型:模拟物体表面的光照明物理现象的数学模型。
“顶点”包括位置关、表面颜色、反射颜色、一个或多个纹理坐标集和一个法向量等属性,其中表面颜色和反射颜色是怎么来的呢?不仅仅依靠人为决定,同时也依靠模拟光源照射在物体上的物理过程。我们在真实世界中能看到五光十色的物体,就是太阳光和物体相互作用影响产生的效果,假如到晚上太阳落山并且没有月亮反射太阳光同时又停电了,那么世界在我们眼中就一片漆黑了。所以说光照处理过程决定了整个场景的绚丽美观程度,在计算机图形引擎中,光照的处理被抽象化成众多的数学公式模型,其中比较常见的依次有(排序方式依据推出的时间从先到后,运行得到的效果从简陋虚假到复杂真实,当然运算效率肯定是从高到低了):
1.Phong光照模型
2-1.png
2.Anisotropic光照模型
2-2.png
3.Fresnel光照模型
2-3.png
4.Blinn光照模型
2-4.png
图片百度找的可能不准确,但是没关系,后面我们要一个一个仔细推导其背后的数学公式,然后在图形引擎中实现,就能看到具体效果了。
过去的固定功能图形流水线被限制只能使用一个光照模型,被称为固定光照模型,当然也就是我们排序的第一个phong光照模型了,因为其数学计算最少,运行效率高,在老式的图形卡中跑得起来,虽然效果最差,当然这个phong光照模型会经过一些调整和增强,如增加输入参数等,也足够用来调整和控制物体的外观表现了,只是效果不那么真实。
现在的可编程图形卡就比较高级了,都能支持cg编程语言,我们基本上都可以自己指定运行的光照模型数学公式,上面那四种是比较通用的光照模型,但其实很多图形引擎都有一套自己的调优光照模型公式,实现的效果可以非常真实且运行效率比较不错,比如寒霜引擎和顽皮狗游戏引擎,这些inhouse引擎基本都是自己实现的高效高真实感光照,甚至有局部高效光线追踪效果(光线追踪效果后面再详细学习)。
比较常见的通用图形API(dx&opengl&vulkan)都提供了一些基本的光照模型模板,在这些光照模型里,一个物体的表面颜色是放射(emissive)、环境反射(ambient)、漫反射(diffuse)、镜面反射(specular)等光照作用的加成总和,同时每种光照作用取决于表面材质的性质(比例亮度和材质本身颜色)和光源的性质(例如光的颜色和位置)的共同作用。我们用一个包含红、绿、蓝三原色的float3的float数组(也可称向量)来表示每种光照作用。
光照作用最终表面颜色公式,如下:
surfaceColor = emissive + ambient + diffuse + specular;
这篇我们就来看看其中分量的意义。
一.放射(emissive)
放射表示了物体表面所发出的光,这种光照作用是独立于所有光源的(比如荧光石黑夜中发光)。放射是一个RGB值,指明了表面所发出的光的颜色,黑夜中荧光石发出的光就是它呈现的颜色。但是在图形引擎中,将放射并不定义为光,这里和现实世界不同,现实世界中不论什么光线都会对其周围的物体照成影响,一个真实物体的放射光也可以是一个光源从而照亮周围物体。图形引擎中为了运行效率考虑,并不将场景中某物体放射带入对其他物体光照影响进行计算,不然假如每个放射物体都是光源,那么可能导致场景计算量太大运行太卡。
放射也可以计算完物体其他所有光照项后添加其颜色,因为放射算是一个非常独立的颜色项。
ps:当然了,有很高级的全局光照模型将物体放射也带入了光照计算,也就是将放射物体当作了光源去计算对周边的光照影响,这就很复杂了。(大部分我们需要这种效果的时候,都是在放射物体中添加一个点光源模拟放射光照)
假如需要用一个数学值表示放射,如下:
emissive = Ke;
①.Ke代表材质的放射颜色
二.环境反射(ambient)
环境反射代表了光在场景中经过多次折射和反射后看起来像来自四面八方一样,就比如太阳光从遥远的地方发射过来,在地球上的某个开着窗户的屋子里,乱七八糟的反射(比如照射到墙壁漫反射,镜子镜面反射)和折射(透过玻璃或者鱼缸),原本算是平行的光线早已散乱了。
环境反射光并不依赖光源的位置,因为光线早已是四面八方的,环境反射依赖于一个物体的材质的环境反射能力,以及照射到材质上的环境光的颜色。和上面那个放射一样,环境反射依赖它本身,是一种固定颜色,但又不像放射颜色,环境反射颜色受全局环境光照影响。
用数学公式去表示环境反射,如下:
ambient = Ka*globalAmbient;
①.Ka是材质的环境反射系数
②.globalAmbient是入射环境光的颜色
三.漫反射(diffuse)
漫反射代表了从一个表面相等地向所有方向反射出去的方向光。通常,漫反射表面在微观尺寸上市非常粗糙的,有许多向很多方向反射光线的凹凸和裂缝,当入射光线达到这些凹凸和裂缝的时候,光线会向各个方向反射。光的反射量与光到达表面的入射角度成正比,例如一块布满灰尘的黑板被认为是漫反射的,无论视点从哪个角度观察,一个表面上任何一点的漫反射影响效果都是一样的。
用数学公式去表示漫反射,如下:
diffuse = Kd*lightColor*max(dot(N,L),0);
①.Kd是材质的漫反射系数
②.lightColor是入射光的颜色
③.N是规范化的表面法向量
④.L是规范化的指向光源的向量
这里来描绘一下,不然可能有点看不懂,如下图:
这里我解释一下,假设“一束”颜色为lightColor的光线从太阳照射到P点上,那么“这束”光线的相反单位向量L与P点所在表面的单位法向量N组成的夹角θ越大就意味着反射量(反射光强)越低(或者说光线单位向量-L与N的夹角越大反射量越高),打个极端的比方,假设L与N夹角为90°,那么就意味着“这束”光线和物体表面“擦边而过”,那就没有反射光了,也就是0(当然也不存在大于90°的情况,大于90°其实“这束”光线就被挡住照射不到P点了)。这里正好用点积去计算L与N得到一个浮动值max(dot(L,N),0)表示光方向与法向量夹角对反射光强的影响。
四.镜面反射(specular)
镜面反射代表了从一个表面主要的反射方向附近被反射的光(实际表现就是反射出一个高亮光斑),镜面反射在非常光滑和光泽的表面是最显著的,例如抛光的镜面。不像漫反射这次乱散的反射,镜面反射的效果依赖于观察者的位置,假如观察者不在一个能接收到反射光线的位置,观察者将不可能在表面上看到一个镜面反射强光(也就是光斑)。镜面反射不仅受光源和材质的镜面反射颜色性质的影响,而且受表面光泽度的影响,越是光泽的材质高光区越小,而较少光泽的材质受到的高光区则分散的很开。
用数学公式去表示镜面反射,如下:
specular = Ks*lightColor*(max(dot(N,H),0))^shininess
①.Ks是材质的镜面反射系数
②.lightColor是入射镜面反射光的颜色
③.N是规范化的表面法向量
④.V是指向视点的规范化向量
⑤.L是指向光源的规范化向量
⑥.H是V和L的中间向量的规范化向量
⑦.shininess是一个大于1的指数,这个指数控制光斑的强度,当然可以看出它控制的底数(max(dot(N,H),0))是属于[0,1]的,也就意味着shininess越大,光斑强度相反越小
这里继续绘画一下,从数学上了解,如下图:
这里解释一下,“光束”的反向量L与反射点P到眼睛的向量V(也就是“视线”的反向量)的夹角β越大,那么max(dot(N,H),0)^shininess的值就越小(反之β越小,值就越大),那么最终求得的specular值就越大,意味着反射光量(或者说光强)越高,越容易形成高亮光斑。
五.综合
最后我们根据最顶上的公式:
surfaceColor = emissive + ambient + diffuse + specular;
将这些颜色分量相加,那么求得的surfaceColor就是渲染出来的最终效果。光照模型属于前人经验总结的公式。
WEBGL学习网 » 真实图形学(光照模型)(4/10)