渲染流水线:
应用阶段(CPU):输出渲染所需的几何信息,即渲染图元(Rendering Primitives)
几何阶段(GPU):把顶点坐标变换到屏幕空间中,再交给光栅器处理
光栅化阶段(GPU):决定每个渲染图元中的哪些像素应该被绘制在屏幕上
应用阶段:CPU与GPU的通信
- 把数据加载到显存中
- 设置渲染状态
- 调用DrawCall
把数据加载到显存中:渲染所需的数据从硬盘HDD中加载到系统内存RAM中,然后网格和纹理等数据加载到显存VRAM中
设置渲染状态:定义场景中的网格是怎样被渲染的,使用哪个顶点着色器/片元着色器、光源属性、材质等
调用DrawCall:CPU告诉GPU哪些图元应该被渲染
GPU流水线:
顶点着色器
Vertex Shader
:完全可编程,用于顶点的空间变换,顶点着色等
曲面细分着色器Tessellation Shader
:可选,用于细分图元
几何着色器Geometry Shader
:可选,用于逐图元(per-primitive)的着色操作,或者用于产生更多的图元
裁剪Clipping
:可配置,将不在摄像机范围内的顶点裁剪掉,并剔除某些三角图元的面片
屏幕映射Screen Mapping
:可配置/编程,将每个图元的坐标转换到屏幕坐标中
三角形设置
Triangle Setup
和三角形遍历Triangle Traversal是固定函数(Fixed Function)的阶段
片元着色器Fragment Shader
:完全可编程的,执行逐片元的着色操作
逐片元操作Per-Fragment Operations
:执行很多重要的操作,如修改颜色、深度缓冲、进行混合等
顶点着色器:Vertex Shader
- 坐标变换
- 逐顶点光照
- 输出后续阶段的数据
这意味着:输入进来的每一个顶点都会调用一次顶点着色器,顶点着色器无法创建或者销毁任何一个顶点,而且无法得到顶点与顶点之间的关系
坐标变换:
顶点着色器这一步操作主要是改变顶点的位置,例如模拟水面波动,但一个最基本的顶点着色器必须有的功能是:把顶点坐标从模型空间转换到齐次裁剪空间
o.pos = mul (UNITY_MVP, v.position )
再由硬件做透视除法之后,就可以得到归一化的设备坐标NDC-Normalized Device Coordinates
裁剪:
一个图元与摄像机的关系:
- 完全在视野内
- 部分在视野内
- 完全在视野外
完全在视野内的图元传给下一个流水线阶段,完全在视野外的不会继续向下传递,而部分在视野外的需要执行裁剪处理
屏幕映射:
将三维空间的坐标转化到屏幕的二维空间内,即将每个图元的x&y
坐标转化到屏幕坐标系下,然后屏幕坐标系和Z
一起构成了窗口坐标系传递到光栅化阶段
屏幕坐标系差异问题:OpenGL的屏幕最小值为左下角,DirectX的屏幕最小值为左上角
三角形设置:(进入光栅化阶段)
几何阶段的输出信息为:屏幕坐标系下的顶点位置以及额外信息,如深度值(z坐标)、法线方向、视角方向等
光栅化阶段的目标:计算每个图元覆盖了哪些像素,以及计算出这些像素的颜色
三角形设置会计算光栅化一个三角网格所需的信息
三角形遍历:
检查每个像素是否被一个三角网格覆盖,如果被覆盖的话,就会生成一个片元(Fragment),这样的过程也被称为扫描变换(Scan Conversion)
这一步的输出信息为:片元序列
注意:一个片元并不是真正意义上的像素,而是包含了许多状态的集合,这些状态用来计算每个像素的最终颜色。这些状态包括了:屏幕坐标、深度信息、法线、纹理坐标等
片元着色器:Fragment Shader
- 输入:上一个阶段对顶点信息进行插值得到的结果
- 输出:一个或多个颜色值
纹理采样:在顶点着色器阶段输出每个顶点对应的纹理坐标,然后经过光栅化对三角形的三个顶点的纹理坐标进行插值后,就可以得到其覆盖的片元的纹理坐标
逐片元操作:渲染流水线的最后一步
主要任务:
- 决定每个片元的可见性,进行很多测试:深度测试、模板测试等
- 如果一个片元通过了所有测试,就需要把这个片元的颜色值和已经存储颜色缓冲区内的颜色进行混合
深度测试的实现过程:
模板测试的实现过程:
混合操作:
如果没有开启混合操作,片元的颜色会直接覆盖掉缓冲区内的颜色,这会导致得不到透明效果,如果开启混合操作,GPU会将源颜色和目标颜色进行混合。