ShaderLab占用疑问

1)ShaderLab占用疑问
​2)关于Android下ARM64和ARMV7的问题
3)关于ILRuntime相关的性能检测工具
4)字体加载问题
5)LZ4压缩模式下的资源打包网络


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

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

Shader

Q:我从官网下载了一分内置Shader,本身写工具刷了一遍,确认界面里面材质球已经没有引用内置Shader,而且把Standard Shader都清除了,从内存去看也没有这个,可是ShaderLab的占用仍是有点大,如今在主场景有47MB。工具

A1:变体太多就会这样,仔细看看那些不少关键字的Shader。

感谢deviljz@UWA问答社区提供了回答性能

A2:楼上说的对,分享一段几年前写的扫描工程Shader变体的代码,扫描一下,把Top前几的Shader改改就能降不少了。测试

[MenuItem("Find/GetAllShaderVariantCount", false, 20)]
    public static void GetAllShaderVariantCount()
    {
        #if UNITY_5_6
        Assembly asm = Assembly.LoadFile(@"D:Program FilesUnity_5.6.5f1EditorDataManagedUnityEditor.dll");
        System.Type t2 = asm.GetType("UnityEditor.ShaderUtil");
        MethodInfo method = t2.GetMethod("GetComboCount", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
        #elif UNITY_2017_1_OR_NEWER
        Assembly asm = Assembly.LoadFile(@"D:Program FilesUnity_2018.3.0f2EditorDataManagedUnityEditor.dll");
        System.Type t2 = asm.GetType("UnityEditor.ShaderUtil");
        MethodInfo method = t2.GetMethod("GetVariantCount", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
        #endif
        var shaderList = AssetDatabase.FindAssets("t:Shader");

        var output = System.Environment.GetFolderPath(System.Environment.SpecialFolder.DesktopDirectory);
        string pathF = string.Format("{0}/ShaderVariantCount.csv", output);
        FileStream fs = new FileStream(pathF, FileMode.Create, FileAccess.Write);
        StreamWriter sw = new StreamWriter(fs, Encoding.UTF8);

        EditorUtility.DisplayProgressBar("写统计文件", "正在写入统计文件中...", 0f);
        int ix = 0;
        sw.WriteLine("ShaderFile,VariantCount");
        foreach (var i in shaderList)
        {
            EditorUtility.DisplayProgressBar("写统计文件", "正在写入统计文件中...", 1f * ix / shaderList.Length);
            var path = AssetDatabase.GUIDToAssetPath(i);
            Shader s = (Shader)AssetDatabase.LoadAssetAtPath(path,typeof(Shader));
            var variantCount = method.Invoke(null,new System.Object[]{ s,true});

            sw.WriteLine(path + ","+variantCount.ToString());
            ++ix;
        }
        EditorUtility.ClearProgressBar();   //清除进度条
        sw.Close();
        fs.Close();
    }

感谢李星@UWA问答社区提供了回答字体

A3:URP有一套变体裁剪代码,拿来改改,加入你的打包流程会裁剪掉没用的变体(我估计你不少关键字用不到,因此应该会减很多)。

感谢Robot.Huang@UWA问答社区提供了回答优化

A4:推荐使用UWA的本地资源检测,看下哪一个Shader的变体多,是否是变体的问题,另外再确认一下是否是还有Shader的冗余。

感谢芭妮妮@UWA问答社区提供了回答网站

Build

Q:关于Android下ARM64和ARMV7的问题,从经验上讲,同一个Unity的游戏在这两个架构下会出现运行效率的差别吗?渲染效率会受到CPU架构的影响吗?ui

A:ARM64能解决不少因地址空间不足、内存分配时出现地址冲突而致使的内存分配失败的问题。比较典型的就是高通的Adreno显存不足,或者说字典这种容器类型大量使用致使的内存泄露问题。可是,伴随着的问题也就来了,一样的包64位比32位要大,对于对内存有严格要求的游戏,原本优化内存就已经够头疼了,换成64位忽然又涨了一截,一股苍白无力感又油然而生。至于效率问题,没测试过也没对比过,楼主能够测测FPS、温度、能耗等有多大区别。

感谢李星@UWA问答社区提供了回答

ILRuntime

Q:UWA已经出了针对Lua的性能分析,求ILRuntime,新项目打算改用ILRuntime,看中Await和Async来实现网络通信的“同步”代码,战斗部分的逻辑代码也打算在ILRuntime中实现(强CPU计算会尽可能用C#实现),可是性能方面略有担忧。如有性能分析工具特别是与C#相互交互部分,能够在初期定技术框架给本身一颗定心丸就行了。

另外,请问ILRuntime已经有哪些项目在线上成功应用吗?再就是稳定性方面能接过Lua的拉力棒担当重任吗?

A1:基本知足平常须要。其实底层机制仍是与Lua相似的,开发习惯和语言上会舒服很多。做为功能模块附加或者热更新功能仍是很不错的。不过性能方面没有很是针对性地去作测试,目前只能说知足项目须要。高计算量处理方面仍是不建议在ILRuntime作太多,基础缘由其实跟Lua问题仍是蛮相似的。

使用上来讲,要注意Adaptor的定义。还有热更新方面,不一样代码节点多是须要分别出ILRuntime的热更包。这个在出包管理上会烦琐一些,不过开发语言统一上仍是有很多好处的。

感谢阿里@UWA问答社区提供了回答

A2:性能方面其实不须要太大的担忧,分享一下个人经验:

  1. 必定要用Release方式去编译DLL,而且打开DISABLE_ILRUNTIME_DEBUG的宏;
  2. 因为解译执行,因此执行效率跟直接执行自然就有20-100倍的差距,太复杂的计算确定不行;
  3. 运行时也是纯C#的,因此用UWA工具就能检测出一些性能问题;
  4. 咱们项目安卓用的有原生DLL效率确定是比Lua要快的,iOS上面测试下来比Lua要慢一点,可是苹果设备以及IL2CPP的性能都不错,因此也能作到跑满帧;
  5. 对对象中的结构体赋值会有没法避免的GC,建议先转成本地变量,或者V3这种直接存成XYZ;
  6. Foreach会产生GC,写的时候不要用。

感谢萧小俊@UWA问答社区提供了回答

A3:知识搬运工芭妮现身,搬于某国内新一线大厂的大柴:
有朋友用这个作上线了还行,计算密集型不能胜任,计算密集型能够用Lua,双热更核心也是个值得参考的点子。

  1. 核心代码用C#,例如:物理系统模拟之于闪暖。
  2. 战斗库逻辑层用Lua,例如:秒算战报的回合制的战斗核。
  3. 业务逻辑用ILRuntime,例如:装备系统,升阶升星强化转生。
  4. 再套一层Injectfix,修非Burst的C#。

感谢芭妮妮@UWA问答社区提供了回答

A4:由于ILRuntime是C#实现的,因此直接看Profiler就能看性能消耗。

感谢终极大菜狗@UWA问答社区提供了回答

Resource

Q:我如今真机测试,在内存发现有两份字体的加载,一份是好比登陆界面,或者其余自己有字体的场景引用到的,引用的是原始的Font,另外一份我发现是由于预制体加载到场景,会引用一份复制出来的字体。这个要怎么解决?

A:若是预设体是从AssetBundle中加载的,场景却不是AssetBundle加载的,那么确定是会有两份的,由于普通的场景打包和AssetBundle走的是不一样的路线,是引用不到同一份字体资源的,一份是来自场景的Sharedassets,一份是来自AssetBundle。因此要么场景也走AssetBundle打包,要么场景中的用到这个字体的UI部分从AssetBundle动态加载。

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

Addressable

Q:LZ4压缩模式下,Addressables加载Bundle只会加载Headers到内存中,那么是否能够将全部资源打包成一个Bundle?这样就能够不用考虑资源粒度以及资源重复打包的问题了?

A1:若是是文件级别的资源更新,而且AssetBundle很大的状况下和从新下载整包没什么太大区别,资源粒度主要是为了方便减小更新资源量。

感谢郑骁@UWA问答社区提供了回答

A2:说一下个人总体思路,请大佬看看有没有什么隐患。

全部资源使用Addressable打成一个Bundle包,固定读取路径为UnityEngine.Application.persistentDataPath,即永远读取本地。舍弃边玩边下这个模式,实际体验起来,边玩边下会致使频繁的卡顿,体验很很差。

首包发布一个小包,游戏启动时检查资源更新,资源Bundle(包括后续的增量包)经过C#的HttpWebRequest下载(本身管理下载),支持断点续传,统一下载到persistentDataPath,下载完成后正式进入游戏流程。

优势:

  1. 资源管理简单。
  2. 不用考虑资源拆分粒度。
  3. 不用考虑资源重复打包。
  4. 不用考虑首次启动下载太多Bundle包致使的下载速度缓慢的问题。

缺点:
目前没想到有什么隐患,请你们帮忙指正。

感谢题主ShiltonLi@UWA问答社区提供了回答

A3:从资源卸载的角度来讲这样作是不太合理的。Addressable是通引用计数来处理卸载的,只有当AssetBundle的引用计数减小到0的时候才会触发,触发时会调用AssetBundle.Unload(true)。因此若是这个大的AssetBundle里面有一个资源须要一直常驻内存,就说明那个AssetBundle也须要常驻内存,那么其它用不到的资源,如某张短期使用事后就能够卸载的纹理,就卸载不掉了。固然这个说法的前提是用Addressable的加载接口和卸载接口来加载卸载资源。

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

封面图来源:Unity Shader Sketches
https://lab.uwa4d.com/lab/5b564b46d7f10a201fd903de
使用ShaderLab绘制草图。


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

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