Unity渲染优化中文翻译(一):定位渲染问题
最近有一点个人的时间,尝试一下自己翻译一下英文的 Optimizing graphics rendering in Unity Games,
这儿附上英文链接:
个人英文水平有限,unity图像学知识也是入门,希望通过这次翻译能增进自己的图形学知识,若有错误,欢迎各位大神指点,让我也学习进步,谢谢。
介绍
本文主要学习在Unity进行一帧的渲染的时候,观察到的场景背后的运行原理,在渲染的时候会有什么样性能问题发生以及如何解决这些渲染相关的问题。
在开始阅读这篇文章之前,首先需要知道对于渲染问题是没有万能的解决之法的。渲染的结果受到游戏中众多因素的影响,同时也极其依赖于游戏所运行的硬件条件和操作系统。最重要的一点,是要记住我们需要通过分析,实验和测试,严密的分析测试结果来解决渲染性能问题。
本文主要分析常见的渲染问题并提供相应问题的解决办法及其链接,并不能完全概括渲染的问题,所以本文主要旨在提供解决的思路并提供一些较为有效的查找办法的途径。
渲染的简单介绍
在开始本文之前,让我们快速的回顾一下在Unity的一帧渲染中发生的事情。理解下面的一些概念和关系对于解决渲染性能问题有较大的帮助。
注意:在全文中我们会使用"object"来代表游戏中需要被渲染的物体,任何带有渲染组件的物体都可以被称为object。
从最基本的角度看,渲染过程的组件可以分为:
. CPU,主要计算出需要被渲染的对象和渲染的方式;
. GPU,CPU将渲染指令发送给GPU
. GPU根据CPU的渲染指令进行渲染工作
本文接下来会详细介绍这几步流程,现在只需要熟悉这几个关键词汇并理解其在渲染过程中所扮演的角色。
渲染管道常常被这生动的用来描述渲染的过程,高效的渲染过程就是保持信息的流动。CPU在每帧的渲染过程中的工作主要包括:
. CPU检查场景中的object是否需要被渲染。一个object只有满足一定的条件才可以被渲染,例如它的部分模型处于相机的视角范围内 View frustrum。被剔除的object是不会被渲染的。
. CPU收集需要被渲染的object并将其排序为渲染指令(Draw calls)。一个DC主要包含一个网格的数据和其渲染方式,例如其中哪个贴图需要被使用。在通常情况下,使用相同的DC的objects会被合并,这种合并不同渲染objects的操作就是批处理(batching)。
. CPU对每个DC中的数据进行批处理打包,有时打包的结果有时更多的包含的是数据而不是DC,但是这对渲染影响不大,所以本文并不考虑这些情况。
对于每个包含DC的打包指令,CPU必须进行以下处理:
. CPU发送一个指令改变当前的渲染状态(render state)。这个指令叫做 SetPass call,主要用来告诉GPU下一个被渲染的网格的渲染设置,该指令也只有在下一个渲染网格的渲染设置和当前的设置不同的时候会被发送。
. CPU发送DC给GPU,DC指令主要操作GPU采用最近的SetPass Call 设置来对特定的网格进行渲染。
.在一些情况下,在一个batch中会有多个pass(shader中的一部分代码),如果一个pass中要求新的渲染状态(render state),那么CPU就会发送一个新的SetPass指令给GPU,然后重新发送DC指令。
与此同时,GPU需要进行如下操作:
. GPU根据指令的顺序处理渲染任务。
. 如果当前的任务是SetPass Call,那么更新当前的渲染状态。
. 如果当前任务为DC,GPU就渲染网格。 根据shader代码中的不同步骤进行渲染。该部分的渲染较为复杂,在此并不做深入阐述,但是了解shader中的 vertex shader有利于了解GPU是如何处理网格中的顶点数据,了解shader中的 fragment shader有利于了解GPU是如何绘制每个单独的像素点。
. 这个过程会重复的进行直到CPU中发送过来的渲染指令都被处理完。
在了解了Unity在进行一帧的渲染中的操作后,现在我们考虑在渲染中的一些问题。
渲染问题的分类
对于渲染,有一个关键点是:CPU和GPU必须在渲染的一帧中完成各种的任务,如果任何一个花费较长时间来完成,则会造成一帧的渲染延迟。
渲染的问题主要有两个基本的因素。第一因素是低效的渲染管道,如果在渲染管道过程中某个或者多个步骤消耗较长时间就会造成渲染管道的低效,从而中断数据流,这也被称为渲染瓶颈。第二个因素是渲染管道中数据过多,即使是最高效的渲染管道在每帧的渲染处理中也有数据量大小的限制。
如果渲染问题来自于CPU在计算渲染任务时耗时过长,则将其称为 CPU bound, 如果渲染问题来自于GPU渲染耗时过长,则将其称为 GPU bound。
了解定位渲染问题
在我们进行任何渲染改进之前,可以利用分析工具来了解定位造成渲染问题的原因。不同的问题有不同的解决办法,同时我们需要测量我们的改进结果。解决渲染性能问题是一个平衡的操作,提升一方面的性能会对另一方面的性能造成相反的效果。
我们将利用两种unity中的工具来定位渲染性能问题:Profiler window 和 Frame Debugger.
The Profiler window
利用profiler window 我们可以查看到游戏运行时各个方面的实时数据,包括内存使用,渲染管道和脚本的性能。
The Frame Debugger
利用Frame Debugger可以了解每帧的渲染操作及其详细的渲染信息,比如每个DC中渲染的是什么,每个DC的shader属性,GPU接收到的渲染指令顺序等。利用渲染信息可以帮助我们了解到游戏中的渲染情况从而提升游戏的性能。
查找造成渲染性能问题的原因
在我们尝试改进渲染问题的时候,我们必须确定游戏运行较慢的原因是由渲染问题造成,如果游戏运行较慢来自于游戏脚本运行复杂则优化渲染无济于事,可以通过此处来确定是否由于渲染造成游戏运行较慢。
一旦我们确定游戏运行较慢来自于渲染,则需要确定是由于CPU还是GPU,不同的问题有不同的解决办法,所以在解决问题前定位问题非常重要。
在定位渲染问题来自于CPU还是GPU后,下面详细介绍各自的解决办法,参看下一篇文章。