渲染器品种繁多,有Max自带的、MentalRay、Brazil、Luma、RayMax、Radioray、FinalRender、 VirtualLight、Lightscape、Maya自带的、Renderman(包括Prman和BMRT)、POVRay、XSI的 MentalRay、Mantra(Houdini的)、Cinema 4D XL等等。
它们的渲染效果各有不同,速度、特点也有不同,但这不是主题,我在这里就不详细叙述了。
其实所有的渲染器都离不开三种最基本的渲染算法:扫描线、光线跟踪、辐射度,这次我们就只说说这三种算法是怎么样工作的。(不谈好坏了,上次已经说够了 ;-) )
说这三种算法之前我们先讲讲光照的计算方法,影响光照的有什么因素。
一、光照:
什么是光照?就是光线照射到物体上。广义上的光照是Global Illumination,就是全局光照。但这里先说狭义的光照,就是物体上的一点受到光的照射后软件怎么样计算它的光照强度。
首先我引入一个概念:法线。
三维动画中的法线十分重要,
法线是定义平面的方向的变量,严格上说,法线应该垂直于平面。
但是!为了让多边形更好地工作,所以我们转变了一下法线的使用。
看下面这个球体的表面,黑线表示球体的解释式所求出的多边形,但要很多的多边形模拟,所以我们用比较少的多边形模拟球体(红色的线表示)。
可是这样渲染出来的面十分不好看(可以使用Flat光照模式看看效果),面一块一块的。
为了解决这个问题,我们在顶点引入渲染法线(绿色的线),它并不同于表面的法线(紫色的线):
然后法线中间的点就计算点到四个顶点的距离的比再乘上法线的值得出这个点的法线。图中蓝色的线就是紫色的线与绿色的线的平均值。
这样就有了下面的问题,虽然表面是平滑的,但边缘却是有棱有角突起的,这个问题我记得王老师好象在***人二就在说Polygon和Nurbs的时候提出过。因为当时Max引入了Nurbs,Nurbs就不存在这种问题。
因为nurbs是一种解释曲面,是用软件解释表面的点的数学描述曲面。(关于Nurbs我会另外写一篇文章)
知道了什么是法线,那光照就容易解决了。
看上图,光源L向P点照射,N为P点的法线,视点为V,那么P点上受到L的光照为:
Lambert:
I = kd * Il * cos * decay * dist(P,L)
Phong:
I = [ Il * ( kd * cos + ks * cos ^ n ) ] * decay * dist(P,L) 其中H = (L + V)/2
Blinn:
I = Il * cos dw ( kd * Rd + ks * Rs ) 其中Rs = F * D * G / pi * cos cos (F、D、G的计算十分复杂,详细叙述对大多数人没有意义,想仔细了解的可以联络我)
Il为灯光的颜色,kd为漫反射系数,ks为高光系数(包含高光颜色),n就是Maya中的cospower,decay是衰减,cos表示A和B的夹角的cos值。
CookTorrance的是在Blinn的基础上加入光谱计算,Metal的只是在Lambert的基础上加入高光控制,Anistropic和Stratuss的都比较抽象。
上面的公式比较抽象,但仔细看一看就发现并不难理解(除了Blinn的,因为如此复杂所以在Max2.0时才加入了),如果可以理解对于用好各种材质会有很大的帮助。
(如果你要学写ShadingLanguage,那上面的公式就必须好好的理解)。
分析:
仔细地看可以知道Lambert模型是简单地把光线的入射角和光照亮度联系在一起,只有漫反射系数,没有高光,适合表现纸、墙壁、树木躯干等没有高光的材料。
而Phong加入了对高光的控制,是用一个幂次来控制的,如果数学不错的朋友就可以知道Phong的高光变化其实就是幂函数的图象(如果不知道是怎么样的就查查数学书),这样的高光最适合塑料。
而Blinn比较复杂,但通过我的分析(是我的分析,所以可信度不高……),Blinn的高光在Roughness和Specular rolloff的控制下,从中心到一定的范围不变,但超出Specular rolloff后就以Roughness的值变化(Roughness通过Fresnel项计算,比较复杂)。这个可能要多练习才可以控制得好。
要注意的是法线消隐和定向,比如说用了法线消隐,法线和灯光夹角大于90度小于0度的面就可以不用显示了(Backface culling),而且双面材质也是靠法线确定哪一面用什么材质的。
线、面的光照模型:
现在的软件都有了线、面的光源,线、面的光照比上面的要复杂,但都是以采样的方式计算。MR中就提供了Sample这个参数,就是计算一点上的光照时对光源的线或面进行的采样数目。
二、扫描线
这是大家最熟悉的,特别是从3ds开始玩起的元老。
扫描线的基本概念就是把场景内的物体一一投影到视平面上,通过Z值的比较,距离视平面最近的物体就可以看见,距离远的就被消隐。
Zbuffer算法是最优秀的扫描线算法之一。
假设要渲染一幅 720 X 576 的图画,那么系统就分出720 X 576 X 5(RGBAZ) X sizeof(float)的内存,然后逐一象素渲染,写入画面信息。
但实际中渲染只要分配一行的Z深度值就够了。
描线其实就这么多内容,关键是实现的时候有不同的方法,比如Renderman的经典算法REYES,可是那不是做动画的人要了解的内容,是写程序的人要头痛的,所以在这就不多说了。
三、光线跟踪
下面我们集中讲述光线跟踪,毕竟它是我们用得最多最频繁的。
光线跟踪里最复杂的计算方法是MentalRay里面的,用可怕两个字形容绝对不过分。
光线跟踪的基础是把光线看成没有大小和长度的射线,从光源开始发射,到漫反射面或背景(无交)就结束。
光线跟踪已经十分成熟,有很多辅助算法使光线跟踪实现很多各种各样的效果,比如最好的运动模糊和景深算法分布式光线跟踪,Caustic模拟算法双向光线跟踪,GI算法Monte Carlo积分法和PhotonMap法等等,而且光线跟踪是辐射度渲染的基础,是唯一的折射算法。
光线跟踪的加速也做的越来越好,BSP算法已经可以极大地加速光线跟踪,而且还可以加速Antialiasing。
光线跟踪一般是逆向求交的,因为如果跟踪从光源发出的光线,那么就有大部分的光线都没有对画面进行贡献(非GI求解)。所以光线跟踪一般从视平面出发跟踪。
光线跟踪的过程如下:
从镜头计算出发出的光线(一般垂直于镜头),原点为镜头上的一点(假设正在渲染640 X 480的画面,可以把镜头分成640 X 480个小平面,每个平面代表一象素——一点),然后光线象场内发射
图片比较容易理解吧。
实现的时候会用递归算法,十分耗效率,所以反射/折射的次数要尽量少。
或许会觉得以上的算法已经比较复杂,但MentalRay给出了一种更复杂的算法,而且现在Max、Maya的渲染有学习的趋向.
光线跟踪还有分布式光线跟踪和双向光线跟踪。
分布式光线跟踪是一种空间采样法,可以更好地表现画面的细节。他的思想是把要跟踪的象素划分成16个更小的格子(其实不一定是16个,只不过16个是 4 X 4的Sampling),然后对这16个格子的光线进行一定的随机打乱方向(当然不能太乱),然后把跟踪的结果进行某种(详细是哪一种由软件定夺)加权平均的计算。
现在分布式光线跟踪多数用在Monte Carlo积分GI计算上,因为可以快速地计算一片物体表面的光能采样。
双向光线跟踪是因为Caustic而诞生的。1986年Arvo用"illumination map"成功地第一次模拟了Caustic现象。其实这就是把一片虚拟的空间贴图包裹在物体上,然后从光源发出光线射向非漫反射物体,贴图接受了光线的能量,变成了非漫反射物体受光照情况的分布图,然后在渲染时再加以采样处理就成了Caustic。因为渲染的时候既有逆向跟踪,也有正向的采样跟踪,所以叫双向光线跟踪。
中国的图形学家朱一宁曾使用加速的算法模拟了一次传递的Caustic现象(1988)!
四、辐射度
辐射度比前面的算法复杂的多啦,涉及很多领域的理论:元面划分、积分逼近、不可见面消隐、空间传递加速算法、子结构等等,使用辐射度最好(最实际)的也就只Lightscape。
与前面的算法一样,辐射度也是模拟逼近算法,所以也靠采样的精度。
辐射度来源于物理学的热辐射,因为光和热的属性十分接近,所以公式也从热辐射度中继承了过来:
我相信很多人——特别是做动画的人——第一次看到这条公式也会和我第一次看到一样——傻了眼,根本不知道说什么。我也是弄了两个多月苦思冥想才开始理解的。当然,有理科背景的人会很快看懂。
我在这儿把辐射度讲得太细也没有必要,因为不多人使用,所以只说说辐射度的工作流程:
1.剖分元面——把场景内的多边形(Nurbs也先划成多边形,曲面的辐射度算法还不成熟)剖分成细小的元面,但不是统一的大小,是按它在空间中的位置、接受周围辐射的形状因子而决定的,通常来说是边角的地方比较分得细,因为辐射度的变化大,而空旷的位置的元面比较大。
2.求解——一般都是使用逐步求精的算法,不断地重复把过剩的能量辐射到周围的元面的过程,直到过剩的能量小于阀值。
3.渲染——为什么已经求解了还要渲染呢?因为辐射度只是负责把场景内的元面的能量分配求出,其他的他不管,所以真正的渲染还要靠扫描线和光线跟踪来完成。
五、渲染前准备
对了,说了那么多渲染的东西,那物体怎么从场景中调入到渲染器里?
渲染前一般还要经过这些步骤:
模型重组/划分 ===》 局部坐标系置换到场景坐标系 ===》 场景坐标系进行取景变换和透视变换 ===》光栅化(就是我们平时所说的渲染)
如果是扫描线算法还要进行多边形剪裁,跨越视平面内外的多边形剪裁到视平面内。
六、其他
还有其他的一些问题,但我以前的一篇文章《渲染器算法的讨论》已经有了十分详细的描述,包括贴图、灯光、材质、光线跟踪的BSP加速法等,有兴趣的朋友可以找一找看。
上面比较集中地谈光照和光线跟踪,是因为各位都多用光线跟踪,本来还可以谈得详细一点,但又怕想《渲染器算法讨论》那样、很多人说看不明白,所以写得比较浅一些。