对于需要渲染的每一帧,CPU 将处理如下工作:
1.检查场景中所有物体,判断其是否需要被渲染。物体需要是否需要被渲染要满足一系列的条件,例如其是否在摄像机的视锥体中等。不会被渲染的物体被称为被剔除(culled)。
2.收集并排序所有需要渲染的物体相关信息并整理为通常所说的draw calls命令。一个draw call 包含了一个网格(mesh) 数据以及如何对其进行渲染的数据。例如,将会需要使用哪个纹理(texture)等等。在某些情况下,使用同一组设置信息的物体可能被组合起来成为一个draw call。将不同物体的数据合并为一个draw call 的过程称为batching。
3.为每一个draw call 创建一个通常所说的“批次”(batch)的数据包。Batch 中有时候可能包含draw call 之外的数据。
对于每个包含了draw call 的batch,CPU 将继续如下工作:
1.CPU可能会发送一些命令用于变更GPU 一系列渲染相关的变量,这些变量被统称为渲染状态(render state),这些命令本身就是通常所说的SetPass call。一个SetPass call 告知GPU 哪些设置将被用于渲染下一个网格。仅当下一个需要被渲染的网格需要变更渲染状态的时候才需要发送。
2.CPU 发送draw call 给GPU。Draw call 指示GPU 使用最近发送的SetPass Call 所提供的设置来渲染特定的网格。
3.在有些情况下,一个batch 可能需要多于一个的pass。Pass 是着色器(shader)代码中的一节,一个新的pass 需要对render state 进行变更。对于batch 中的每一个pass,CPU 将发送一个新的SetPass call 并且再次发送draw call。
GPU 在渲染流程中主要做如下工作:
1.按照CPU 的发送顺序处理渲染任务。
2.如果当前的任务是个SetPass call,GPU 更新render state。
3.如果当前的任务是个draw call,GPU 渲染该mesh。此过程按照shader 代码的不同段落分步有序进行,此过程较为复杂,简单来说,其中一段称为顶点着色器(vertex shader)的代码告知GPU 如何处理网格的顶点,另一段称为片段着色器(fragment shader)的代码告知GPU 如何绘制每一个像素。
4.重复上述工作直至CPU 下发的所有任务均被GPU 处理完毕。
在Unity 的渲染进程中包含三种类型的线程:
1.main thread:绝大多数CPU 任务在main thread 中完成,包括一些渲染任务。
2.render thread:用于向GPU 发送命令的特殊线程。
3.worker thread:每个worker thread 用于完成一个独立的任务,如culling 等。
注:并非所有平台都支持多线程渲染,目前WebGL 还不支持这个特性。