延迟着色法
延迟着色法基于我们延迟(Defer)或推迟(Postpone)大部分计算量非常大的渲染(像是光照)到后期进行处理的想法。它包含两个处理阶段(Pass):在第一个几何处理阶段(Geometry Pass)中,我们先渲染场景一次,之后获取对象的各种几何信息,并储存在一系列叫做G缓冲(G-buffer)的纹理中;想想位置向量(Position Vector)、颜色向量(Color Vector)、法向量(Normal Vector)和/或镜面值(Specular Value)。场景中这些储存在G缓冲中的几何信息将会在之后用来做(更复杂的)光照计算。下面是一帧中G缓冲的内容:
我们会在第二个光照处理阶段(Lighting Pass)中使用G缓冲内的纹理数据。在光照处理阶段中,我们渲染一个屏幕大小的方形,并使用G缓冲中的几何数据对每一个片段计算场景的光照;在每个像素中我们都会对G缓冲进行迭代。我们对于渲染过程进行解耦,将它高级的片段处理挪到后期进行,而不是直接将每个对象从顶点着色器带到片段着色器。光照计算过程还是和我们以前一样,但是现在我们需要从对应的G缓冲而不是顶点着色器(和一些uniform变量)那里获取输入变量了。
下面这幅图片很好地展示了延迟着色法的整个过程:
这种渲染方法一个很大的好处就是能保证在G缓冲中的片段和在屏幕上呈现的像素所包含的片段信息是一样的,因为深度测试已经最终将这里的片段信息作为最顶层的片段。这样保证了对于在光照处理阶段中处理的每一个像素都只处理一次,所以我们能够省下很多无用的渲染调用。除此之外,延迟渲染还允许我们做更多的优化,从而渲染更多的光源。
在几何处理阶段中填充G缓冲非常高效,因为我们直接储存像素位置、颜色、法线等对象信息到帧缓冲中,而这几乎不会消耗处理时间。在此基础上使用多渲染目标(Multiple Render Targets, MRT)技术,我们甚至可以在一个渲染处理之内完成这所有的工作。
G缓冲
G缓冲(G-buffer)是对所有用来储存光照相关的数据,并在最后的光照处理阶段中使用的所有纹理的总称,主要包括Position、Color、Normal、Specular等。
坐标系统
为了将坐标从一个坐标系转换到另一个坐标系,我们需要用到几个转换矩阵,最重要的几个分别是模型(Model)、视图(View)、投影(Projection)三个矩阵。首先,顶点坐标开始于局部空间(Local Space),称为局部坐标(Local Coordinate),然后经过世界坐标(World Coordinate),观察坐标(View Coordinate),裁剪坐标(Clip Coordinate),并最后以屏幕坐标(Screen Coordinate)结束。下面的图示显示了整个流程及各个转换过程做了什么:
- 局部坐标是对象相对于局部原点的坐标;也是对象开始的坐标。
- 将局部坐标转换为世界坐标,世界坐标是作为一个更大空间范围的坐标系统。这些坐标是相对于世界的原点的。
- 接下来我们将世界坐标转换为观察坐标,观察坐标是指以摄像机或观察者的角度观察的坐标。
- 在将坐标处理到观察空间之后,我们需要将其投影到裁剪坐标。裁剪坐标是处理-1.0到1.0范围内并判断哪些顶点将会出现在屏幕上。
- 最后,我们需要将裁剪坐标转换为屏幕坐标,我们将这一过程成为视口变换(Viewport Transform)。视口变换将位于-1.0到1.0范围的坐标转换到由glViewport函数所定义的坐标范围内。最后转换的坐标将会送到光栅器,由光栅器将其转化为片段。
HDR(High Dynamic Range高动态范围)
HDR原本只是被运用在摄影上,摄影师对同一个场景采取不同曝光拍多张照片,捕捉大范围的色彩值。这些图片被合成为HDR图片,从而综合不同的曝光等级使得大范围的细节可见。看下面这个例子,左边这张图片在被光照亮的区域充满细节,但是在黑暗的区域就什么都看不见了;但是右边这张图的高曝光却可以让之前看不出来的黑暗区域显现出来。
深度冲突
防止深度冲突
- 第一个也是最重要的技巧是让物体之间不要离得太近,以至于他们的三角形重叠。通过在物体之间制造一点用户无法察觉到的偏移,可以完全解决深度冲突。在容器和平面的条件下,我们可以把容器像+y方向上略微移动。这微小的改变可能完全不被注意但是可以有效地减少或者完全解决深度冲突。然而这需要人工的干预每个物体,并进行彻底地测试,以确保这个场景的物体之间没有深度冲突。
- 另一个技巧是尽可能把近平面设置得远一些。前面我们讨论过越靠近近平面的位置精度越高。所以我们移动近平面远离观察者,我们可以在椎体内很有效的提高精度。然而把近平面移动的太远会导致近处的物体被裁剪掉。所以不断调整测试近平面的值,为你的场景找出最好的近平面的距离。
- 另外一个技巧是放弃一些性能来得到更高的深度值的精度。大多数的深度缓冲区都是24位。但现在显卡支持32位深度值,这让深度缓冲区的精度提高了一大节。所以牺牲一些性能你会得到更精确的深度测试,减少深度冲突。
光照模型
1967年,wylie等人第一次在显示物体时加进光照效果。wylie认为,物体表面上一点的光强,与该点到光源的距离成反比。
1970年,Bouknight提出第一个光反射模型,指出物体表面朝向是确定物体表面上一点光强的主要因素,用Lambert漫反射定律计算物体表面上各多边形的光强,对光照射不到的地方,用环境光代替。
1971年Gourand提出的基于“漫反射模型与插值”思想的Gourand模型。对多面体模型,用漫反射模型计算多边形顶点的光亮度,再用增量法插值计算。
1975年,phong提出图形学中第一个有影响的简单光照明模型。模型虽然只是一个经验模型,但是其真实度已达到可以接受的程度。在phong光照模型的基础之上,相继出现了Goud明暗处理和phong明暗处理两个增量式光照模型。
1980年,whitted提出了一个光透射模型:whitted模型,并第一次给出光线跟踪算法的范例,实现了模型它综合考虑了光的反射、折射透射、阴影等。从本质上来说,whitted模型也只是一种经验模型,它仅考虑特定方向上的环境入射光对被照射点的光亮度共线,因而它仅能模拟理想的镜面反射和规则的投射效果。
1982年,Cook和Torrance为了克服Phong模型的缺点,提出了一个基于物理光学的表面反射模型—Cook-Torrance模型“使得模型中反射光的位置和分布与实际情况非常接近,因而用它绘制的图形具有很好的质感。
1983年,Hall和Greenbert在whitted基础上此进一步给出Hall光透射模型,考虑了漫透射和规则透射光。改进了whitted中投射高光效果,并再环境光中加入距离衰减因子,使之能够更好的模拟物体表面的透射特性。
1986年,Kajiya统一了以前所有的光照模型.Kajiya首先提出使类似于随机采样的蒙特卡罗(Monte Carlo)方法求解绘制方程的光线追踪算法(Raytracing), 通过对到达图像平面上的光线路径进行采样,然后估计它们对最终图像的贡献来生成图像.
环境光:
Iambdiff = Kd*I a
其中Ia表示环境光强度,Kd(0<K<1)为材质对环境光的反射系数,Iambdiff是漫反射体与环境光交互反射的光强。
方向光:
Ildiff = Kd * Il * Cos(θ)
其中Il是点光源强度,θ是入射光方向与顶点法线的夹角,称入射角(0<=A<=90°),Ildiff是漫反射体与方向光交互反射的光强,若 N为顶点单位法向量,L表示从顶点指向光源的单位向量(注意顶点指向光源),则Cos(θ)等价于dot(N,L),故又有:
Ildiff = Kd * Il * dot(N,L)
最后综合环境光和方向光源,Lambert光照模型可以写成:
Idiff = Iambdiff + Ildiff = Kd * Ia + Kd * Il * dot(N,L)
Phong模型认为镜面反射的光强与反射光线和视线的夹角相关:
Ispec = Ks * Il*(dot(V,R)) Ns
其中Ks 为镜面反射系数,Ns是高光指数,V表示从顶点到视点的观察方向,R代表反射光方向。由于反射光的方向R可以通过入射光方向L(从顶点指向光源)和物体的法向量求出,
R + L = 2 * dot(N, L) * N 即 R = 2 * dot(N,L) * N - L
所以最终的计算式为:
Ispec = Ks * Il * ( dot(V, (2 * dot(N,L) * N – L ) )Ns
Blinn-Phong是一个基于Phong模型修正的模型,其公式为:
Ispec = Ks * Il * (dot(N,H) )Ns
其中N是入射点的单位法向量,H是光入射方向L和视点方向V的中间向量,通常也称之为半角向量(半角向量被广泛用于各类光照模型,原因不但在于半角向量蕴含的信息价值,也在于半角向量是很简单的计算:H = (L + V) / |L + V| )。
Rendering Equation 是Kajia在1986年提出的,
Lo(X, Wo) = Le(X, Wo) + ∫fr(X, Wi, Wo) Li(X, Wi) dot(N, Wi) dWi
其中X表示入射点,Lo(X, Wo)即从物体表面X点,沿方向Wo反射的光强,Le(X, Wo)表示从物体表面X以方向Wo 发射出去的光强,该值仅对自发光体有效,fr(X, Wi, Wo)为,入射光线方向为Wi, 照射到点X上,然后从Wo方向发射出去的BRDF值,Li(X, Wi)为入射方向为Wi照射到点X上的入射光强,N表示点X处的法向量,然后对入射方向进行积分(因为光线入射的方向是四面八方的,积分的意义是对每个方向进行一遍计算后相加),计算的结果就是全局光照的辐射率。
对于单个点光源照射到不会自发光的物体上,公式可以简化成:
Lo(X, Wo) = fr(X, Wi, Wo) Li(X, Wi) dot(N, Wi)
这个公式非常有用,通常会将该公式分解为漫反射表达式和镜面表达式之和。对于漫反射表面,BRDF可以忽略不计,因为它总是返回某个恒定值,所以可以写成如下形式:
Lo(X, Wo) = Idiff + frs(X, Wi, Wo) Li(X, Wi) dot(N, Wi)
其中Idiff表示漫反射分量,使用公式的计算方法,frs(X, Wi, Wo)表示镜面反射的BRDF函数,前面的Phong高光模型,其实是rendering equation在单一光源下针对理想镜面反射的特定推导,对于Phong高光而言:
frs(X, Wi, Wo) = Ks (dot(N, H)Ns / dot(N, Wi)
几种光照模型的比较
Lambert 模型能够较好地表现粗糙表面上的光照现象,如石灰墙,纸张等等,但是在渲染金属材质制成的物体时,则会显得呆板,表现不出光泽,主要原因是其没有考虑到镜面反射效果,所以Phong模型对其进行了很好的补充。
由于Blinn-phng光照模型混合了Lambert的漫射部分和标准的高光,渲染效果有时会比 Phong高光更柔和,有些人认为phong光照模型比blinn-phong更加真实,实际上也是如此,Blinn-phong渲染效果要更加柔和一些,但是由于Blinn-phong的光照模型省去了计算反射光线方向向量的两个乘法运算,速度更快,因此成为许多CG软件中默认的光照渲染方法,此外它也继承在了大多数图形芯片中,用以产生实时的快速渲染。在OpenGL和Direct3D渲染管线中,Blinn-Phong就是默认的渲染模型。
Rendering Equation是基于物理光学的模型,其对于观察方向上的辐射率进行了本质上的量化,Phong模型只是其特定BRDF的推导。