Unity渲染流程概述

本篇的任务是回答:在Untiy的渲染流程中CPU和GPU分别做了什么。

渲染到设备屏幕显示的每一帧的画面,都经历了这样的加工过程:cpu>gpu>screen

CPU的工作流程:

  1. 准备好需要被渲染的对象。也就是哪些物体需要被渲染,哪些物体需要被剔除(culled),剔除的常用方式包括视锥体剔除和遮挡剔除,并对需要渲染的对象进行排序。
  2. 设置每个对象的渲染状态。渲染状态包括所使用的着色器、光源、材质等。这个过程就是SetPass Call。
  3. 发送DrawCall。当给定一个DrawCall时,GPU会根据渲染状态和输入的顶点数据进行计算。

Unity的渲染顺序可以简单的理解为是从近到远(实际上要复杂的多,--渲染顺序超链接--)。根据渲染对象的排序,会为每一个渲染对象的每一个材质,生成一个渲染批次batch。在不考虑动态批处理和静态批处理的情况下,总的batch量就是每个渲染对象所包含的材质的和。但是因为存在动态/静态批处理的情况,所以实际产生的batch数量要小于前面计算的总和。

SetPass call 和Draw call作为渲染命令队列的组成内容,担负着不同的任务。可以这样理解,SetPass call是准备工作的一部分,而draw call则是最终的渲染调用,SetPass call通知GPU用于下一个网格渲染的设置,仅当下一个需要渲染的网格需要变更渲染状态时,才会产生SetPass call。所以,SetPass call和Draw call虽然是相伴产生的,但是两者却不一定对等。在某些情况下,一个batch可能会用到多个pass,比如mesh的反向描边。对于不同的pass,CPU将发送新的SetPass call 和Draw call。

通常来说在优化时我们关注的是DrawCall,但也有不同的声音说,SetPass call更有意义。我觉得用哪个做分析从优化角度来说,差别不大。他们传递的都是指令和地址,真正耗时的是执行绘制阶段。并且两者的产生也基本是相伴的。

GPU的工作流程:

Unity渲染流程概述

其中最为熟悉的莫过于顶点着色器和片元着色器。顶点着色器的输入来自于CPU,CPU输入的每个顶点都会执行一次顶点着色器,顶点着色器本身无法创建和销毁顶点,并且无法得到顶点与顶点之间的关系。正因为这样的独立关系,GPU可以利用自身的特性进行并行运算,所以顶点着色器的运算速度非常快。

最常用的裁剪设置是CULL OFF/BACK/FRONT,分别是不剔除/背面剔除/正面剔除。这里的正反面与摄像机没有一分钱的关系,而是通过法线方向决定的。

这里注意一点,虽然屏幕映射是玩家不可配置和编程的,但是屏幕分辨率确实玩家可以设置的,较小的屏幕分辨率对光栅化阶段是有非常重要的优化效果的。

最常用的逐片元操作设置包括ZTest、ZWrite、Blend。