DrawInstance和完全不做合批情况下的性能差异

DrawInstance和完全不做合批情况下的性能差异

1)DrawInstance和完全不做合批情况下的性能差异
​2)UWA报告中检测出工程没有的资源
3)精灵设置九宫后,如何不在界面中显示出来
4)关于AssetBundle资源的卸载问题
5)Total Mono突然上涨的原因


这是第236篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间10分钟,认真读完必有收获。

UWA 问答社区:answer.uwa4d.com
UWA QQ群2:793972859(原群已满员)

Rendering

Q:我做了个测试,环境:Unity 2019.4.15 ,机型:小米5X,绘制1000个物体(顶点数>300,不动态合批),测试顺序是:Unity默认渲染(20 FPS)–>Update中通过Graphics.DrawInstance(16.5 FPS)–>通过CommandBuffer实现的DrawInstance(21.5 FPS),对于第二个测试DrawInstance性能反而降低了不太理解,有大佬帮忙解答吗?

图片和测试工程可通过以下链接下载:
链接:https://share.weiyun.com/ZFOlW1of
密码:ip37rr

A:1.Instancing耗时更高主要原因还是GPU压力比较大,见下面的测试案例:

测试1:1000个物体(顶点数88,关闭动态合批)

Default:子线程Camera.Render(14.59 ms)、Gfx.PresentFrame(3.94 ms)

Instancing:子线程Camera.Render(7.1 ms)、Gfx.PresentFrame(4.70 ms)

测试2:1000个物体(顶点数1278)

Default:子线程Camera.Render(15.02 ms)、Gfx.PresentFrame(9.01 ms)

Instancing:子线程Camera.Render(8.21 ms)、Gfx.PresentFrame(19.15 ms)

Instancing是能够明显降低CPU渲染(Camera.Render)耗时的,但GPU调用DrawInstanced()比Draw()的性能似乎差一些,导致CPU端等待耗时较高。所以Instancing总体帧率有所下降主要是GPU的压力较大导致的。

2.如下图Graphics.DrawMeshInstanced在Update中每帧调用存在脚本耗时明显DrawInstancing更高(在Update中准备相关DrawInstance参数),Demo渲染的是静态物体,使用CommandBuffer实现DrawInstancing可优化这部分耗时,同时在Update中的逻辑也会有New XXX[]数组这样的Mono堆内存频繁的分配,也会有GC影响(这部分影响较小)。

结论:Instancing可以降低CPU渲染耗时,但GPU API性能会有所降低,帧耗时还是受到CPU渲染耗时及GPU耗时的综合影响,不同的机型可能表现的会有所差异。

Instancing的使用:推荐绘制大量静态物体时使用CommandBuffer的实现,例如草海之类的。

感谢羽飞@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/60095ef310a17c6c2b09dc04


Texture

Q:请问一下:性能报告中,RGBA32的图片有一些在工程中没有,但是在报告中却体现,请教一下这些是哪里产生的?

A:截图中的Background、UIMask、UISprite是由UGUI中默认的UI元素引入的,如下图中的ScrollView:



UnityNormalMap这个是由于Shader中的纹理使用Bump作为默认的值,但是在材质球中又没有给这个纹理赋值导致的。对于这种空纹理的资源,在UWA本地资源检测中是可以检测出来的。

感谢Xuan@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/600a812910a17c6c2b09dc31


UGUI

Q:导入一张171*41的图片,设置完九宫信息后创建UI图片。然后设置图片宽高为0,并设置图片模式为Sliced。但是还是能看到图片显示出来了。个人感觉上是UV计算错误了。如果切换到Simple则图片正常不显示。请问大佬这是什么原理?

测试工程可在原问答下载(版本:Unity 2018.4.23)

A:这个和九宫格图片的实现原理有关,可以看看下面这个图片:

当你选择Sliced模式,他有一个最小的绘制区域,也就是四个角:1、3、7和9,必须绘制出来。当你设置的Rect大于1、3、7、9四个角组成的区域时,那么2和8则是在x方向进行缩放,y方向不变,而4和6则是在y方向缩放,x方向不变;而5则是x和y方向都会进行缩放。当你选择Simple模式,则是根据你设置的Rect范围决定的,如果Rect比原始尺寸大,那么就拉伸,反之则缩小;这也就是你可以不显示的原因。

感谢李星@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/60096dcc10a17c6c2b09dc0d


AssetBundle

Q1:公共资源public.ab做全局预加载,常驻内存。某特定资源A引用了public.ab里的一张大图纹理,以及另外一个a.ab里的资源。在没加载A时,public.ab即使常驻内存也不会实际将那张大图纹理实例化。

现在的问题是,当加载并用完A资源后,想把A彻底从内存中清理出去时,对a.ab进行Unload(true)可以把a.ab清理掉,但是public.ab里的那张大图,在不对public.ab进行Unload(true)的前提下,是没有任何其它办法能将它从内存中清掉吗?

A1:如果能拿到那张Texture的引用,可以尝试使用Resources.UnloadAsset

但个人认为既然是公共资源,说明有可能被很多地方引用到,应做好public.ab里面的资源都常驻内存的内存预算准备。否则,按照你例子中的说法,可能把这张大纹理单独拿出来会好一些。

感谢范君@UWA问答社区提供了回答

Q2:由于该大图纹理被多个UI预置体引用,因此放到了public.ab里,但这些UI预置体,在游戏大部分时间(比如挂机战斗时)不会打开,因此也是不需要用到的,故而想卸载。看来还是只能再拆分出一类不常驻内存的公共资源,来解决这类问题了?

A2:既然要作为公共资源,常驻内存,那么就是从App的开始到App的结束都是不会去卸载的。如果你想原来在公共资源里的小图只有特定场景下才会使用到,平时不用时想卸载,可以参考下这个运行时动态图集,动态将小图合并到常驻内存的图集中,不用时在动态剔除回收。

《Unity运行时动态图集的实现》

感谢Coyote@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/6007ee4010a17c6c2b09db6f


Mono

Q:现象:在Total Mono突然撑大的那几帧中,Used Mono并没有上涨,如图:


Used在50MB左右时,Total突然分配到140MB,这是为什么?

A:很有可能是一帧中分配了大量的堆内存,将Total撑大了,但本身的堆内存是可以GC掉的,所以Used并没有太大的变化。

该问答由UWA提供,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/6007f1b810a17c6c2b09db70

封面图来自网络


今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。

官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
UWA学堂:edu.uwa4d.com
官方技术QQ群:793972859(原群已满员)