1.渲染流水线主要分为三个概念阶段
应用阶段由CPU负责
几何阶段和光栅化阶段由GPU负责
2.从硬盘读取数据并最终加载到显存,一般加载到显存后,内存里的数据就会被清除3.应用阶段的主要任务
- 加载数据到显存
基本步骤就是纹理、网格等数据从硬盘加载到系统内存再加载到显存。数据加载到显存后系统内存中的数据就可以被移除了,但是对于一些数据来说CPU需要访问他们,例如用于碰撞检测用的网格数据,这些数据则会被保留。- 设置渲染状态
渲染状态指的是场景中的网格是如何被渲染的,例如使用哪个Vertex Shader或者哪个Fragment Shader、光源属性、材质等。- 调用DrawCall(图形编程接口)
Draw Call指的是一个命令,发起方为CPU,接收方为GPU。当给定了一个Draw Call时,GPU会根据渲染状态(例如材质、纹理、着色器等)和所有输入的顶点数据进行计算,最终输出成在屏幕上的像素。这个计算的过程就是GPU流水线。
4.几何阶段和光栅化阶段
开发者无法拥有绝对的控制权,实现的载体是GPU,GPU通过实现流水线化,大大提高了渲染速度。虽然无法完全控制两个阶段的具体细节,但是GPU向开发者开放了部分权限,如图,绿色模块代表完全可编程控制;黄色模块代表可配置但不可编程;蓝色模块代表是固定实现
4.1.顶点片元着色器
顶点片元着色器的处理单位是顶点,从CPU输入GPU流水线的每一个顶点数据都会调用一次顶点片元着色器(顶点片元着色器本身不能创建或销毁顶点,也无法得到顶点之间的直接关系)
主要工作:坐标变换和逐顶点光照
坐标转换:将模型顶点的坐标转换到齐次裁剪空间下的坐标
4.2.曲面细分着色器
可选着色器,主要用于细分图元
4.3.几何着色器
可选着色器,用于执行逐片元的着色操作
4.4.裁剪
一个图元与摄像机的关系有三种:完全在视野内、部分在视野内、完全不再视野内。
完全在视野内的图元继续进行下一操作,完全不再的则舍弃,
裁剪的主要任务是将部分不在视野内的图元做裁剪处理
4.5.屏幕映射
主要任务是将裁剪后的齐次坐标(NDC)转换到屏幕坐标系
齐次坐标是由顶点片元着色器转换坐标后,输出后再由硬件做透视除法得到的
几何阶段向光栅化阶段输入顶点的屏幕坐标系数据以及相关信息,深度值、 法线方向等
光栅化阶段完成计算图元覆盖的元素以及元素的颜色
4.6.三角形设置
主要任务是从几何阶段得到的顶点数据,计算三角网格的每条边的像素坐标得到三角形边界的表示方式
4.7.三角形遍历
由上一步得到的三角表示方式,检查被三角形网格覆盖的每一个像素并生成对应的片元,并使用各顶点信息对覆盖区域的像素进行插值,最终输出所有片元的序列。
片元多个状态的集合,包含深度信息、屏幕坐标、顶点信息等,并用与计算像素的最终颜色
4.8.片元着色器
由上一步的顶点信息数据与像素的插值作为输入数据,计算输出一个或多个颜色值
4.9.逐片元操作
决定每个片元的可见性,通过模板测试、深度测试、混合筛选可见的片元,只由通过测试后的片元才能和颜色缓冲区原有的像素颜色混合并写入颜色缓冲区
模板测试
如果开启了模板测试,GPU会首先读取模板缓冲区中该片元位置的模板值,然后将该值和读取到的参考值(可以开发者自己指定)进行比较,开发者可以设定成小于时舍弃或者大于等于时舍弃该片元。模板测试通常用于限制渲染的区域,另外模板测试还有别的高级用法,如渲染阴影,轮廓渲染。
深度测试
如果一个片元幸运的通过了模板测试,那么就会进行深度测试,如果开启了深度测试,GPU就会把该片的深度值和已经存在于深度缓冲区中的深度值进行比较,这个比较函数也是由开发者设定的,可以选择大于此值时舍弃也可以选择小于等于此值时舍弃。但通常这个比较函数是小于等于的关系,这是因为我们我们总想只显示出离摄像机最近的物体,而那些被其他物体遮挡的片元就不需要出现在屏幕上。和模板测试不同的是,如果一个片元没有通过深度测试,他就没有权利修改深度缓冲区中的值。而如果通过了测试,开发者可以通开启/关闭深度写入来决定是否要利用这个片元的深度值覆盖缓冲区中的值。
混合
渲染过程中一个物体接着一个物体画到屏幕上,而每个像素的颜色信息被储存在一个名为颜色缓冲的地方,因此,当我们执行这次渲染时,颜色缓冲中往往已经有了上次渲染后的颜色结果,那么,我们使用这次渲染得到的结果进行其他处理,既是合并需要解决的
对于不透明物体,开发者可以关闭混合操作,这样片元着色器计算得到的颜色值就会直接覆盖掉颜色缓冲区中的像素值。但对于半透明的物体,我们就需要开启混合操作来让这个物体看起来是半透明的。混合操作是高度可配置的,开发者可以选择开启/关闭混合功能。如果开启了,GPU会取出源颜色和目标颜色,将两种颜色进行混合。源颜色是指片元着色器得到的颜色值,而目标颜色则是已经存在于颜色缓冲区中的颜色值。
5.CPU与GPU如何并行工作
使用命令缓冲区,命令缓冲区包含了一个缓冲队列,CPU向队列添加命令,由GPU从队列读取命令,添加和读取的过程是相互独立的。命令缓冲区使得GPU和CPU可以相互独立的工作,当CPU需要渲染一些对象时,GPU就可以从命令缓冲区取出渲染命令并执行