流水线
流水线系统中决定最后生产速度的是最慢的工序所需要的时间,该工序也是性能的bottleneck。理想情况下,把一个非流水线系统分成n个耗时相同的阶段,可以使整个系统的速度提升n倍。
渲染的概念流水线
1、渲染流水线的工作任务是从一个三维场景(一系列顶点数据、纹理等信息)出发,生成(渲染)一张二维图像。
2、渲染流程分为三个阶段:
Application Stage (输出渲染图元)→ Geometry Stage(输出屏幕空间的顶点信息) → Rasterizer Stage
Application Stage:
CPU 负责,需要准备场景数据、进行粗粒度剔除(culling ),设置每个模型的渲染状态,最后输出渲染图元(渲染所需的几何信息,可以是点、线、三角面等),此阶段的流水线化由开发者主导。
第一步:把数据加载到现存中。显卡对显存访问速度更快,且大多数显卡对于RAM没有直接访问的权利
第二步:设置渲染状态,决定网格是如何渲染的。例如使用哪个顶点/片元着色器、光源属性、材质等。
第三步:调用DrawCall 这个渲染指令,由CPU发送给GPU,GPU流水线(即几何阶段+光栅化阶段)会进行计算输出(渲染)。
Geometry Stage:
GPU 负责,分成更细的阶段,对输入的渲染图元进行逐顶点、逐多边形的操作,输出屏幕空间的二维顶点的坐标、深度值、着色等信息。
1、Vertex Shader :处理单个顶点,且顶点间相互独立,主要完成坐标变换(把顶点坐标从模型空间转换到齐次裁剪空间,输出后硬件做透视除法得到NDC【Normalized Device Coordinates】下坐标:,NDC中,OpenGL+Unity使用Z∈[-1,1],DirectX使用Z∈[0,1])和逐顶点光照,还可以输出后面阶段需要的数据,可改变顶点位置完成顶点动画。
2、Clipping: 将部分处于视野内的图元进行裁剪后与完全处于视野内的图元继续传递到下一个阶段。
3、Screen Mapping: 输入为NDC下范围处于立方体内部的的三维坐标 ,将图元的x和y转换到屏幕坐标系(Screen Coordinates),输出屏幕坐标系的xy+不被处理的z坐标构成窗口坐标系(Window Coordinates)传入Rasterizer Stage。
ps:屏幕坐标系的区别:OpenGL左下角为(0,0),DirectX左上角为(0,0)
Rasterizer Stage
GPU 负责,分成更细的阶段,主要是计算每个渲染图元覆盖了哪些像素,并且为这些像素计算颜色,最终绘制在屏幕上。对输入的逐顶点数据进行插值然后进行逐像素处理,产生屏幕上的像素,并渲染输出最后的图像。
1、Triangle Setup :计算三角网格表示数据的过程。
2、Triangle Traversal (Scan Conversion):检查每一个像素是否被一个三角网格所覆盖,如果被覆盖,就会生成一个fragment,一个fragment是包含很多状态的集合,例如屏幕坐标、深度信息等。
3、Fragemnt Shader :输入是上一个阶段对顶点信息插值得到的结果,输出一个或多个颜色值。该阶段可完成很多渲染内容,例如纹理采样,但存在一定的局限,即只可以影响单个fragment。
4、Per-Fragment Operations(OpenGL)/ Output-Merger(DirectX):决定fragment的可见性(深度测试Depth Test、模板测试Stencil Test等)、通过了所有测试以后,该fragment颜色值与颜色缓冲区中的颜色混合Blend。Stencil Test 可以用来渲染阴影、轮廓渲染等。Depth Test可以用来做透明效果
ps:模板测试和深度测试的区别在于,无论一个fragment是否通过模板测试,都可以修改模板缓冲区,而深度测试只允许通过的fragment修改,可通过开启深度写入来做到。这些测试之后的Blend操作也可以选择开启/关闭。一般为了提高性能,深度测试会被放到Fragment Shader之前,称为Early-Z 技术,但也可能产生与Fragment Shader操作中冲突的结果,现代GPU会提前判断该点冲突。为避免看到光栅化过程,采用双缓冲(Double Buffering)策略。渲染过程在后置缓冲(Back Buffer)中,完成后GPU交换后置缓冲和前置缓冲(Front Buffer)中的内容,以此保证图像的连续性。高级的着色语言:HLSL ( High Level Shading Language) / GLSL ( OpenGL Shading Language) / CG ( C for Graphic)