材质和纹理的开销是如何相互影响的?

材质和纹理的开销是如何相互影响的?

这是第105篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间15分钟,认真读完必有收获。文末,我们的互动话题是:.net 4.6是否值得尝鲜?

UWA 问答社区:answer.uwa4d.com
UWA QQ群:465082844(仅限技术交流)


制作

Q1:请教一个问题,我们项目中有一种粒子系统需要不断地修改发射点,用worldspace模式确实可以达到一定的效果,但是目前需要在一帧里从若干个位置同时发射粒子,用多个相同的Particle System确实可以达到目的,但总觉得有些浪费,容易造成频繁的创建和销毁,如果都缓存的话总数可能就会很大了,不清楚有没有可能用一个Particle System来实现这个效果?

可以参考这个文档:
https://docs.unity3d.com/ScriptReference/ParticleSystem.Emit.html
通过调用ParticleSystem的Emit方法来发射粒子,可以在一帧里用不同的EmitParams进行多次调用Emit。这样的话,粒子系统本身就不用移动了,只是每次Emit的位置参数不同。

感谢zZ@UWA社区提供了回答,欢迎大家转至社区进行进一步交流:

https://answer.uwa4d.com/question/5abde6cd425802635474fbb1


资源管理

Q2:情景1:一张512x256的纹理。情景2:两张256x256的纹理。请问以上哪个情景消耗会更大呢?

进一步再说,一个同样的角色,情景1:一个材质球,一张512x256的纹理,情景2:两个材质球,各256x256的纹理,这种情况下又是哪个情景消耗更大呢?判断依据和原理是什么呢?

UWA:就内存方面,设置相同的情况下,二者应该是一致的(某些需要长宽相等的压缩格式除外)。

在CPU开销方面,那么二者基本上也可能是差异很小的。如果是一个材质,一张和两张的区别在于采样次数。一张纹理会减少一次纹理的绑定开销,理论上减小的耗时开销是在ns级别的,所以在绝大多数实际情况下CPU端的差异都可以忽略不计;如果是两个材质,影响的因素就会多了,可能会造成更多的Draw Call、更多的RenderState切换等等,这就是为什么要采用Atlas Packing的优化原因。

至于GPU上的开销,多一张纹理的Shader采样肯定要多一些计算,所以Shader Instruction和Cycles肯定也会更多一些。但是否真的是会带来更大的实际开销呢?不一定,因为GPU压力不光是要看一个Shader的Instruction,同时还要看Runtime到底有多少像素是通过这个Shader来渲染的,如果本身占比很小,那么多一次采样和少一次采样,在实际情况下没啥区别。

该回答由UWA提供,欢迎大家转至社区进行进一步交流:
https://answer.uwa4d.com/question/5abdca59910222635366dc77


渲染

Q3:我想渲染一个低分辨率的DepthTexture,有什么比较方便的做法吗?

一种方式是自己创建一个低分辨率的RenderTexture,然后通过Shader Replacement来渲染一个DepthTexture(Shader可以参考Unity的ShadowCaster的实现)。

还有一种是通过_LastCameraDepthTexture来访问其他的低分辨率相机(如果有的话)渲染出来的DepthTexture。

感谢zZ@UWA社区提供了回答,欢迎大家转至社区进行进一步交流:

https://answer.uwa4d.com/question/5abde736910222635366dc78


渲染

Q4:我想了解下Unity中物体接受灯光、产生阴影、接受阴影的性能开销情况。之所以这么问,是想看看Unity中的以上三种的性能开销。另外,在移动端是否有开启以上三种,或者部分的可能性,谢谢。

UWA:题主的“接受灯光”是指接受Real time光照吗?如果是的话,那么这种性能开销是没法预估的,因为它跟你的渲染场景复杂程度、接受光照物体的多少等都有很大关系,并不能简单理解成“开启就耗时、绝对不可以开启”。建议看看这篇文章:【求知探新】独立游戏《Abi》场景耗时分析

“产生阴影”和“接受阴影”是实时阴影功能的两个选项而已,建议在UWA性能报告中关注Shadows.RenderShadowMap和Shadows.PrepareShadowMap两项,从而来看到你项目的具体性能耗时情况。
请输入图片描述
目前,实时光照和实时阴影在很多移动项目中都已经开始大量使用。
最后,UWA Blog中有很多精彩的实时阴影文章,建议查看,希望对题主有所帮助。
https://blog.uwa4d.com/search/实时阴影

该回答由UWA提供,欢迎大家转至社区进行进一步交流:
https://answer.uwa4d.com/question/5ab8b537d35eb22c10a0a426


管理

Q5:我们项目正在立项初期,在Mono和IL2CPP之间犹豫徘徊。到底是Unity ILCPP编译好还是Mono的编译更好?IL2CPP的性能是否真有显著的变化?麻烦用过的朋友来分享下,谢谢!

A1:IL2CPP还是Mono,现阶段主要是安卓上的选择。

首先,这个问题在立项的时候无须纠结,就现在IL2CPP的成熟程度,随时打开就能用了,无须多虑。前期为了出包快,用Mono出。正式版本或者做性能和兼容性测试的版本,上IL2CPP,妥妥的。(当然指的是没有用.net做dll代码热更新的情况)

从个人在项目中尝试和得知的一些信息,稍微总结一下:

Mono的好处:
1)久经考验;
2)出包速度快;
3)包体略小;
4)支持安卓上DLL动态载入程序集热更新(本人没有用过,不肯定IL2CPP完全不支持)。

IL2CPP的好处:
1)没有堆内存只涨不降的问题;
2)C#侧的计算密集型算法性能暴增N倍(我们项目的同地图寻路、自动建筑位置规划等算法的速度都有3倍以上提升);
3)Lua热更无任何问题,反射调用还是导出式调用都很完美支持(应该不能算优点,但确实在我的预料之外)。

再说一下IL2CPP的问题:

  1. 构建时间长好多,安卓NDK的windows版工具链怎么就能性能这么低呢!AMD 16核32线程撕裂者走起,NDK编译时完美支持并行化的,核多了编译慢也不是事儿了;
  2. IL2CPP后,如果仅编译ARMv7的版本,部分模拟器无法启动游戏。用FAT(ARMv7 + x86)就可以了,而且模拟器上运行也非常流畅了,当然包又大了20多MB(我们的c#代码就是这么多…)。

Mono模式已经不可能支持64位了,面向未来,IL2CPP是唯一的选项,Unity现在已经做得很好了。

感谢郑昊提供了以上回答

A2:补充一点,安卓2019年想上架Google Play必须要提供64位的程序库,只能走IL2CPP这一条路了。

另外IL2CPP在安卓上还个坑 “Failed to extract resources needed by Il2CPP”,应该是目前是唯一阻碍我们使用的问题了(亲测在2017.3也会重现)
https://forum.unity.com/threads/failed-to-extract-resources-needed-by-il2cpp-unity-5-4-0f3.419593/

简单描述一下这个问题,在安卓上Unity要把IL2CPP需要用到的资源解压出来(assets/bin/Data/Managed目录,里面有Mono的config,及各种meta数据),每次启动都会这么干,关键问题是这个操作还会失败。其实Unity直接从apk里读就好了,但愿官方能早日完善这个问题。

该回答由littlesome@UWA问答提供,欢迎大家转至社区进行进一步交流:
https://answer.uwa4d.com/question/5abdea21425802635474fbb4


互动话题

Unity 2017中可以选择.net 4.6了,那要不要使用4.6的特性呢?你有什么高见吗?

欢迎来拍砖!