第二章 渲染流水线
2.1概述
渲染流水线的任务:
由一个三维场景生成一张二维图像。
渲染流程的3个阶段:
应用阶段 (Application Stage)> 几何阶段(Geometry Stage)、光栅化阶段(Rasterizer Stage)。
- 应用阶段
这个阶段由应用主导,因此通常由CPU负责实现。
在这一阶段中,开发者有3个主要任务:首先,准备好场景数据。其次,做一个粗粒度剔除(culling)工作;最后,需要设置好每个模型的渲染状态,如使用的材质(漫反射颜色、高光反射颜色)、使用的纹理、使用的Shader等。 - 几何阶段
几何阶段用于处理所有和要绘制的几何相关的事情。这一阶段通常在GPU上进行。
几何阶段的一个重要任务就是把顶点坐标变换到屏幕空间中,再交给光栅器进行处理。通过对输入的渲染图元进行多步处理后,这一阶段将会输出屏幕空间的二维顶点坐标、每个顶点对应的深度值、着色等相关信息,并传递给下一个阶段。 - 光栅化阶段
这一阶段将会使用上个阶段传递的数据来产生屏幕上的像素,并渲染出最终的图像。这一阶段也是在GPU上运行。光栅化的任务主要是决定每个渲染图元中的哪些像素应该被绘制在屏幕上。它需要对上一个阶段得到的逐顶点数据(例如纹理坐标、顶点颜色等)进行插值,然后再进行逐像素处理。
2.2CPU和GPU之间的通信
渲染流水线的起点是CPU,即应用阶段。应用阶段大致可分为3个阶段:
(1)把数据加载到显存中。
(2)设置渲染状态。
(3)调用Draw Call
2.2.1设置渲染状态
渲染状态定义了场景中的网格是怎样被渲染的。 例如,使用哪个顶点着色器(Vertex Shader) /片元着色器(Fragment Shader)光源属性、材质等。
在准备好上述所有工作后,CPU就需要调用一个渲染命令Draw Call来告诉GPU已经准备好数据,可以开始渲染。
2.2.2调用Draw Call
Draw Call是一个命令,它 的发起方是CPU,接收方是GPU。
当给定了一个Draw Call时,GPU就会根据渲染状态(例如材质、纹理、着色器等)和所有输入的顶点数据来进行计算,最终输出成屏幕上显示的的像素。而这个计算过程,就是GPU流水线。
2.3GPU流水线
当GPU从CPU那里得到渲染命令后,就会进行一系列流水线操作,最终把图元渲染到屏幕上。
2.3.1概述
几何阶段和光栅化阶段,开发者无法拥有绝对的控制权,其实现的载体是GPU。
GPU的渲染流水线接收顶点数据作为输入。这些顶点数据是由应用阶段加载到显存中,再由Draw Call指定的。这些数据随后被传递给顶点着色器。
顶点着色器(Vertex Shader)是完全可编程的,它通常用于实现顶点的空间变换、顶点着色等功能。
裁剪(Clipping)阶段是可配置的。
屏幕映射(Screen Mapping)这一阶段是不可配置和编程的,它负责把每个图元的坐标转换到屏幕坐标系中。
片元着色器(Fragment Shader)则是完全可编程的,它用于实现逐片元(Per・Fragment)的着色操作。
几何阶段
2.3.2顶点着色器
顶点着色器(Vertex Shader)是流水线的第一个阶段,它的输入来自于CPU。
顶点着色器需要完成的工作主要有:坐标变换和逐顶点光照,还可以输出后续阶段所需的数据。
顶点着色器必须完成的一个工作是,把顶点坐标从模型空间转换到齐次裁剪空间。
2.3.3裁剪
2.3.4屏幕映射
屏幕映射(ScreenMapping)的任务是把每个图元的x和y坐标转换到屏幕坐标系(Screen Coordinates)下。
屏幕坐标系和Z坐标一起构成了一个坐标系,叫做窗口坐标系(Window Coordinates)。这些值会一起被传递到光栅化阶段。
OpenGL中,屏幕左下角为最小坐标值,DirectX中,屏幕左上角为最小坐标值。
光栅化阶段
2.3.5三角形设置
光栅化的第一个流水线阶段是三角形设置(Triangle Setup)。这个阶段会计算光栅化一个三角网格所需的信息。具体来说,上一个阶段输出的都是三角网格的顶点。但如果要得到整个三角网格对像素的覆盖情况,我们就必须计算每条边上的像素坐标。这样一个计算三角网格表示数据的过程就叫做三角形设置。它的输出是为了给下一个阶段做准备。
2.3.6三角形遍历
三角形遍历(Triangle Traversal)阶段将会检查每个像素是否被一个三角网格所覆盖。如果 被覆盖的话,就会生成一个片元(fragment)。这一步的输出就是得到一个片元序列。
2.3.7片元着色器
前面的光栅化阶段实际上并不会影响屏幕上每个像素的颜色值,而是会产生一系列的数据信息,用来表述一个三角网格是怎样覆盖每个像素的。
片元着色器的输入是上一个阶段对顶点信息插值得到的结果。
为了在片元着色器中进行纹理采样,通常会在顶点着色器阶段输出每个顶点对应的纹理坐标,然后经过光栅化阶段对三角网格的3个顶点对应的纹理坐标进行插值后,就可以得到其覆盖的片元的纹理坐标了。
2.3.8逐片元操作
这一阶段的主要任务:
(1)决定每个片元的可见性。
(2)如果一个片元通过了所有的测试,就需要把这个片元的颜色值和已经存储在颜色缓冲区中的颜色进行合并。
片元 一► 模板测试 一►深度测试 一►混合 一►颜色缓冲区
模板测试通常用于限制渲染的区域。
对于不透明物体,开发者可以关闭混合(Blend)操作。这样片元着色器计算得到的颜色值就会直接覆盖掉颜色缓冲区中的像素值。但对于半透明物体,就需要使用混合操作来让这个物体看起来是透明的。
2.4问题
如何减少Draw Call?
使用批处理方法。利用批处理,CPU在RAM把多个网格合并成一个更大的网格,再发送给GPU
在游戏开发过程中,为了减少Draw Call的开销,有两点需要注意:
(1)避免使用大量很小的网格。当不可避免地需要使用很小的网格结构时,考虑是否可以合并它们。
(2)避免使用过多的材质。尽量在不同的网格之间共用同一个材质。