UWA问答 | 博客 | 游戏及VR应用性能优化记录分享 | 侑虎科技 - mono
ProtoBuf-net Serializer.Serialize产生大量的GC
1）ProtoBuf-net Serializer.Serialize产生大量的GC ​2）如何快速在工程代码中每个函数注入自己想要插入的代码 3）Unity设置IL2CPP导出的Mac平台的Xcode工程中，如何通过Object-C代码反调Unity侧的C#代码 4）ShaderGraph生成的Shader在UGUI上使用的问题 这是第289篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） Mono Q：在我们游戏中有使用到ProtoBuf的序列化，在查找性能问题的时候看到序列化的函数产生了大量的GC，如下图： A：可以参考《Unity3D游戏GC优化总结---protobuf-net无GC版本优化实践》。 感谢lanyt@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/621f2a12d83cff4676f5b924 Script Q：如何快速地在工程代码中的每个函数注入自己想要插入的代码？有说借助Mono Ceil的，还有一些库没有开源，所以想请问有没有其他方面的资料可以参考？ A：可以参考《使用Mono.Cecil实现IL代码注入》。 感谢羽飞@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/6220e17380139e0c1f157aae Script Q：在iOS平台下，IL2CPP导出的Xcode工程中Object-C调用Unity方法是通过SendMessage实现的： 请问在Mac平台下IL2CPP方式导出的Mac工程，如何通过Object-C代码反调Unity侧的C#代码？也是通过SendMessage的方式吗？但是我没找到相关的接口。 A：用SendMessage是可以实现的，但是效率不好。可以参考我这个Object-C回调Unity。把你需要的接口，写成函数指针，在Object-C里注册，需要时做回调。 可以参考《Unity与Object-C交互》。 感谢廖武兴@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/6215fcede7172c2775f76e56 Shader Q：我用URP 10.4.0和Shader Graph10.4.0建立了一个用于UGUI Image的Shader，它能在PC上正确运行，但是在手机上UV就错误了，如下图： 如下图，这样直接连一个简单的Tex2D就会出现，ShaderGraph也如下图连接： 我使用Unity 2022 URP13.1.6 SG13.1.6再次建立同样的ShaderGraph Shader在手机上是正确的，但是我暂时没有办法更换Unity版本。 A：可以参考这个视频的做法，应该是不能直接把ShaderGraph生成的Shader直接用到UGUI上的，需要做一些调整： https://www.youtube.com/watch?v=RxW7_qgkXPo 感谢Xuan@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/6221ec0d80139e0c1f16e5e2 封面图来源于：Protobuf-net Optimization Protobuf-net无GC优化版本，另外还提供了一些无GC自定义数据结构，以及对Unity 3D中C#代码的各种无GC使用方式测试。 今天的分享就到这里。当然，生有涯而知无涯。在漫漫的开发周期中，您看到的这些问题也许都只是冰山一角，我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入，也许你的方法恰能解别人的燃眉之急；而他山之“石”，也能攻你之“玉”。 官网：www.uwa4d.com 官方技术博客：blog.uwa4d.com 官方问答社区：answer.uwa4d.com UWA学堂：edu.uwa4d.com 官方技术QQ群：793972859（原群已满员）
子线程GC导致主线程函数耗时较高的问题
1）子线程GC导致主线程函数耗时较高的问题 ​2）升级Unity大版本后，Text颜色修改问题 3）清除增量式GC导致的Mono堆内存泄漏问题 4）多Pass合批优化问题 这是第274篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） Rendering Q：在主线程中有非常多的卡顿，从UWA的报告中看到很多异常的高耗时，请问可能是什么原因造成的？ A：像上面这样的频繁卡顿，且卡顿函数种类非常多的情况，应该是子线程分配了非常多的堆内存，导致子线程GC，从而卡住了主线程。当GC的时候，主线程可能会处于各种阶段，因此对应阶段的函数耗时就会包括等待GC的耗时。可以从UWA的Mono报告中查看是否有子线程分配了大量的堆内存，通常是由这种（Thread）打头的子线程函数的分配导致的。 感谢han@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/6180e0f28f8c834241fd6930 UGUI Q：从Unity 4.6.9f1升级到Unity 2020.3.2.f1c1。首次Unity升级之后UI的Text颜色修改是正常。当运行一次之后，所有的Text颜色都无法修改了。就算新创建一个新的Text也无法修改。 A：会有多余的UI-Default和UI-DefaultFont这两个Shader，删除它们，然后重启Unity就好了。 感谢芝麻青豆角@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/6185085fd8413e18eb034520 Mono Q：最近在研究Mono堆内存时，发现一帧内分配多次较大内存，会导致内存无法被回收。 过程如下： 在同一帧内调用三次分配100MB内存的方法，分配内存的变量都是在各自的作用域，在这之后调用GC.Collect()。发现有较大几率出现100MB或者200MB无法被回收的Mono堆内存。经过排查之后发现取消勾选Incremental GC之后，内存就能完全被收回。 我推测是每次申请内存的时候会执行一次GC，清除上一次分配的内存，但是由于使用增量GC，无法在本帧完成回收工作。再下一次GC的时候，第二次GC的回收内容被重置了，导致第二次的GC需要被回收的内存就泄漏了。 不知道我这么理解是不是对的，希望大佬们解惑。同时希望大佬告知有没有办法清除这部分内存。 测试环境： Unity 2019.4.15c1 Unity 2020.4.15f2 测试平台： 安卓 Mono 以下为测试代码： using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Profiling; public class TestMonoMemory : MonoBehaviour { void Do() { CallBack01(); CallBack02(); CallBack03(); } public void CallBack01() { List<int> i = new List<int>(1024 * 1024 * 100 / 4); //CallBack02(); } public void CallBack02() { List<int> i = new List<int>(1024 * 1024 * 100 / 4); //CallBack03(); } public void CallBack03() { List<int> i = new List<int>(1024 * 1024 * 100 / 4); } public string text; private void OnGUI() { GUILayout.Label("Allocated Mono heap size :" + Profiler.GetMonoHeapSizeLong() / (1024 * 1024) + "MB"); GUILayout.Label("Mono used size :" + Profiler.GetMonoUsedSizeLong() / (1024 * 1024) + "MB"); GUILayout.Label("Total Reserved memory by Unity: " + Profiler.GetTotalReservedMemoryLong() / (1024 * 1024) + "MB"); GUILayout.Label("- Allocated memory by Unity: " + Profiler.GetTotalAllocatedMemoryLong() / (1024 * 1024) + "MB"); GUILayout.Label("- Reserved but not allocated: " + Profiler.GetTotalUnusedReservedMemoryLong() / (1024 * 1024) + "MB"); if (GUILayout.Button("DO")) { Do(); } if (GUILayout.Button("DO1")) { CallBack01(); } if (GUILayout.Button("DO2")) { CallBack02(); } if (GUILayout.Button("DO3")) { CallBack03(); } if (GUILayout.Button("GC")) { System.GC.Collect(); } } } A：通过题主的方法，我也复现了该问题。我还是比较赞同你的理解的。 Unity官网的一篇关于增量GC的博客也写了该方法的弊端： 它的正常运行是需要前提的，那就是在GC期间这些被标记为“需要清理的内存”都保持不变。如果在GC期间变化了，比如频繁分配大量内存，那么就需要重新标记一遍，而这个阶段可能会有意想不到的bug产生。内存泄漏很可能就是发生在这个阶段（我也只是猜测）。 不过个人觉得增量GC仍然是一个良好的尝试，虽然它只是测试阶段，也存在着一些问题，但是以前的Boehm-Demers-Weiser garbage collector很容易引起高耗时峰值从而造成卡顿，而分代式GC正是为了减轻峰值的影响，尽量确保流畅性。 可以参考官方博客：https://blog.unity.com/technology/feature-preview-incremental-garbage-collection 该回答由UWA提供，欢迎大家转至社区交流： https://answer.uwa4d.com/question/61658ad48f8c834241d92a0b Rendering Q：游戏使用简单的Mesh显示几十张扑克牌，为了效果，材质Shader使用了2个Pass，其中一个是拉伸做边缘效果，但是由于是多Pass，即使是相同的材质和贴图，还是不能动态合批，请教这种情况有没有什么优化方案？ 1. 不能合批，但是材质是相同的，顺序渲染过程中是否有什么状态切换的消耗？ 2. 能否使用两个Mesh，不同的材质，Shader都使用单Pass，区别是一个Mesh是正常显示，一个Mesh仅仅做拉伸边缘效果，理论上是不是不超过顶点数的情况下可以两次动态合批？ A1：Unity BuiltIn渲染管线不支持多Pass合批，多Pass的Shader通过Set Pass call逐个渲染每个Pass后才会继续渲染下一个Object重复一遍，所以会产生比较多的Draw Call。 更好的办法就是用自定义的渲染管线的方式渲染多个Pass。在渲染第一个Pass的时候，把所有的Object一次性全都渲染了，渲染完毕之后通过一次Set Pass Call去渲染下个Pass，可以试下URP渲染管线。 感谢星傲蝶恋@UWA问答社区提供了回答 A2：题主说的第二点是比较常规的做法，要注意的是为了防止Draw Call的穿插，需要调整这两种渲染的RenderQueue，将他们对应的RenderQueue错开。 感谢Xuan@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/6178c9c58f8c834241f2aaeb 20211108 更多精彩问题等你回答～ Unity增量打包AssetBundle没变化的资源也会被重新打包 在模型有UV2的情况下开启Generate Lightmap UVs 如何实现AAB包的增量更新 封面图来源于网络 今天的分享就到这里。当然，生有涯而知无涯。在漫漫的开发周期中，您看到的这些问题也许都只是冰山一角，我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入，也许你的方法恰能解别人的燃眉之急；而他山之“石”，也能攻你之“玉”。 官网：www.uwa4d.com 官方技术博客：blog.uwa4d.com 官方问答社区：answer.uwa4d.com UWA学堂：edu.uwa4d.com 官方技术QQ群：793972859（原群已满员）
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（原群已满员）
多个相机分别实现各自屏幕后处理的问题
1）多个相机分别实现各自屏幕后处理的问题 ​2）怎么查看子线程中的GC Alloc 3）Mesh组件的世界坐标 4）绘制的Mesh丢失了Unity自带的Keywords 5）AssetDatabase V2和V1的核心区别 这是第235篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） Rendering Q：游戏中有多个相机，每个相机有自己的后处理效果。但是发现Depth越大的相机OnRenderImage传过来的图像越小于这个Depth所有相机的叠加图像，这样就没法实现各自的后处理效果，有什么方法可以解决吗？ A：经过测试，给Camera赋值RenderTarget，那这个相机上的OnRenderImage就只会对这个RT起作用。 使用这种方式，对不同的Camera加不同的OnRenderImage。最后需要一个额外的相机将这些RT合在一起，在这个额外的相机里面，可以渲染一个Canvas，里面用多个RawImage来将之前的RT叠在一起。 下图中，球和天空盒是场景相机渲染的，相机渲染到RT1，文本是UI相机渲染的，相机渲染到RT2。 第一个相机OnRenderImage里面颜色反一下，第二个相机的OnRenderImage里面变成灰度图。从下图可以看到这两个效果是相互独立的。 最后用CombineCamera画一个Canvas，里面有2个RawImage，RawImage里面的Texture分别使用那两个RT就可以了，如下图： 感谢Xuan@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5ffd0b2910a17c6c2b09d98c Mono Q：我把一些大计算量的东西放到了子线程中，现在想看下有没有GC Alloc，但是没找到像Profiler.BeginSample/Profiler.EndSample这样的方法，看不到子线程中的GC Alloc，只能看到时间开销。请问要怎么才能看到子线程中的GC Alloc呢？ A：目前新版本的GOT2.3版本已经支持了。 《多线程统计 | GOT Online新功能上线》 感谢Xuan@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5e575ef386a3954891983a38 UGUI Q：Mask组件的世界坐标传给了Shader，然后要把模型空间的Vertex转到世界空间进行对比。 把Mask的四个角的坐标通过GetWorldCorners这个接口获取到传给Shader， 然后将特效的Vertex转换到世界空间中作比较。但是效果看起来这个转换的值好像不太对，我的渲染模式是Overlay。 A：我把Render Mode改成Camera就行了，应该是在Overlay下GetWorldCorners获取到的值不正确。 感谢题主方星@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5ff9606310a17c6c2b09d94e Rendering Q：使用CommandBuffer.DrawRenderer绘制的Mesh会丢失Unity自带的Keywords，导致ShadeSH9计算的结果不对。（版本：Unity 2019.2.0f1） 正常渲染： CommandBuffer.DrawRenderer： A1：光照处理阶段，CommandBuffer的内容还未产生，所以也就不会有球谐和屏幕空间阴影的内容了。 感谢李星@UWA问答社区提供了回答 A2：测试后发现，可以使用EnableKeyword来强行开启Keyword。但是会遇到环境光渲染不出来的问题。 正常的渲染如下： 环境光渲染不出来，如下： 虽然Keywords是完整的，但是环境光还是没渲染出来，原因是SH的系数出问题了，具体解决方案可以参考： https://github.com/keijiro/LightProbeUtility 使用如下的代码可以让这个Cube和普通的渲染方式产生相同的渲染结果，但是需要使用CommandBuffer.DrawMesh的方式。 public class TestCommand : MonoBehaviour { public MeshRenderer rend; public Mesh mesh; CommandBuffer cb; MaterialPropertyBlock block; Material mat; void Start() { block = new MaterialPropertyBlock(); LightProbeUtility.SetSHCoefficients(rend.transform.position, block);//来自git中的脚本 cb = new CommandBuffer(); cb.name = "DrawCube"; mat = new Material(rend.sharedMaterial); mat.EnableKeyword("SHADOWS_SCREEN"); mat.EnableKeyword("LIGHTPROBE_SH"); cb.DrawMesh(mesh, rend.localToWorldMatrix, mat, 0, 0, block); Camera.main.AddCommandBuffer(CameraEvent.AfterSkybox, cb); } } 感谢Xuan@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5ff2c41610a17c6c2b09d87c Editor Q：AssetDatabaseV2和V1的核心区别是什么？切换到V2对项目有哪些好处？ A1：做个搬运工： 《资产导入新管线：加速资源导入的坚实基础》 《Asset Pipeline Version 2（Asset Database v2）内部细节》 《The new Asset Import Pipeline: Solid foundation for speeding up asset imports》 AssetDatabase.Refresh() refresher - Unite Copenhagen（需要梯子） Speed up your asset imports for big projects - Unite Copenhagen（需要梯子） 【三思Unity】深入浅出资源管理之：Asset Import Pipeline v2（上） 感谢黄程@UWA问答社区提供了回答 A2：就是在编辑器加速导入的功能，本身也不收费。加速幅度还比较大，对多个小文件导入提速比较明显，但是导入ASTC图片依然很慢，可能因为主要耗时是在图片转换这边。总的来说，切换到V2没遇到什么问题。 感谢邹彬@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5f8eaaf79424416784ef286f 封面图来自网络 今天的分享就到这里。当然，生有涯而知无涯。在漫漫的开发周期中，您看到的这些问题也许都只是冰山一角，我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入，也许你的方法恰能解别人的燃眉之急；而他山之“石”，也能攻你之“玉”。 官网：www.uwa4d.com 官方技术博客：blog.uwa4d.com 官方问答社区：answer.uwa4d.com UWA学堂：edu.uwa4d.com 官方技术QQ群：793972859（原群已满员）
1）开启Allow unsafe code的影响 ​2）Unity线性空间下，PhotoShop制作半透明图片，制作带外发光、内发光的图层如何正确导出 3）Unity中实现完善的暂停机制 4）RenderPipelineManager.DoRenderLoop_Internal的堆内存优化 5）Unity 2020版本中ARBackgroundRenderer和ARRenderMode的相应替代类 这是第223篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） Script Q：最近项目引进几个插件，以及学习别人的插件，代码中用到了unsafe关键字，需要再project settings中勾选Allow unsafe code，之前知道一点是不勾选最好，但是勾选以后到底哪里不好也忘了，也没有勾选之后上线来验证，所以问问大家，是否应该勾选，以及勾选之后有何影响？ A：勾了没什么实际上的坏处，只是由于.net当初设计的时候是不鼓励使用unsafe代码的，所以在编译器默认设置这个门槛，鼓励大家尽可能使用安全的代码（也就是不要直接操作原生内存地址）。 但是，很多高性能的C#代码为了最大限度地高效访问内存，不可避免要用unsafe，只要保证unsafe代码被限制在较小的范围并严格测试保证不会出内存访问错误，对整个工程来说就不是大问题。 感谢招文勇@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5f8820039424416784ef27cb Texture Q：大家好，因为项目是PBR项目，所以Unity使用线性空间，现在在制作UI的时候，带透明通道的图片，混合时候就会出错。 我们前后试了几种方法： 1. 改PhotoShop的工作空间为线性的，定义Gamma为1.0： 2. 单独改用灰度系数混合RGB颜色：1.00，这样大部分情况下，Unity中效果PhotoShop中效果就是一致的： 3. 改Unity渲染管线。 以上方法都有一些局限和问题。 1. 普通不透明图层有些渐变效果无法绘制，因为线性空间下的暗部颜色精度不够； 2. PhotoShop制作带外发光、内发光的图层合并之后会错误： 3. 因为用的还是内置Forward管线，影响太大，低端机效率低下，暂不考虑。 我们最终采用的是第二种，美术还是在Gamma工作空间作图，只是图层混合采样。 最后想问下大家，针对线性空间下的半透明图层如何导出？ 或者有没有什么办法能处理这种外发光、内发光图层问题？ A1：目前公司项目都采用Linear方式，美术直接修改PhotoShop设置，出图过后，在Unity中测试，能与原图是一个色彩，之前也尝试过其他办法，如Shader修正，但是都有一定的问题，目前采用的这种方案，暂未发现问题。 感谢范超@UWA问答社区提供了回答 A2：用下图的配置，在PhotoShop CC 2019里试了下，只要不合并图层，直接导出png，再放到Unity中就没有问题。另外如问题中的例子，只要从下向上合并图层（带着背景），最终结果就没问题。可能是PhotoShop的Bug。 就我和美术了解的情况，他们很少合并图层。一般导出就是把不需要的图层隐藏了。所以这种情况应该是可以避免的。 感谢张首峰@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5f8129c29424416784ef25a1 Script Q：目前使用TimeScale=0来暂停游戏，但是在UI上不想让特效和动画暂停，而在某些战斗场景，只希望暂停一部分逻辑。如果把TimeScale=0，就要处理ParticleSystem、TrailRenderer、Spine动画等组件，特别是TrailRenderer和Spine都需要修改源码。如果不用TimeScale=0， 是不是就要在框架层就处理好各模块的更新逻辑？ A1：常规的做法确实就如你说的，不用TimeScale=0，各个地方去实现暂停，然后统一管理。 感谢邓永健@UWA问答社区提供了回答 A2：可参考这篇文章：《Unity Chronos - Time Control 时间控制器》 感谢黄程@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5f812d769424416784ef25a4 Mono Q：项目采用了URP，用UWA进行了初步测试，发现RenderPipelineManager.DoRenderLoop_Internal分配了很多堆内存，这个函数是URP中的内置函数吗？应该如何定位问题进行优化？ A：这个函数是内置用于SRP的总函数，不过分配堆内存的很有可能是题主自己写的C#函数。从图中来看，目前堆内存分配的太多了，建议通过GOT（Online）中的Mono模式来进行测试，就可以看到其具体的堆内存分配情况了。通过“倒序”查看方式，可以直接查看分配的最低级子函数，如下图所示。 以上回答由UWA提供，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5f8666969424416784ef26db Editor Q：请问下，以下这两个类现在有替代类吗？是怎么规划处理的？ UnityEngine.XR.ARBackgroundRenderer UnityEngine.XR.ARRenderMode 以上这两个类经测试： Unity版本：2020.1.4f1c1，找不到； Unity版本：2019.4.7f1，找得到。 我又试了下当前最新的Untiy 2020.2.0b6版本这两个类也没有。 看了些资料，Unity 2020版本后，这两个类应该就被删除了。 A：Unity新版本将很多功能都是以Package的方式导入，关于AR从PackageManager中导入AR Foundation包，ChangeLog中有提到ARBackgroundRenderer已经在某个版本重命名为ARCameraBackground，AR/VR开发可能需要熟悉一下相关的Package，如下图： 感谢羽飞@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5f8839d99424416784ef2802 封面图来源于网络 今天的分享就到这里。当然，生有涯而知无涯。在漫漫的开发周期中，您看到的这些问题也许都只是冰山一角，我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入，也许你的方法恰能解别人的燃眉之急；而他山之“石”，也能攻你之“玉”。 官网：www.uwa4d.com 官方技术博客：blog.uwa4d.com 官方问答社区：answer.uwa4d.com UWA学堂：edu.uwa4d.com 官方技术QQ群：793972859（原群已满员）
如何远程更新Addressable随包打进的游戏资源
1）如何远程更新Addressable随包打进的游戏资源 ​2）Unity内存机制与安卓内存机制的关系 3）UWA报告中的GPU渲染信息统计 4）如何采样不同纹理压缩格式的时间 5）如何去掉每帧的GC 这是第211篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） Addressable Q：我们新项目想用Addressable Asset System。我这几天看了一下，有个问题想请教一下：AAS通过Build and Load Paths设置local/remote决定Group中的资源随包/远端下载。那么我想在远端更新local方式的资源（即随包打进StreamingAssets中的资源）该怎么操作？ A：Local打包方式的Group设置Cannot Change Post Release，两个属性bundlename设置成FileName，取消bundle的CRC，这样再Check/Build之后就可以做到增量更新了。Addressable会把改变的部分生成到一个新的Group中，这个Group会默认设置成remotebuild/load 。这样就做到增量更新了。 感谢题主柚子爱爸爸@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5ee9d9725d07d80acd26241c Memory Q：Unity内存机制与安卓自身的内存机制有什么关系？我目前的理解是安卓操作系统基于Linux内核，所以自己有本身的内存管理机制；而java VM是为了让一些应用可以运行在安卓平台上而建立的一种跨平台机制。相当于在安卓系统上开了一个虚拟机，应用运行在虚拟机的环境中。同理，Mono和IL2CPP也是另一种虚拟机，也会运行在安卓操作系统上，但是也有着自己本身虚拟机的内存管理机制，也就是说Unity的内存管理机制实际上就是Mono或者IL2CPP的内存管理机制。 想了解下我的理解对吗？虚拟机的管理机制和安卓系统的管理机制有什么样的关联呢？任何相关的回答都不胜感激，谢谢！ A：可以参考： 《浅谈Unity内存管理》——视频 https://www.bilibili.com/video/av79798486/ 《浅谈Unity内存管理》——猫冬夏的笔记 https://www.notion.so/Unity-f79bb1d4ccfc483fbd8f8eb859ae55fe 感谢俞顺捷@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5f02890dc6123f2e0df5b3ae Rendering Q：URP项目GPU渲染信息统计问题：看情况是统计到逻辑代码里了，这个后面会区分出来吗？ A：CPU耗时和GPU耗时是完全不同的两码事。虽然最终渲染是在GPU端进行，但是CPU端也需要做很多事情的，比如提交Draw Call。以不透明渲染来说，常见的是Render.Mesh,Batch.DrawStatic这些Draw Call的提交，再比如MeshSkinning.Render，Culling等，这些都算在Camera.Render的耗时里面。 在使用了SRP的情况下，与Camera.Render相对应的函数叫RenderPipelineManager.DoRenderLoop_Internal()，这里面的耗时也都是CPU端的耗时，建议题主通过UWA线上的真人真机测评服务来查看更为具体的耗时分配。 题主截图中的GPU耗时为0，可能是因为使用了Vulkan，也可能是因为某些GPU型号问题（一般出现在华为手机上），但这个跟CPU的耗时都没有关系的，也并不是GPU的耗时统计到CPU逻辑代码里面去了。 感谢Xuan@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5f02e4a2ade17d6115427bb2 Texture Q：有什么方法可以知道采样不同纹理压缩格式的时间吗？想了解下对于ETC2 ETC、ASTC采样所消耗的时间，能够具体量化吗？ A：我理解只要是硬件原生支持的贴图格式，采样的时长应该没什么差别吧，毕竟都是硬件解压到显存中进行。 更可能产生差异的是大小不同导致的传输时间和命中率上的差异，比如ASTC通常优于RGBA的原因就是对于带宽占用小，Cache命中率高。 可能整体看更好，当然如果要去追究采样消耗，可能通过一些GPU Profile统计Sampe的消耗会有些价值。 感谢贾伟昊@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5ee19dd2713e187c947575d9 Mono Q：scriptableruntimereflectionsystemwrapper每帧都有9B GC，如何去掉呢？ A1：可以参考： https://unity3d.com/cn/unity/whats-new/2018.3.8 Scripting: Removed allocation in every frame from ScriptableRuntimeReflectionSystemWrapper.TickRealtimeProbes. (1097039) 感谢littlesome@UWA问答社区提供了回答 A2：一般为SRP中一些逻辑代码所分配的堆内存占用，可能是Command buffer的切换代码或者其他。可以通过Deep Profiler方式在Editor中定位具体是什么函数。 该问答由UWA提供，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5efff0412e944561c84e0001 封面图来源于网络 今天的分享就到这里。当然，生有涯而知无涯。在漫漫的开发周期中，您看到的这些问题也许都只是冰山一角，我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入，也许你的方法恰能解别人的燃眉之急；而他山之“石”，也能攻你之“玉”。 官网：www.uwa4d.com 官方技术博客：blog.uwa4d.com 官方问答社区：answer.uwa4d.com UWA学堂：edu.uwa4d.com 官方技术QQ群：793972859（原群已满员）
1）关于Texture2D Crunched压缩格式 ​2）Unity自身GC和.NET的GC如何协调工作 3）关于环境光照球面坐标映射2D贴图UV的某算法的疑问 4）iOS审核dlopen、dlsym风险 5）Unity 2018.4在iOS上压缩贴图用的是哪个可执行文件 这是第208篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） Texture Q1：关于Texture2D的压缩格式设置上，想问一下大家有没有Crunch ETC2 压缩格式的上线经验。效果如何？ A1：当时是使用的Unity 4.7，后来翻了5.6的源码移植。2017的算法有了更多的优化。为了解决包体大小的问题，曾经在某上线项目中，将Crunched ETC2功能移植到了Unity早期的版本中。 使用Crunched ETC2压缩后会降低包体的大小，但同时会增加运行时解压缩的时间消耗，总体来说效率影响是比较可控的。不同的贴图使用Crunched ETC2会有不同的压缩比，于是对于一类贴图批量控制贴图格式将达到更好的压缩性价比。 当时我们针对部分类型的帖图进行了Crunched ETC2的压缩，测试下来的效果是默认开启Crunched ETC2整体包体可以优化百分之十左右。其中在三星 Note3上，单张512开启10级Mipmap，解压时耗大约在2ms左右。 使用最新的Unity引擎启用Crunched后将获得更好的效率（Unity本身也持续有优化。貌似之前Crunched的作者已被官方收编）如果对包体大小要求较高，建议可以大胆尝试。 Q2：目前用Crunch ETC2算法压缩在安卓平台下一个2048*1536的图可以压到342KB。压缩比例很高，使用的版本用的Unity 2017还是更早？ A2：当时是使用的Unity 4.7后来翻了5.6的源码移植。2017的算法有了更多的优化。 感谢康斯特@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5eec64f9ea02f0538ce31716 Script Q：Unity有自己的GC，.NET也有自己的GC，两者在游戏运行的时候，是如何协调工作的？ A1：提出这个问题之前，先要搞清楚一个问题：Unity与Mono和.NET三个概念之间的的关系。 维基百科： .NET框架（英语：.NET Framework）是由微软开发，一个致力于敏捷软件开发（Agile Software Development）、快速应用开发（Rapid Application Development）、平台无关性和网络透明化的软件框架。 .NET Framework是一个软件框架，可以理解为对一系列结构和功能的期待。不是一个具体的某个软件。最初有一段时间，.NET框架只能在Windows平台上运行。 Mono是.NET运行时和开发库的实现版本，为C#脚本提供一个编译器和运行的虚拟机（CLR）。Mono的初衷是：(1)使微软.NET应用可以跨平台运行 (2)支持.NET在Linux上使用。Mono比.NET Core支持更多的平台（如：Linux、FreeBSD、Unix、Mac OS X和Solaris）。 Unity引擎对跨平台特性有很大的需求，于是使用Mono提供C#等符合CLI规范的脚本语言的运行环境。 直观的理解参考下图： 总的来说，Unity驱动Mono，为C#等提供编译和运行的环境。而C#等脚本的GC便是由Mono的虚拟机提供的。 因此，题主说的Unity自己的GC，和.NET的GC，应该是一回事，也就是Mono的GC。（如有错误之处，希望大神指出） Ref: https://www.cnblogs.com/shanyou/p/4295163.html https://www.cnblogs.com/zhujinghui/p/3369217.html https://zh.wikipedia.org/wiki/.NET框架 https://en.wikipedia.org/wiki/Mono_(software) https://www.cnblogs.com/u3ddjw/p/10909975.html 上面忽略了Native层的内存垃圾，不过Native的垃圾回收不存在像Mono一样的自动回收机制。需要主动调用Resources.UnloadUnusedAssets()来触发。 感谢Prince@UWA问答社区提供了回答 A2：Unity里面的 C# GC是针对代码层的。Unity的所谓GC是针对资源的。 感谢欧月松@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5eda0243eab6db1f8238a372 Shader Q：在学习某大作的Shader的时候发现类似以下算法，不是很明白这些魔术数字的意义。 float h = pow(tmpvar_50, 2); h = ((((((((((-0.01213232 * h) + 0.05368138) * h) - 0.1173503) * h) + 0.1938925) * h) - 0.3326756) * h) + 0.9999793) * tmpvar_50; h += float(absEnvRefzx > 1.0) * (h * -2.0 + UNITY_HALF_PI); 因为是在处理环境贴图的球面坐标映射到2D贴图UV的地方，目测应该是一些快速三角函数计算，但和找到的几个都对不上。 A：好像是arctan的近似公式（0-1对应角度0-45很精确），但没找到相关资料。 https://www.desmos.com/calculator/93qwjpebpu 推荐的arctan近似公式： https://stackoverflow.com/questions/42537957/fast-accurate-atan-arctan-approximation-algorithm 感谢羽飞@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5ee195b1299ada7c8f9c2590 Build Q：在iOS build的时候会存在dlopen，dlsym，dlclose的函数，断点的时候没有发现调用，有人知道这些函数的作用吗？ 问题解决： Unity 2017.4.20版本经测试发现Scripting Runtime Version使用.Net4.6的编译会出现dlopen，dlsys，dlclose这3个有风险的API。使用.Net3.5的不存在该问题。 另外在Unity 2018.4.6版本中发现使用.Net4.6并不存在该问题。 这些接口是在IL2CPP的Unity自动生成的，在空的项目也是存在这个问题的，所以应该不是由于使用System.IO中接口导致的。（个人猜想，未证实，如有知道原因，欢迎指出）。 还有渲染的模块也用到了dlsym dlopen。 A：大致查了一下。 根据这篇文章：https://www.jianshu.com/p/b0ce48a22d61，Unity本身就带的，在送审标注里说明，但是插件最好去掉。 另外自己写的System.IO相关的代码不需要的可以检查一下并测试去除。 https://blog.csdn.net/qq_36622009/article/details/103882854 感谢倪帅帅@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5ee1a39a6a5b507cc4513c86 Editor Q1：过去用的是PVRTexTool，但是对Unity 2018.4，将这个可执行文件删除也并没报任何错误，应该是没有被运行。那么现在Unity在压缩ASTC的时候，用的是那个exe文件呢？ A1：回答如下： （1）Unity 2018.4在将Texture压缩为PVRTC的时候使用的是PVRTexTool，在进行压缩时，可见进程中多了PVRTexToolCLI，如图： （2）Unity 2018.4在将Texture压缩为ASTC格式时候，没有使用外部的exe文件，因为压缩时系统中进程数量没有增加，而Unity.exe的CPU利用率增高。 （3）但PVRTexTool本身应该是可以用来压缩成ASTC格式的，可参考文档： http://cdn.imgtec.com/sdk-documentation/PVRTexTool.User+Manual.pdf （4）此外，ARM提供的astc-encoder是ASTC数据格式的压缩器： https://github.com/ARM-software/astc-encoder Q2：在Mac OS上测试的结果是：项目中有PVRTC贴图，但将PVRTexTool改名，Unity没有任何抱怨。 A2：换一下PVRTC贴图的质量（2 bits, 4 bits等），点apply，重新压缩，看会不会报错。 感谢题主Prince@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5ee21955cb30182b94d10fcf 封面图来源于网络 今天的分享就到这里。当然，生有涯而知无涯。在漫漫的开发周期中，您看到的这些问题也许都只是冰山一角，我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入，也许你的方法恰能解别人的燃眉之急；而他山之“石”，也能攻你之“玉”。 官网：www.uwa4d.com 官方技术博客：blog.uwa4d.com 官方问答社区：answer.uwa4d.com UWA学堂：edu.uwa4d.com 官方技术QQ群：793972859（原群已满员）
不管项目本身是否重度，性能调优永远是上线前的必经之路。优化性能，不仅需要足够深度的分析来定位问题瓶颈，也需前瞻性的保障措施来缓解后续的优化压力和性能风险。因此，我们推出了UWA GOT Online，并且很荣幸地在推出后得到不少朋友的积极反馈。 关于UWA GOT Online UWA GOT是UWA推出的本地性能测评工具，它方便研发团队在本地真机测试，并能在编辑器中搭建本地服务器查看性能数据。UWA GOT Online是基于其本地测评模式上的线上同步功能，研发团队可以将本地测评的数据快速同步到UWA官网，生成在线测评报告。 除了“本地化”和“快”这两大天然优势，我们目前提供了四大性能检测模式：总体性能检测、Mono堆内存分析、运行时资源检测和Lua性能分析来满足大家的优化需求，下面小编就带大家一一浏览。文末附上UWA GOT Online的使用攻略哦！ 以下是四大模式的核心功能和特色，点击对应的条目可以查阅详细的功能说明。 CPU性能检测 全方位的引擎模块剖析（渲染、物理、粒子、UI、动画和加载，一个都不能少） UWA API 提供（锁定你关注的性能细节，让其无处遁形） Mono堆内存检测 Mono具体分配详情（对代码堆内存的分配一目了然，还有贴心的倒序功能哦） Mono堆内存泄露定位（代码泄漏风险？用这个模式捋一遍就明了） 运行时资源检测 具体资源使用情况检测（详细展现主流资源的具体运行情况） 资源内存泄露定位（不同采样点随心比较，科学排查泄漏风险） Lua性能检测 LuaCPU性能测评 （深度、全面的调用堆栈，直接锁定性能瓶颈） Lua内存检测（无论是内存分配过大还是内存泄露，用它就对了） 凭借“本地化”和“快”两大天然优势，UWA GOT Online能让项目人员快速执行项目的测试需求，以更友好、更易用的展示方式呈现给开发者。同时，依托于报告中具有针对性的分析建议，研发/测试人员也能定期地对自己的项目版本进行性能跟踪，一旦发现某个版本上的某个重要性能指标出现了问题，就能及时反馈给研发团队进行完善和修复。 UWA GOT Online截图 项目的研发需要持续改善，而解决问题的最佳时机就是在我们看到问题的当下，从而极大减少后期的优化时间，降低后期堆积的性能压力的风险，并加快游戏的整体研发进度。 以上就是UWA GOT Online功能的不完全说明，更多功能欢迎大家登陆www.uwa4d.com，在“本地测试 / UWA GOT Online”中查看各个模式下的Demo报告。 UWA GOT Online使用攻略 1、我可以直接用UWA GOT Online吗？具体操作方式如何？ 首先你需要拥有一个灵活的本地化测评工具UWA GOT； UWA GOT Online的具体操作方式为：本地真机测试完毕后，将测试数据传输到UWA官网进行查看。 2、UWA GOT和UWA GOT Online功能上有哪些区别？ 配置还是很不一样的哦，后者包括更广度的检测模式/功能，包括Lua性能、CPU性能模块分析、性能简报、优化建议和版本对比等功能，具体可参见此处。 3、想试试看怎么入手？ 登录UWA官网的个人账号，选择“立即体验”即可开始试用。 4、UWA GOT Online具体效果如何？ 截止目前，我们收到不少团队的积极反馈，并获知该功能帮助他们改善了测试机制。 UWA报告Tips 性能简报—小白都能秒懂的定位方法！ 优化时间不充裕？快快让性能简报帮你抓重点！ 突然卡顿不知为啥，卡顿分析里有大秘密！ 解决疑难杂症必备：堆栈分析，从此开启专家把脉模式！ 重要引擎性能参数，把握项目健康的几个核心指标！ 内存过高，资源占用的几个大头要盯牢！ 粒子数量过高，看看是否都物尽其用了？ 特效复杂，使用Overdraw排查问题就对了！ Mali Counter 分析，高效定位发热、耗电现象 Timeline视图分析，直观显示卡顿的时序 Lua-Mono对象引用，解决Mono内存泄漏的顽疾 Shader解析耗时高，原来是冗余问题在作怪 资源实例化&激活，想要运行表现平滑，这个技巧不能少 Mipmap分析，优化纹理分辨率，每个像素用到刀刃上 自定义参数，随时把关重要参数走势 GC调用分析，GC耗时、调用频率一览无余 渲染模块性能分析，快速定位，一目了然！ Shader.CreateGPUProgram 优化分析，特别重点关注游戏战斗中的耗时！ Shader.Parse优化分析，优化Shader策略，避免重复加载卸载！ Unity卸载优化分析，场景切换时间太长，如何有效优化？ 物理模块优化分析，一招教你把耗时清零！ 网格内存优化，降低网格内存一二三，走你！ 纹理资源内存优化（一），纹理太大还是冗余？这些小技巧必备！ 纹理资源内存优化（二），优化缓存策略，巧妙降低纹理内存！ GPU图元处理，节省GPU图元算力，减缓带宽能耗压力！ GPU Shader Cycles，锁定Shader复杂度瓶颈，针对性排查优化！ 温度细分为CPU、GPU、 电池，定位压力来源，确认发热原因！高效优化的小技巧~ AssetBundle驻留信息，AssetBundle的驻留情况怎么看，你学会了吗？ 场景分隔线，精细化数据分析，你有没有用起来呢？ Mono泄漏，如果判断定位堆内存性能点？内存泄露分析来帮你！ Mono倒序调用，快速定位堆内存深层子函数，定位堆内存问题瓶颈！ Lua倒序调用，定位堆内存分配、高耗时原因，精确到代码行！ Lua端Mono对象引用，查看Mono对象引用情况，避免Lua端造成的堆内存泄漏！ UWA性能简报页更新！新增性能评级，项目瓶颈一目了然！ 性能总结页改版啦！新增Jank帧和同步等待耗时统计！ 如何进行特效优化？试试GOT Online Overview模式吧！ GPU负载在Mali芯片下都有哪些参数？如何优化？ GPU负载在Adreno和PowerVR芯片下代表什么？要怎么来看？ 提高场景GPU缓存率，节省带宽和能耗！ 当GPU压力较大时，要如何选择纹理过滤？ 查看测试时的设备功率信息，定位发热耗电情况！ 线程耗时统计，支持子线程数据统计，快速定位线程压力情况！ 性能简报页，快速跳转至问题界面，定位问题不迷路~ 如何快速判断项目压力情况？试试GPU同步模块吧！ 函数堆栈自定义面板，除了函数的耗时情况，有时调用次数也是需要关注的重点！ Overview Timeline，UWA SDK 支持可视化配置啦！开关模式更便捷！ Overview API/堆栈细节，如何获取更详细的堆栈信息？快打开API和堆栈细节！ GOT Online Overview模式中获取Resource数据，告诉你一个定位资源问题的小技巧~ GOT Online Overview模式中获取Lua数据，打开Lua数据采集，精准定位Lua问题！ 三种开启GOT Online测试的方法，总有一款适合你~ “回归测试”、“CPU压力较大”、“内存压力较大”这三种不同场景下 使用GOT Online测试时UWA推荐的参数开关配置
今天推送一则重要消息！UWA在线测评在Android平台上增加了对IL2CPP的支持（iOS平台照常支持）。随着越来越多的Unity项目在该模式开发和打包，该支持将为大家的项目打包测试提供了极大的便利！ 目前，在UWA官网中下载到的最新版UWA SDK（版本号1.2.3）中，我们可以看到针对不同模式，分为普通（Mono）和IL2CPP两个版本，大家只需针对各自的开发模式进行对应的SDK集成即可。 从此不再为运行时的选择而烦恼，大家可以痛痛快快地出包提测啦！ 需要说明的是，IL2CPP 模式下，尚不支持以下模块的数据检测：资源管理、GPU 性能和堆内存测试。对于这些模块性能较为关注的开发者，建议尽可能用 Mono 模式发布提交，以获得完整的性能数据。
这是第122篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） WebGL Q1：目前我们有一个采用Spine的2D项目需要转换成H5游戏，请问直接使用Unity开发WebGL的项目，性能上会有哪些注意事项呢？ 看题主的意思是想在移动设备上跑。我们项目（竞速类）曾尝试了直接用Unity 5转为页游版本，但是是运行在PC平台上的，手机上简单了解过别人的项目，当时得出的初步结论是在移动设备上中重度的3D性能扛不住，这个没有经过亲自验证。 我列下我们在Unity5转PC页游踩的坑供你参考下： 1）WebGL中不支持多线程和C#网络，可以用协程、Websocket代替； 2）我们有些协程用法写得有问题，在协程函数中用了While(1)这种死循环等待资源加载完成，在其它平台下没问题，但是在WebGL中会死循环，大概跟WebGL不支持多线程有关； 3）在游戏加载资源过程中，随着占用内存增大，偶尔会内存溢出，这主要是我们资源没有优化好导致的。我们在跟一个成熟的页游团队交流时，对方建议页游内存不要超过256MB，需要很细致地控制资源的加载和释放； 4）建议使用LZ4压缩格式，WebGL不支持多线程，LZMA压缩的Bundle会导致主线程解压缩时的卡顿； 5）单个资源体积不宜过大，建议控制在1MB以下，尽量做资源依赖打包，要不加载时间过长，很影响体验； 6）WebGL不支持中文输入，我们用原生的方式实现了中文输入； 7）PC端一些浏览器直接不支持，我们测试支持的浏览器有： Google Chrome 9+ 2.Mozilla Firefox 4+ Safari 5.1+(仅限Mac OS X操作系统，不包括Windows) Opera 12 alpha以及以上版本 IE9+，但是IE并不支持WebGL，不过你可以通过下载并安装IEWebGL这个插件 QQ 360 搜狗 8）资源如果没有实例化使用，在Editor下不会闪退，但是打出的PC包和导出的WebGL版本都会闪退。 感谢赵林@UWA问答社区提供了回答，欢迎大家转至社区进一步交流： https://answer.uwa4d.com/question/5b3a27bd3ab9166bb3e84927 堆内存 Q2：从理论上来说，Mono堆内存是越小越好（UWA是建议控制在40MB以内），分配频率越低越好。那单次比较大的内存分配和频率很高的（比如每帧）小内存分配，在性能影响上谁更大呢？单次GC的耗时，是受总体堆大小影响较大，还是受堆内引用对象数量的影响较大？简单来说，是要优先优化那些每帧分配的小内存还是单次较大的内存分配？GC对机器发热的影响大吗？ 优先优化那些每帧都分配的小内存。这个对于GC到来的影响比较大。频繁GC对于运行流畅性的影响比较大，从整体上来说，GC对于能耗的影响不大，比常规开销(渲染模块、UI模块等)要小很多。 单次较高的堆内存分配，建议要注意2MB以上的分配，查看其分配是否合理，尽可能避免8MB以上的分配。它主要的麻烦点在于撑大Mono堆内存峰值，一旦上去了就下不来。 该回答由UWA提供 Mono堆内存峰值高，最大的影响是会撑大Mono内存的占用量，而Mono向系统申请的内存是只增不减的。直白说就是游戏内存占用上升，风险是低内存设备上更容易闪退。 感谢Walker@UWA问答社区提供了回答 GC耗时肯定会受到影响。目前来讲，无论是IL2CPP还是Mono，GC都不分代，这也就意味着，回收的时候会遍历所有的节点。 感谢凯奥斯@UWA问答社区提供了回答 欢迎大家转至社区进一步交流： https://answer.uwa4d.com/question/5b5bd3471e88b37d34e6517d 资源管理 Q3：大家是怎么做代码分离的？游戏项目由于有多个部门需要共同访问，为了保护源代码，希望做到非技术部门在游戏工程只拿到加密后的DLL文件。 最初的想法是，各个部门都是拿同一个游戏工程，其中技术部直接获取源码，其他部门拿到DLL文件，技术编写完成后生成DLL给其他部门更新。但发现Unity中挂脚本组件是通过GUID+FileID的方式去匹配的，所以拿源码的同事是不同的脚本就有不同的GUID，拿DLL的同事则都是同一个GUID。导致不同部门之间没法在同一个工程上制作。 现在的做法是另外创建一个编译工程去生成各个平台对应的DLL文件，但是这样又比较繁琐。 PS：即使在已经做了模块分隔的情况下，导入DLL的时间比更新少量cs文件的时间多出很多，请问大家有没有更好的做法呢？ 这个我们是看部门需求的。 1）美术部门时常需要在Unity上调试效果，我们只对该部门提供带加密好DLL的工程项目，指定目录提交对应资源，并做好工具操作的提示。 2）策划部门在Unity调效果不是硬需求（看各自公司的情况吧），可以提供可加载本地Lua代码的exe包，让业务提供配置代码，并将该部分代码对策划开放(但由于有语法学习成本，可以在svn可hook一个语法检查)，或者工具打包到exe中。 临时想到这些，看看是否能帮到题主。 感谢兰叶凛香@UWA问答社区提供了回答 "导入DLL的时间比更新少量cs文件的时间多太多了，即使在已经做了模块分隔的情况下"。这个问题我估计是题主没加AssemblyInfo，导致Unity会扫描API，可以参考下：https://github.com/pangweiwei/slua/blob/master/Assets/Slua/Editor/LuaCodeGen.cs#L544。 只要大家用一个Unity版本速度会快很多。 再PS. 现在2018了为了一些代码搞这么麻烦性价比真心低。 感谢钱康来@UWA问答社区提供了回答 如果业务逻辑都在Lua，那么可以选择加密Lua的bytecode， 如果业务逻辑也是C#写的，那么可以选择不加密。 其实都到2018年年中了，代码没那么值钱了。用DLL都会加大其他部门的使用繁琐程度。 感谢史云柯@UWA问答社区提供了回答 欢迎大家转至社区进一步交流： https://answer.uwa4d.com/question/5b4eb5f4339d267d357c6b6c 资源管理 Q4：如果多个不同的Shader引用同一份cginc文件，实际上会被编译多少次？ 我理解的是，cginc 是被包含的，相当于编译器预处理复制粘贴到了Shader文件里，可以看做并不存在cginc 这个文件，所以有几个Shader文件包含了这个 cginc，就编译几次。 感谢jim@UWA问答社区提供了回答 cginc只是一些代码片段，Shader用到某个cginc的时候就会把里面对应的函数抠出来，在precompile的时候完成该项工作。所以，如果不同的Shader引用到了同一份cginc文件，其编译并不是整个cginc文件参与编译，而是Shader中用到的那一段代码进行了编译。 该回答由UWA提供 欢迎大家转至社区进行进一步交流： https://answer.uwa4d.com/question/5b5552ff339d267d357c6bdf 动画 Q5：在一个动画事件中实例化另一个动画物体（使用Animator），发现实例化的物体并没有直接开始动画，而是显示了一下默认姿态，在下一帧之后才开始了动画。请问这个该如何处理呢？ 动画事件是动画系统在进行了该帧动画计算（Animation Evaluation）之后激活，如果在动画事件中实例化动画物体，该物体的animator不会在该帧进行动画计算，而会等到下一帧时由动画系统进行动画计算。解决方案是在实例化动画物体后，调用一下 Animator.Update(0). 该回答由UWA提供，欢迎大家转至社区进行进一步交流： https://answer.uwa4d.com/question/5b5ed8681e88b37d34e6519c 今天的分享就到这里。当然，生有涯而知无涯。在漫漫的开发周期中，您看到的这些问题也许都只是冰山一角，我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入，也许你的方法恰能解别人的燃眉之急；而他山之“石”，也能攻你之“玉”。 官网：www.uwa4d.com 官方技术博客：blog.uwa4d.com 官方问答社区：answer.uwa4d.com 官方技术QQ群：793972859（原群已满员）