渲染管线有时也称为渲染流水线,一般是由显示芯片(GPU)内部处理图形信号的并行处理单元组成。
WebGL 2.0中渲染管线实质上指的是一系列的绘制过程。向程序中输入待渲染3D物体的相关描述信息数据,经过渲染管线处理后,输出的是一帧想要的图像。WebGL 2.0中的渲染管线如下图:
该阶段设定3D空间中物体的顶点坐标、顶点对应的颜色、顶点的纹理坐标等属性,并且指定绘制方式,如点绘制、线段绘制或者三角形绘制等。
对于在整个场景中顶点基本数据不变的情况,这部分在程序中是可选的。
可以在初始化阶段将顶点数据经过基本处理后送入顶点缓冲对象,这样在绘制每一帧想要的图像时就省去了输入/输出顶点数据的麻烦,直接从顶点缓冲对象中获得顶点数据即可。
相比于每次绘制时单独将顶点数据送入GPU的方式,它可以一定程度上节省GPU的I/O带宽,提高渲染效率。
顶点着色器是一个可编程的处理单元,功能为执行顶点的变换、光照、材质的应用与计算等与顶点相关的操作,每个顶点执行一次。
其工作过程为首先将顶点的原始几何信息及其他属性传送到顶点着色器中,顶点着色器处理后产生相应的纹理坐标、颜色、点位置等后继流程需要的各项顶点属性信息,然后将其传递给图元装配阶段。
WebGL 2.0中顶点着色器的工作原理如图:
gl_Position、gl_PointSize以及内建输入变量gl_VertexID、gl_InstanceID来说,gl_Position是经过矩阵变换、投影后的顶点最终位置;gl_PointSize指的是点的大小;gl_VertexID用来记录顶点的整数索引;gl_InstanceID是指实例ID,它只在顶点着色器中使用,对于指定的每一组图元,该ID相应递增。
在这个阶段主要有两个任务,一个是图元组装,另一个是图元处理。
所谓图元组装是指顶点数据根据设置的绘制方式被结合成完整的图元。
例如,在点绘制方式下每个图元仅需要一个单独的顶点,在此方式下每个顶点为一个图元;
在线段绘制方式每个图元则需要两个顶点,在此方式下每两个顶点构成一个图元;
在三角形绘制方式下需要3个顶点构成一个图元。
图元处理最重要的工作是剪裁,其任务是消除位于半空间(half-space)之外的部分几何图元,这个半空间是由一个剪裁平面定义的。例如,点剪裁就是简单地接受或者拒绝顶点,线段或多边形剪裁可能需要增加额外的顶点,这具体取决于直线或多边形与剪裁平面之间的位置关系,如下图:
要进行剪裁是因为随着观察位置、角度的不同,不能总看到(这里可以简单地理解为显示到设备屏幕上)特定3D物体上某个图元的全部。例如,当观察一个正四面体但它离某个三角形面很近时,可能只能看到此面的一部分,这时在屏幕上显示的就不再是三角形了,而是经过裁剪后形成的多边形,如下图所示:
虽然虚拟3D世界中的几何信息是三维的,但由于目前用于显示的设备都是二维的,因此在真正执行光栅化工作之前,需要将虚拟3D世界中的物体投影到视平面上。需要注意的是,由于观察位置的不同,同一个3D场景中的物体投影到视平面上时可能会产生不同的效果,如下图所示:
另外,由于在虚拟3D世界中物体的几何信息一般采用连续的量来表示,因此投影的平面结果也是用连续量来表示的。
但目前显示设备屏幕都是离散化的(由一个个的像素组成),因此还需要将投影结果离散化,将其分解为一个个离散化的小单元,这些小单元一般称为片元,具体效果如下图所示:
**其实每个片元都对应于帧缓冲中的一个像素,之所以不直接称为像素是因为3D空间中的物体是可以相互遮挡的。**一个3D场景最终显示到屏幕上虽然是一个整体,但每个3D物体的每个图元都是独立处理的。这就可能出现以下情况,系统先处理的是位于离观察点较远的图元,其光栅化成为一组片元,暂时送入帧缓冲的对应位置。但在后面继续处理离观察点较近的图元时也光栅化出了一组片元,两组片元又对应到帧缓冲中同一个位置,这时距离近的片元将覆盖距离远的片元(如何检测覆盖是在深度检测阶段完成的)。因此某个片元就不一定能成为最终屏幕上的像素,这样称为像素就不准确了,可以将其理解为候选像素。
每个片元包含对应的顶点坐标、顶点颜色、顶点纹理坐标以及顶点深度等信息,这些信息是系统根据投影前此片元对应3D空间中的位置及与此片元相关的图元中各顶点信息进行插值计算而生成的。
片元着色器是处理片元值及相关数据的可编程单元,可以执行纹理采样、颜色汇总、计算雾颜色等操作,每个片元执行一次。片元着色器的主要功能为通过重复执行(每个片元一次),将3D物体中的图元光栅化后每个片元产生的颜色等属性计算出来并送入后继阶段,如剪裁测试、深度测试及模板测试等。
原来在WebGL 1.0中片元着色器的内建输出变量gl_FragColor在WebGL 2.0中不存在了,如果需要输出颜色值,则需要声明out(类型为vec4)变量,用声明的变量替代gl_FragColor。在开发中,应尽量减少片元着色器的运算量,可以将一些复杂运算放在顶点着色器中执行。
如果程序中启用了剪裁测试,则程序会检查每个片元在帧缓冲中的对应位置。若对应位置在剪裁窗口中则将此片元送入下一阶段,否则丢弃此片元。
深度测试是指将输入片元的深度值与帧缓冲中存储的对应片元位置的深度值进行比较,若输入片元的深度值小,则将输入片元送入下一阶段,准备覆盖帧缓冲中的原片元或与帧缓冲中的原片元进行混合,否则丢弃输入片元。
模板测试的主要功能为将绘制区域限定在一定范围内。它一般用在湖面倒影、镜像等场合。
程序中开启了Alpha混合,则根据混合因子会将上一阶段送来的片元与帧缓冲中对应位置的片元进行Alpha混合;否则送入的片元将覆盖帧缓冲中对应位置的片元。
抖动是一种简单的操作,允许使用少量的颜色模拟出更宽的颜色显示范围,从而使颜色视觉效果更加丰富。例如,可以使用白色以及黑色模拟出一种过渡的灰色。但使用抖动也是有缺点的,那就是会损失一部分分辨率,因此对于主流原生颜色已经很丰富的显示设备来说,一般是不需要启用抖动的。
WebGL 2.0中的物体绘制并不是直接在屏幕上进行的,而是预先在帧缓冲中进行绘制,每绘制完一帧将绘制结果交换到屏幕上。
因此,在每次绘制新帧时都需要清除缓冲中的相关数据,否则有可能产生不正确的绘制结果。
同时需要了解的是为了应对不同方面的需要,帧缓冲是由一套组件组成的,主要包括颜色缓冲、深度缓冲以及模板缓冲,各组件的具体用途如下所示。
国家大剧院远景和近景的照片:
从两幅照片可以对比出,现实世界中的某些建筑物远看是平滑的曲面,近看则是由一个个的小平面组成的。3D虚拟世界中的物体也是如此,任何立体物体都是由多个小平面搭建而成的。这些小平面切分得越小,越细致,搭建出来的物体就越平滑。当然WebGL 2.0的虚拟世界与现实世界还是有区别的,现实世界中可以用任意形状的多边形来搭建建筑物,例如,上图中的国家大剧院就是用四边形搭建的,而WebGL 2.0中仅允许采用三角形来搭建物体。这从构造能力上来说并没有区别,因为任何多边形都可以拆分为多个三角形。
WebGL 2.0采用的是右手标架坐标系。一般来说,初始情况下y轴平行于屏幕的竖边,x轴平行于屏幕的横边,z轴垂直于屏幕平面。
本章参考如下:
《WebGL 3D 开发实战详解》