123456819 发表于 2021-2-19 09:25

Unity基础:性能杀手Overdraw详解

有一个杀死了数千计的手机游戏GPU性能的问题:著名的Overdraw。你知道什么是OverDraw么,它正在对你做什么?
不要让OverDraw杀死你的游戏!
为此我们将学习了解以下内容。

了解什么是OverDraw,以及OverDraw如何破坏游戏GPU的性能(尤其是在移动设备和VR上)3种测量游戏OverDraw的技术减少Unity OverDraw的策略
目录
什么是Unity中的OverDraw?为什么Unity OverDraw会使游戏卡顿测量OverDraw的三种方法Unity:OverDraw可视化模式RenderDoc OverDraw分析(Example:森林)使用Compute Shader测量OverDrawSnapdragon ProfilerXcode
如何减少OverDraw减少不透明几何产生的OverDraw由于低效率的渲染策略产生的OverDraw由于Unity批处理而产生的OverDraw
减少透明渲染产生的OverDraw

1.什么是Unity中的OverDraw?

想象一下今天是星期一。
你终于在8:40,第四个闹钟响的时候清醒了过来。
你担心上班迟到,所以只有一点点时间将衣服穿上并且滚粗上班去了。
屋子外面天气很冷,
但是经验告诉你,听生气的老板咆哮比遭受体温过低要糟得多。
因此,你进入汽车并启动了发动机。
现在到9:00还差10分钟。如果你的数学不是体育老师教的,应该可以在5分钟内准时到达办公室并且时开始工作。
现在只有一个问题:挡风玻璃被冻结,你在车内看不到任何车外的东西。
最短也需要5分钟才能将挡风玻璃的冰冻去除。
时间还赶得上,窃喜中。。。
开车时,你注意到挡风玻璃起雾了。
这不可能,你想。
你以不可能的角度从座位上看挡风玻璃某些地方的小像素,这些像素尚未被遮挡。
当你开车时,你又发现挡风玻璃起雾了!!
擦,这下完蛋了。
在你现在的角度,你无法透过挡风玻璃的像素看到车外的景象。
雾越来越大了,你只能打开侧窗,把头伸出车外,才能看清路况,但是你还要想法子开车
你当然在驾驶学校没有学过这样的驾驶技术。
经过短暂理智的思考之后,你认为冒这样的风险不值得。
你认命了...
你以安全的方式进行了操作,但是迟到15了分钟才到达公司。
老板脸上的笑容说明了一切。你完蛋了。
…美好的星期一。
很严重的OverDraw
如果你不注意,进到车里时,你会遭受数次OverDraw。
雾蒙蒙的挡风玻璃可以称为OverDraw。它在你和你想要看到的场景(孩子们过马路)之间添加了中间的视觉效果层。
当你多次绘制同一像素(在一帧中)时,会发生OverDraw,想象一下,你的眼睛就是相机
第一个Draw Call绘制了在你面前的街道(场景)。第二个Draw Call绘制了正在穿马路的小孩子们(角色)。第三DrawCall绘制了有雾的挡风玻璃,它使驾驶很危险。最后一个DrawCall绘制了你所戴的混浊眼镜。
这里有四层OverDraw,类似于Unity渲染会发生的情况:渲染整个屏幕,该屏幕由数百万个像素组成。如果这些像素被绘制了一次以上(总是如此),那么就造成了OverDraw,导致GPU渲染压力增大。
这种情况最常见于透明几何体,因为首先绘制不透明世界,然后逐次将其与半透明对象混合(绘制)。
更糟糕的是:简单的后处理效果(例如 color grading)可能会对每个像素至少计算一次。由于它重画了屏幕上的每个像素,这直接增加了100%(1.0x)的OverDraw。
如果您的后期处理效果仅影响屏幕的左侧,因为它涉及到屏幕像素的一半,它将增加一半的OverDraw程度(0.50x)。
等等。
可悲的是,导致你上班迟到的OverDraw也会导致GPU每帧处理理时间增加。
OverDraw 可能是导致 60 fps或30 fps(或更差)渲染帧率差距的原因。
Unity OverDraw是VR和移动游戏(包括Switch,PSVR和Oculus Quest)的最大性能问题之一。
你知道为什么 OverDraw是你对GPU所能做的最坏的事情之一么?
GPU OverDraw会破坏你的一整天
2.为什么OverDraw会蚕食Unity渲染性能

渲染的目的是将图像(以非常快的速度)放置到屏幕上。这是通过特定步骤(Draw Calls)来完成场景渲染。
其中某些渲染步骤并不是在屏幕中发生,而是在称为帧缓冲区的中间区域中发生。
帧缓冲区就像画家用来画画的一块空画布。
如果你想象你是画家,那么……每个笔画都会花一些时间,尤其是当他们不得不更改绘画时使用的颜色时。
在图形编程方面,该帧缓冲区是一种特殊的纹理。由于许多原因,绘制到帧缓冲区很昂贵。
每次绘制像素时,都需要从该缓冲区传输出和传入关键信息。
此绘制操作会占用内存带宽。
OverDraw会增加游戏渲染消耗的内存带宽。
你猜怎么着?在TBR(tile-based rendering)的渲染架构上,这种带宽消耗尤其糟糕,碰巧是所有移动平台都是TBR的渲染架构。
OverDraw在VR游戏上尤为棘手,有两个原因:
屏幕分辨率:每帧绘制的像素数量已经很高。与传统游戏相比,VR游戏的性能预算要低得多,因为需要达到120Hz才可以避免晕眩,传统游戏只需要60fps就够了。
我希望你已经有一些OverDraw的概念了,接下去我将向你展示测量OverDraw的不同方法。
3.在Unity中测量OverDraw的三种方法

3.1 Unity:OverDraw可视化模式

了解场景中OverDraw的最简单,最快的方法可能是使用Unity内置的OverDraw视图模式。
在场景视图的右上角,单击可视化类型下拉菜单。在那里,选择OverDraw。
你将看到类似于下面的可视化效果。
Unity Overdraw:编辑器可视化
最深的色彩表示具有最高OverDraw屏幕区域。你会发现某些最强烈的区域很可能与粒子效果有关。
如果你看到一个地区有大量的OverDraw,请分析它是由什么原因造成的。很可能是由于渲染半透明元素造成的。
→警告!Unity内置的透支可视化在技术上非常不正确。
Unity使用不带Z-Write的附加着色器来显示它,因此你将看到的大多数不透明对象上的OverDraw都是假的。
Unity没有考虑到渲染管线所做的Z-Test,正常情况下,很多不透明元素的渲染会被Z-Test剔除掉。
但是,只要你知道它的局限性,它仍然是一个有用的工具。
幸运的是,你和我有更准确的工具可以使用。
如果您使用的是HDRP 7.1+(高清渲染管线),那么你会很高兴听到有增强的OverDraw可视化工具可以使用。你可以通过Window → Render Pipeline → Render Pipeline Debug → Rendering来访问它,并将Fullscreen Debug Mode设置为“ TransparencyOverdraw ”。
Unity HDRP:渲染调试窗口
以下是此渲染模式在示例UI上的外观:
Unity HDRP渲染:OverDraw调试示例
让我们检视下一个工具。
3.2 使用RenderDoc分析OverDraw(例子:The Forest)

以下是The Forest的起始场景的屏幕截图。它是一款类似于电视节目《迷失》题材的生存游戏。
在这里,快速预览一下,因为我们将对其进行分析。
森林:飞机硬着陆(截取其中一帧)
该场景有多复杂的OverDraw?
好吧,由于它主要取决于所涉及的渲染顺序和着色器,所以你无法通过查看屏幕截图来了解。
但是我们可以使用RenderDoc,这是一个免费的GPU图形调试器,可以让我们在图形调试上节约很多时间。
优势?开箱即用的内置Unity集成。只要安装RenderDoc就可以了。
在此示例中,我使用RenderDoc捕获与上一张图像相同的帧。然后,我遍历其draw calls,将 overlay mode切换为Quad Overdraw(Draw)来分析它们产生的OverDraw,如下所示。
Unity RenderDoc Overlay:OverDraw
下面GIF动画由粉红色区域表示通过绘制飞机底盘的一部分而产生的OverDraw。
The Forest:不透明物体产生的OverDraw示例
之所以会发生这种OverDraw,是因为我们先绘制了地形的像素,之后才被飞机框架覆盖。这是带宽的浪费!首先进行飞机框架的绘制会更高效,因为Z-Test会跳过随后绘制地形的像素。
这种情况下OverDraw量很大,覆盖了整个屏幕的30%。
哦不, 你无法在移动设备上负担得起这种开销。
接下去我要指出的The Forest中的最后一个示例是UI重绘。
在Unity中,UI最通常在渲染管道的末端绘制。这样,这样可以确保它显示在所有事物之上。
在这里,他看起来这不是主要的问题,因为它仅覆盖屏幕的一小块区域。但是,如果你打开全屏地图或背包界面,会发生什么呢?
是的,你懂得。
森林:UI OverDraw示例
RenderDoc是每个(图形/性能)程序员都应该拥有的一个非常有用的工具。
要了解有关此工具的更多信息,请访问有关Unity RenderDoc集成的文章。注意:帖子很旧,我的写作风格很烂。仍然是很好的参考信息。
到目前为止,这已经是相当生动的图形冒险了。 蛮好玩的。
但这还不够。
你应该成为数字驱动的人。最终关键是可让你用数字比较性能指标。
下一个策略将帮助你在追求性能专业知识的过程中变得更加以数字为导向。
3.3 使用Compute Shader量化OverDraw

在2017年的Unite演讲中,我遇到了一家来自名为Nordeus游戏开发公司的出色工程师。
由于Unite大会上,对于技术涉及的主题通常很浅,因此我经常对Unite的话题感到无聊。
但这次不一样。
演讲的很大一部分是关于Unity GPU性能的,你可以想象到我从一开始就认真地做笔记。你可能实际上在视频中的某个地方看到了我(这并不难找,那时候我非常瘦,像其它程序员一样)。
一位工程师介绍了他们开发的一种工具,该工具可以用大量数字分析量化场景的OverDraw。
从字面上看,该工具为你提供了场景每时每刻都有的OverDraw数值。这是一个非常方便的数字。
自从那次演讲以来,我每年都会和这位工程师见面,我们总是在一些简短的咖啡时间分享关于性能的精彩对话。比如GDC,Unite,等大会上的内容。
您可以在GitHub上使用Nordeus的OverDraw工具,并且可以在YouTube上观看该视频。
该工具是我用来分析和优化每个游戏场景中OverDraw的主要资源之一。
每当我看到超过3倍的OverDraw的图形时,我都会迅速进入该场景并开始优化工作。
Unity Overdraw工具:Nordeus的实现
我可能会就如何使用Nordeus的OverDraw工具进行更深入的介绍,但是你需要注意以下几点:
该工具可以在编辑器中直接使用DirectX正常工作。如果想要使它适用于OpenGL,可能需要修改一些代码,但目前我还无法共享代码(需要的话评论区下留言)。争取只有1倍OverDraw,尽可能避免2倍OverDraw,当然不要超过3倍(这个根据项目的兼容性和适配目标来,现在手机机能越来越强,为了效果堆各种后处理,避免不了OverDraw会上去)。
如果你很关注性能优化这块,那么这是可以集成到项目中的宝贵的资产。
3.4 Snapdragon Profiler

如果你手头有晓龙cpu手机,市场上几乎所有的Android手机(华为除外),那么这就是你的幸运日。
这是一个可以让你从底层分析游戏性能的工具,其中就包含了OverDraw。
但是我不是这个工具的忠实拥护者-它非常不稳定,你可能需要花费数天才能获得有用的东西,但是在特定情况下它非常有价值。
以下就是分析OverDraw数据的截图
Unity + Snapdragon Profiler:OverDraw统计
3.5 Xcode

Xcode是当世代最强的渲染分析工具,有条件的话尽量用ios设备+Xcode分析渲染性能,这里主要讲OverDraw,先简单略过,有兴趣的小伙伴们可以去搜索相关资料,如果需要详细出一期教学,可以在评论区下留言。
4.如何减少OverDraw

既然现在你已经知道OverDraw对游戏有何影响,那么问题就变成了:我该如何处理它?
另外,还有一个重要的问题将导致相同的答案:如何防止OverDraw?
在本章中,我将与你分享我的最佳建议。
4.1 减少不透明OverDraw

与流行的游戏开发理念相反,渲染不透明的几何形状可能会导致大量OverDraw。
不透明几何产生的OverDraw相比透明几何产生的OverDraw开销更低,因为不透明渲染只是替换像素。透明渲染通常会与Alpha Blend一起使用,这对于移动设备来说有更加昂贵。
但是,不要低估不透明OverDraw产生的性能开销。浪费内存带宽的开销依然很昂贵。
Unity会尽最大努力从近到远渲染不透明元素。这就是说,我们首先渲染距离摄像机更近的元素,以便使用Z-Test剔除被遮挡的物体的像素。
该排序基于相机与每个对象的边界框中心之间的距离。
这种排序非常有利于GPU性能。
但是,在某些情况下,会导致渲染队列排序混乱,这会使OverDraw增加。
你知道是什么时候吗?
由于低效率的渲染策略,导致GPU OverDraw

事情是这样的:某些网格肯定是麻烦制造者。
假设你位于巨大的倒球面的中心,就像力场效应一样。
好吧,你到球面的距离是多少?
它接近于零,因为球体的中心恰好是摄影机所在的位置,这意味着将先渲染该球体,即使可能会在其前面绘制一些对象。这将导致OverDraw。
这就是为什么在Unity中应该把渲染天空盒放在渲染不透明几何图形之后的原因。首先渲染天空盒会产生大量OverDraw。
天空球示例
那如何解决这个问题呢?
你可以将对象拆分为较小的子对象,以便Unity可以获取更准确的原点来更有效地对绘图调用进行排序。
相交的几何会发生另一个问题。在这里,透支变得不可预测,因为不能在同一次绘制调用中保证像素渲染顺序。
自相交几何(不建议使用)
对于自相交的几何,还可以以明智的方式将其拆分为不同的几何块。在上一个屏幕截图的情况下,您可以将其完全分成四个平面,因此基于距离的排序将正确地完成其工作(请注意,这个操作将支付更多的Draw Call,以减少OverDraw,这个需要再实际项目中做平衡,看是CPU有余量还是GPU有余量,这里只作为例子介绍减少OverDraw的策略)。
让我们看看其他情况。
Unity Batching导致GPU OverDraw增加

我喜欢批处理。而且你也应该喜欢。
批处理可以帮助你我减少渲染线程的CPU负载,这在未经优化的游戏中通常是一个巨大的瓶颈(CPU瓶颈)。它能够将多个绘制调用合并在一起提交给GPU。
但是,合并绘制调用意味着Unity将不再能够对其按原有的顺序进行排序,因为现在已经合为一体。这可能会导致严重的OverDraw。
这在所有类型的批处理中都会发生:静态,动态和GPU Instance。通常发生的环境不是确定性的,这会使你的性能分析工作更加困难。
可悲的是,常见的解决方案是禁用麻烦对象的批处理(或者按区域手动来进行批合)。
另一种解决方案是通过将渲染队列更改为Geometry-1,Geometry + 1等来手动设置Unity渲染顺序。这几乎可以完全控制渲染顺序,但这带来了责任/风险(常见的是把地表、天空盒进行延后渲染)。使用Standard材质要求检查器处于调试模式,如下所示。
Unity标准着色器:材质的渲染队列
4.2 减少透明渲染的OverDraw

半透明对象是导致OverDraw最常见的元凶
由透明度引起的OverDraw对性能特别不利,因为渲染通常伴随Alpha Blend,这需要额外的读取和算术运算。
更糟糕的是,透明材质通常不会写入Z-buffer,因此最终会写入更多无法丢弃的像素。
你要做的是减少绘制的透明像素的数量及其成本。
减少渲染的透明层的数量。减小透明几何图形所需的屏幕尺寸您可以按比例缩小透明对象的(屏幕)大小。尽最大可能从精灵中删除100%透明纹理像素。制作紧密的网格,以减少完全透明的区域。
Unity OverDraw:透明层叠加过多
Unity:全屏OverDraw
Unity UI通常会导致OverDraw,因为系统仅支持全四方渲染。将可绘制的UI元素彼此堆叠非常容易。这些渲染为完整的四边形而不是紧密的网格。
但是,精灵渲染器支持绘图网格,这些网格可以更准确地表示精灵的不透明部分,以减少过度绘制。
示例如下:
Unity Sprite vs.图像OverDraw
用精灵制作紧密的网格将大大降低OverDraw水平:
Full-Quad vs Tight-Mesh Overdraw
你可以尝试的一种先进技术是在几何渲染队列之前以不透明模式绘制部分UI。如果写入Z-Buffer,则不会渲染其后面的所有像素。当然,这对于所有类型的UI控件来说未必是一件好事。
粒子系统也擅长在透明层上创建OverDraw。问题在于它们经常将粒子堆叠在一起,因此GPU必须在混乱区域渲染太多像素。
最后,我将在此处包括后处理效果,尽量把他们合并计算,权衡使用。
根据后期处理效果的实现方式,最终可能会引入一个新层,即每个引入的效果会造成100%OverDraw。这对于移动GPU来说非常不利。(话越少事儿越大)
注意:如果您无法进一步减少OverDraw,请尝试通过additive而不是Alpha Blend来降低其成本。Additive blending比移动设备上的Alpha Blend要廉价得多。
5. 获取性能优化备忘单

哇,这是一个全部干货的文章。
如果你不熟悉性能优化,那么可能一定要消化很多东西。
即使不是,你最终也可能会忘记这篇文章的重点。
为了进一步帮助你,我准备了一份备忘单,其中包含摘要,资源和清单,你可在游戏开发过程中随时取用。
随身携带它,你可以随时随地翻出来阅读,立刻获取


原文作者
Ruben Torres (The Gamedev Guru)
原文地址:https://thegamedev.guru/unity-gpu-performance/overdraw-optimization/
本文翻译由作者授权

今早我梦醒了坎 发表于 2021-2-19 09:33

666,学习了

李志敏 发表于 2021-2-19 09:38

属于系统和资源策划必备知识了

白云追月素 发表于 2021-2-19 09:38

这收藏点赞数量就很真实[捂脸]

123456811 发表于 2021-2-19 09:46

干活满满

我爱萨其马虞co 发表于 2021-2-19 09:47

看机会不,腾讯的引擎组ue4 base深圳

冀苍鸾 发表于 2021-2-19 09:55

感谢!我的base在上海啦[爱]

掌舵的鱼1987 发表于 2021-2-19 09:58

Mark

哈哈SE7 发表于 2021-2-19 10:01

很不错,三连一波
页: [1]
查看完整版本: Unity基础:性能杀手Overdraw详解