紧接上一篇:https://blog.csdn.net/yinhun2012/article/details/79984729
之前我们了解了计算机图形显示所需要的两个重要硬件(显示器和GPU),现在我们就来学习下到底GPU是怎么把应用数据处理好并输出给显示器进行图形显示的。
目前我们只能浅层次的了解图形显示的这个过程,就跟工厂流水线一样(为什么说工厂流水线呢,大概就是第二次工业革命诞生了由电力驱动的工厂流水线生产模式,所以工厂这个词就火起来了,比如设计模式中就有工厂设计模式,图形学中也有个图形流水线),“图形数据原材料”从一条条皮带这头送进去,然后依次通过一台又一台特定功能的“图形数据组装机器”,材料每通过一台机器就被组装成一个新的样子,最终通过最后一台机器的时候,就在显示器上显示出了该有的图像。这个“图形工厂流水线”就是一系列可以并行和按照固定顺序进行的“图形数据组装”阶段的结合,每个阶段都从他的前一阶段接收输入的“数据原材料”,然后组装生成新的“数据次加工材料”,再把这些“数据次加工材料”输出给下一个阶段,按照一种流水线的方式处理大量的顶点、几何图元和片段,具体的处理示意图如下:
①.首先我们从“原材料”顶点来看,其实每个顶点除了包含位置关系之外,还有其他属性,比如表面颜色、反射颜色、一个或多个纹理坐标集和一个法向量,法向量是用来表示这个顶点所在的平面的垂直向量,这个向量的作用在光照计算中有用(光照计算后面我们就会学习,但是通过向量几何那一类博文中,我们也知道计算平面法向量对于光线计算的作用了)。
②.然后经过第一台叫“顶点变换”的机器,这台机器其实就是在每个顶点上执行一系列数学操作,这些操作包括把顶点位置变换到屏幕位置(目前可能不太明白这个变换到底做了些什么,后面会有详细的讲解)以便光栅器使用,为贴图生成纹理坐标,以及照亮顶点以决定它的颜色(也叫顶点着色)。
③.然后经过“顶点图元装配和光栅化”的机器,首先,在图元装配阶段根据伴随顶点序列的几何图元分类信息将顶点装配成集合图元,这个过程将产生一堆三角形、线段和点(这个好理解,前面我们用api构建网格就是构建的三角形拓扑集合数组,并且数学上点线面构成几何体也算是常识),这些图元需要经过裁切到可视平截体(三维空间中摄像机的视域形成的一个平截体,这些括号内暂时让人困惑的概念和名字后面都会详细讲解),光栅器还可以根据多边形的朝前或者朝后来丢弃一些多边形,这个过程叫做culling(这个应该也好理解,比如以我的眼睛形成的可视平截体正看着电脑屏幕那么屏幕后面的散热口肯定是看不见了,这些看不见的顶点就被忽视剔除掉了,具体culling方法比如判断前后顶点A和B距离我的眼睛的距离,距离偏远的顶点B假定为需要剔除的顶点,然后判断这个需要剔除的顶点B和我的眼睛连线所组成的直线是否和前顶点A所在的几何体的平面相交,假如相交那么就能确定这个顶点B就是被顶点A所在的几何体平面遮罩了)。
接着这些经过裁切和挑选剩下的多边形必须进行光栅化,光栅化是一个决定哪些像素被几何图元覆盖的过程,多边形、线段和点根据为每种图元指定的规则分别被光栅化,光栅化的结果是像素位置的集合和片段的集合,当光栅化后,一个图元拥有的顶点数目和产生的片段之间没有任何关系。(这里怎么理解呢?假如我们常用的1080p显示器上显示就显示一个三角形,三角形嘛,就三个顶点,可是在显示器上就不止需要显示三个顶点了,之前我描绘了一下斜线的栅格化,这个三角形就可以想象成三条斜线的栅格化,然后组成的三角形区域还需要像素填充满,这样才是一个三角形),形象的示意图如下:
黑色的虚线就是我们要绘制的三角形,那么光栅化后,圆珠笔填充的区域就是三角形三斜边光栅化后的线段,铅笔填充的区域也是三角形光栅化后包含的片段数组。
ps:这里我顺便解释下片段和像素的区别,前面我说片段暂时就认为是像素,两着其实就是成长关系。先说像素,一个像素代表帧缓存中某个指定位置的内容,一个像素包含颜色、深度和其他与这个指定位置相关联的值。再说片段,一个片段就是光栅化后每个几何图元(比如上面画的那个三角形)所覆盖的像素分解成像素大小的片段(铅笔涂抹的小方块),一个片段有一个与之相关联的像素位置、深度值和经过插值的参数。例如颜色、反射颜色以及一个或多个纹理坐标集,这些各种各样经过插值的参数来自于变换过的顶点,这些顶点组成了某个用来生成片段的集合图元,我们目前可以将片段看成像素的“种子”,经过成长(各种光栅化测试),最后成为帧缓存中像素数据。
④.然后通过”插值、贴图和着色“的机器,当一个图元被光栅化成为一堆片段的时候,插值、贴图和着色阶段就在片段属性需要的时候插值,执行一系列的贴图和数学操作,然后为每个片段确定一个最终的颜色,除了确定片段的最终颜色之外,这个阶段还要确定一个深度信息,亦或者丢弃这个片段以避免更新帧缓存对应的像素。
⑤.然后通过”片段光栅操作“的机器,片段光栅操作在最后更新帧缓存之前,执行最后一系列的针对每个片段的操作,这些操作时opengl和dx3d的一个标准组成部分,这个阶段中,隐藏面通过一个被称为深度测试的过程而剔除,其他的一些效果,比如混合和基于模板的阴影也发生在这个阶段(打个比方,比如一个金项链被锁在玻璃壁柜里面,玻璃片显然遮住了金项链,但是因为玻璃是透明的,所以我们不能直接剔除金项链的显示,而需要混合金项链和玻璃的颜色,最终达到一个金项链在玻璃后面的效果)。
片段光栅操作将通过不止一种测试法检查每个片段,具体这些测试包含剪切、alpha、模板和深度等测试,这些测试是确定片段最后的颜色和深度以及像素的位置和一些像素值(像素深度值和模板值),如果任何一项测试失败了,当前片段就会被丢弃从而更新像素的颜色值。通过了深度测试的片段的深度值可以代替像素的深度值。在这些测试成功之后,一个混合操作将把片段的最后颜色和对应像素结合起来,最后,一个帧缓存写操作用混合的颜色代替像素的颜色,这个操作的具体示意图如下:
ps:这里解释一下什么是模板测试,模板顾名思义就是一个标准产考物,假设我们建立一个和显示器像素矩阵行列数相匹配的模版矩阵,模版矩阵是由数字0和1组成的,0代表丢弃该行列索引的片段,1代表保留这个行列索引的片段,那么就做到了一个特定裁剪图元的功能,演示一下如下图:
如果我们按照左图的模板矩阵裁剪图元,那么就能裁剪出右边的矩形图形。
⑥.接着我们来个缩略的图形流水线生产过程的示意图,如下图:
其实最后还有个片段光栅操作,也就是最终决定到底该不该显示图形的一系列测试过程,这个过程在三维场景渲染中广泛运行,后面我们一并对三维场景到底如何显示在屏幕这个二维像素矩阵上进行理解和学习。