UWA问答 | 博客 | 游戏及VR应用性能优化记录分享 | 侑虎科技 - ios
1）WorldSpace下的合批策略与ScreenSpace有什么区别 2）在iOS上用Metal取代OpenGL的多么 3）在动画蓝图中将两个或多个动画同时融合到同一个网格 4）Mipmap如何限定层级 这是第387篇UWA技术知识分享的推送，精选了UWA社区的热门话题，涵盖了UWA问答、社区帖子等技术知识点，助力大家更全面地掌握和学习。 UWA社区主页：community.uwa4d.com UWA QQ群：793972859 UI Q：WorldSpace下渲染Prefab做的HUD，如果只显示同一张图片，可以合批，如果再显示一个TextMeshPro， 直接全部都不能合批了。 【UGUI疑问】WorldSpace下的合批策略与ScreenSpace有区别吗？ 针对以上问题，有经验的朋友欢迎转至社区交流分享： https://answer.uwa4d.com/question/6645d42c5ce8a46b00fc4d3f iOS Q：苹果官方早就宣布放弃OpenGL了， 所以这年头用Unity开发iOS的用Metal取代OpenGL的多么？ A：苹果的软硬件统一要求非常严格，为了支持新的iOS系统和手机、包括方便渲染性能分析调试的话，现在应该普遍都是用Metal的了。 感谢Faust@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/6642c9595ce8a46b00fc4d35 Animation Q：需要明确的是，当我按下游戏手柄或控制器上的按钮X时，会播放按钮X的动画。如果我按下按钮Y并仍然按住按钮X，我希望看到两个按钮的动画同时播放，而不仅仅是一个动画。 我正在使用一个装配好的手柄和控制器网格，带有动画蓝图，使用状态机来调用和播放动画。 我已经在AnimGraph中尝试了几乎所有不同的混合节点。但是，只播放动画一（混合权重1）或动画二（混合权重2）。如果我设法将两个动画混合在一起（混合权重0.5），则会播放按钮x和y的动画，但只播放动画的一半。 请问，有没有办法在动画蓝图中将两个或多个动画同时融合到同一个网格（不同的骨骼）上？ A：使用Layered blend per bone，并在细节面板的图层设置中为每个混合姿势设置一个关节。 这样你就有了每个关节的Alpha值，并且动画可以与其他动画一起用于单个关节。 复现： 在ABP中用Layered blend per bone来组合不同的动作，上面的是主动作，下面是要叠加的动作。 在Layer Setup中设置受控制的关节名称。 这样就可以两个动作叠加在一起了。 针对以上问题，有经验的朋友欢迎转至社区交流分享： https://answer.uwa4d.com/question/664582e85c7f5d2c5805d3e3 Memory Q：请问Mipmap如何限定层级？ 比如一张1024x1024纹理，共有Mipmap0~10，但是项目只用到Mipmap0~2，如何省略掉3~10？ A1：用Texture2D.minimumMipmapLevel试试。 感谢vTHu9nLdTLZM@UWA问答社区提供了回答 A2：Texture Streaming理论上可以让你更节约一点点。 感谢王林@UWA问答社区提供了回答 A3：用mipCount这个参数试试。 new Texture2D(width:256, height:256, textureFormat:TextureFormat.ARGB32, mipCount:3, linear:true) 感谢给个30K的资深titleba求求了@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/65c0a61340a8d93b624afccc 封面图来源于网络 今天的分享就到这里。生有涯而知无涯，在漫漫的开发周期中，我们遇到的问题只是冰山一角，UWA社区愿伴你同行，一起探索分享。欢迎更多的开发者加入UWA社区。 UWA官网：www.uwa4d.com UWA社区：community.uwa4d.com UWA学堂：edu.uwa4d.com 官方技术QQ群：793972859
1）限制Unity帧率的方式 2）只在编辑器内，纹理不开启Read&Write情况下，如何获取纹理所有颜色值 3）如何在FBX剔除Lit.shader依赖 4）如何在iPhone 12mini设备上禁止竖屏 这是第373篇UWA技术知识分享的推送，精选了UWA社区的热门话题，涵盖了UWA问答、社区帖子等技术知识点，助力大家更全面地掌握和学习。 UWA社区主页：community.uwa4d.com UWA QQ群：465082844 Platform Q：目前我们想把游戏设置为30帧，是通过Application.targetFrameRate实现的；但是会有一些兼容性问题，比如一些设备会动态调整设备刷新率导致游戏帧率过低（比如设备从120HZ动态降为60HZ时，游戏就从30帧掉为15帧了），我们也尝试过跟进设备的刷新率变化动态调整Application.targetFrameRate，但是一些设备还是出问题，主要是一些支持高刷新的设备，如120HZ、180HZ，设备在标准模式下本身会动态调整刷新率的，节约能耗。 不知道大家有没有相关的经验或者更好的解决方案？ A：可以尝试挂一个Update脚本，估计可以跟上高刷新的设备120HZ、180HZ的动态调整刷新率。 感谢NG週@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/65bb481a3625c22cffcb1df0 Editor Q：只想在编辑器内优化一些纹理图片，纹理不开启Read&Write。 目前方案如下，但是会有几个问题： 1. LoadImage只支持PNG、JPG格式，像TGA、PSD格式则返回为空。 2. 对于那些几十MB的PNG纹理，也是返回空。 请问有无其他方式？ 代码如下： var texture = AssetDatabase.LoadAssetAtPath<Texture2D>(assetPath); var bytes = File.ReadAllBytes(assetPath); var new_texture = new Texture2D(texture.width, texture.height); var res = new_texture.LoadImage(bytes); if (res == false) { Debug.LogError($"错误提示：{assetPath}纹理资源LoadImage失败", texture); return null; } var colors = new_texture.GetPixels32(); // 获取到所需颜色数组 A1：可以试试以下方法： Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(assetPath); // 你的纹理 byte[] rawTextureData = texture.GetRawTextureData(); Texture2D finalTex = new Texture2D(texture.width, texture.height, texture.format, false); finalTex.LoadRawTextureData(rawTextureData); finalTex.Apply(); var colors = finalTex.GetPixels32(); // 获取到所需颜色数组 请注意，所有这些方法都是在绕过Read/Write Enable的限制时的替代品，而不是直接的解决方案。如果可能，最好还是在导入纹理时启用Read/Write Enable以获得更好的性能和更简单的纹理操作。 另外一个方法：可以设置一个Camera的TargetTexture为一个RenderTexture，接着使用Graphics.Blit将目标纹理渲染到这个RenderTexture上。然后，你可以通过ReadPixels函数将RenderTexture读取为Texture2D。这种方法不依赖于Read/Write Enable。 扩展阅读：《高效访问纹理数据，持续优化整体性能》 感谢NG週@UWA问答社区提供了回答 A2：我之前用过@NG週说的办法，是可行的，不过我当时只处理PNG图片。 另外离线处理纹理，可以考虑使用Job来并行化处理，效果很高。 感谢junbin.liu@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/65b320393625c22cffcb1de5 Asset Q：测试发现只能通过后处理才能去掉Lit.shader依赖，尝试使用AssetDatabase.LoadAssetAtPath(fbxPath)然后执行下面代码，并不能去掉依赖。请问还有什么其他办法吗？ protected void OnPostprocessModel(GameObject model) { var renderers = model.GetComponentsInChildren<Renderer>(); foreach (var renderer in renderers) { // 默认fbx会引用Lit.mat，会引起ab包冗余，导入时去掉 foreach (var material in renderer.sharedMaterials) { if (material != null && material.name == "Lit") { renderer.sharedMaterials = new Material[0]; } } } // 去掉fbx默认自带的材质球 ModelImporter importer = (ModelImporter)base.assetImporter; if (importer != null) { if (importer.materialImportMode != ModelImporterMaterialImportMode.None) { importer.materialImportMode = ModelImporterMaterialImportMode.None; importer.SaveAndReimport(); } } } A：可以试试在打包阶段，打AssetBundle之前，去掉Lit.mat对lit.Shader的依赖。 Cube.prefab，就是Unity默认的Cube做成的Prefab。 var prefabGO = AssetDatabase.LoadAssetAtPath<GameObject>(“Assets/Editor/Cube.prefab”); var renderer = prefabGO.GetComponent<Renderer>(); renderer.sharedMaterial.shader = null; 感谢范世青@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/65aa21893625c22cffcb1ddd iOS Q：使用的Unity引擎是2020.347f1，已经在打包时候设置了横屏，然后又使用了以下代码设置，其它机型没问题但对面的机器还是能竖屏。 Screen.orientation = ScreenOrientation.AutoRotation; Screen.autorotateToLandscapeLeft = true; Screen.autorotateToLandscapeRight = true; Screen.autorotateToPortrait = false; Screen.autorotateToPortraitUpsideDown = false; 想要禁止竖屏，设置横屏在安卓和大部分苹果上没问题，但在iPhone 12mini上却可以竖屏，请问还有其它方法吗？ A1：先确定iPhone 12mini的出包工程跟其他苹果设备的是否是同一个，接着排除有没有不小心在Xcode工程里面设置了竖屏模式，还有就是给iPhone 12mini装一个同类型的游戏，看看能不能横屏，排除是不是手机装了强制竖屏插件问题。 感谢NG週@UWA问答社区提供了回答 A2：遇到过一次，是手机系统的Bug，打开任何游戏都能切换横竖屏，重启下手机然后好了。 感谢jj@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/65b896bc40a8d93b624afca5 封面图来源于网络 今天的分享就到这里。生有涯而知无涯，在漫漫的开发周期中，我们遇到的问题只是冰山一角，UWA社区愿伴你同行，一起探索分享。欢迎更多的开发者加入UWA社区。 UWA官网：www.uwa4d.com UWA社区：community.uwa4d.com UWA学堂：edu.uwa4d.com 官方技术QQ群：465082844
1）2D项目大量物品图标Draw Call优化方案 ​2）UGUI SpriteAtlas的热更新问题 3）iOS平台突然有一帧UI渲染开销很高 4）iOS上频繁Crash，堆栈很奇怪 这是第288篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） Rendering Q：我们有个2D项目，大致布局如下图： 1.场景按格子划分，玩家可以在每个格子上面摆放物品，物品种类非常多（700+）。 2.部分物品还有动画效果，动画会改变该物品的材质属性。 3.物品图标的大小不是严格一个格子大小，因此会有部分物品图标间的重叠。 4.场景的视角可拖动，最远视距下可以看到超过100个物品。 5.场景上除了物品，还有云雾、水波、发光粒子等各种特效。 具体实现： 1. 场景底图采用美术分割方式，每张2048*2048大小，由16张组成，直接使用SpriteRenderer摆放渲染。 2. 物品图标每张256以内，同样采用SpriteRenderer摆放渲染。 3. 使用Unity内置渲染管线。 经过一番Profile，发现目前主要性能问题在于Drawcall数量非常大，没摆满的情况下都接近300，主要消耗点在于特效跟物品图标的渲染。 1.由于物品数量巨大（后续还会增加），目前采用SpriteAtlas方式把所有物品图标进行合图，会产生3张2048*2048尺寸的图集，各个物品可能会随意分散在这3张图里，加上物品穿插显示，导致无法合批。 2.物品有状态，不同状态会对材质属性进行变更，改变灰度明亮度等效果，导致无法合批。 3. 场景上的粒子特效是3D的，会随意在物品图标中移动穿插，导致图标无法合批。 已经考虑过，但否决了的方案： 1.把图标缩小，使生成的图集在一张2048以内。 => 询问过策划，物品种类目前还不是全部的，完整的配置里有超过1000+物品，都合成到一张2048里不现实。 2.图标不合图集，直接散图集成，采用运行时动态合图方式对场上物品进行合图。 => 游戏主要玩法会导致不停拖动物品图标以及旧物品的删除跟新物品的生成，操作会非常频繁，动态合图方式消耗巨大。 鉴于上面所描述的状况，各位大佬有没有什么推荐的优化方案？ A1：可以从以下方式入手： 首先图片和图集减少Draw Call没问题，图集也应该做分类，把能组合的类型分配并归类。图集不是追求少就好，应该是动静分离，还有按项目分类。做到图集数最优，这个就要结合自己的项目分析了。 然后合批的问题要解决。重写一个Shader，挂载到SpriteRenderer上，改变这个材质上的属性可以避免导致无法合批。 格子布局应该避免元素重叠，这个在设计就要避免的。粒子特效尽量用2D效果来做表现，粒子的发射数量与粒子数量也要做权衡。 感谢廖武兴@UWA问答社区提供了回答 A2：建议动态图集，静态图集在这种情况下，基本是负优化。 感谢uwa菜鸡奶泡泡.@UWA问答社区提供了回答 A3：这个问题，其实挺好解决。 1.背包的物品组件做一个循环动态列表功能，这样同屏加载不会很多。 2.物品的同一个组件进行拆分，比如bg一个图集， icon一个图集，数字图片一个图集，特效纹理一个图集。 这样下来DrawCall一般在三四个可以搞定。 感谢郑佳宇joe@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/6215b229e7172c2775f6f5c6 Atlas Q：UGUI图集切换后，图集中的图片名称不变，只是改变该图片为其他图片，但是为什么在加载UIPrefab的AssetBundle之后，UI上对应修改的图片会出现白图？会发现SpriteAtlas的CanBindTo返回false。 A：替换图片时，不修改原GUID则可以避免这个问题。 感谢题主Austin@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/621c3e1be7172c277500573d UGUI Q：iOS平台通过Profile定位性能，偶现某一帧UI开销异常高，通过Timeline看到是Render引起的，但是不知道后续应该如何定位。 这里可以看到这一阵Render开销达到了12.35ms，其他帧只有不到2ms。 A：EmitWorldScreenspaceCameraGeometry（图中紫色）这个函数是UGUI的Canvas网格重建生成UI Draw Call的开销，主要工作在Native子线程进行，主线程表现为该函数的等待开销，建议排查该时刻是否有较为复杂的UIPanel创建（结合Profile的UI模式）。 感谢羽飞@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/6215fde7e7172c2775f76fd9 iOS Q：在线上FireBase收集到不少的iOS Crash。Crash的栈有很多种，但共同点是通过Il2CppInvokerTable.cpp的第4336936768行（一个不合理的行号）指到了某个函数，之后可能会调用自身若干次，再跳转到一个不确定的位置Crash掉。我们尝试过给该函数做过保护修复，但发布后还s会Crash，调用又全部换成了另一个函数。所以怀疑并不是某个函数本身的问题。 大部分是后台触发，但也有前台触发的。大部分系统剩余内存不多（<100MB），但也有剩余超过1GB的。系统版本主要是iOS 15，我们有接入一些iOS原生的SDK。 版本信息： Unity 2018.4.30 IL2CPP 只有iOS 怀疑有某个函数指针的指向错误导致，但如何继续定位问题呢？ A1：FireBase上面对IL2CPP部分的堆栈还原是有Bug的，基本看不出来是哪个堆栈，可以尝试下通过添加自定义事件和Log查看大概在哪崩溃的，然后再尝试重现和修复。 这个从Unity的堆栈上面来看，是挂在某个线程了。 我年前给FireBase团队提的Bug，对应的issue在这里：https://github.com/firebase/quickstart-unity/issues/1200 感谢梅辰@UWA问答社区提供了回答 A2：建议添加一下Unity的符号表。 感谢郑佳宇joe@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/62130bdce7172c2775f35d30 封面图来源于：Simple inventory system for unity Unity3D的背包系统。 今天的分享就到这里。当然，生有涯而知无涯。在漫漫的开发周期中，您看到的这些问题也许都只是冰山一角，我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入，也许你的方法恰能解别人的燃眉之急；而他山之“石”，也能攻你之“玉”。 官网：www.uwa4d.com 官方技术博客：blog.uwa4d.com 官方问答社区：answer.uwa4d.com UWA学堂：edu.uwa4d.com 官方技术QQ群：793972859（原群已满员）
1）SRP Batch合批失败 ​2）Unity增量打包AssetBundle没变化的资源也会被重新打包 3）如何查找il2cpp.so代码段映射的内存突然变大的问题 4）iOS画面不明原因freeze 这是第283篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） SRP Q：最近尝试用SRP Batch，但感觉非常难以捉摸。这里所有的物体都是用的同一个Shader，而且关键字也都一样，也就是同一个变体。按说应该可以合并Batch的，但第二个提示Shader的关键字不同，SRP合并失败。 在网上查了一些资料，没有有用的信息。自己试了一下，只要改其中的一些RenderQueue，SRP Batch的结果就有变化（不能合并的数量变少了）。 但是，RenderQueue不能随便改吧？会影响性能。而且对于半透的来讲，渲染结果都会错。更何况改起来非常麻烦。各路大神们，想了解一下大家是怎么解决这个问题的？另外，大家的项目有没有用SRP Batch？还是用的传统的Static Batch？ 有人提醒，把光图去掉试试，虽然的确有用，但总不能去掉光图吧？ 又试了一下，专门把这些结点单独烘一下，也有用。看来跟光图也没直接关系。 A1：这个应该是mat序列化文件里残留的关键字导致，Unity的Bug。 比如说：美术先用创建一个材质a，用的lit shader，调整自发光设置，导致材质里多了一个关键字_EMISSION，然后美术把这个材质改成了自定义Shader。这时候就算你的自定义Shader里没有_EMISSION这个关键字，材质的序列化文件里还是会记录下来。 然后再创建一个材质b，和材质a属性完全一样，只是没有残留的关键字_EMISSION，你会惊讶的发现材质a与材质b不能SRP Batcher，原因写：Node use different keywords。并且这时候你用Frame Debuggger去看这两个材质的DrawCall，你是看不到_EMISSION这个关键字的，因为实际上确实没用到。 感谢deviljz@UWA问答社区提供了回答 A2：感谢回复，确实是mat文件里存储的关键字导致的问题，如图： 修改关键字后，两个SRP Batch变成一个了： 另外，补充一下，之前说的改RenderQueue就能解决部分问题，中间确实是这样。但后来经过测试，我把整个的光图重新烘了一下，问题就解决了。中间做了什么已经不清晰，原因未知。不过，半透的东西我还需要再确认一下是不是改keywords就没问题了。 现在大致摸到门路了，如果Batch和Batch之间上下紧挨着，变体又是一个，就是关键字的bug问题。如果并不是紧挨着，变体虽然是同一个，也不能合并Batch。这时，需要先调整RenderQueue，让它们渲染次序紧挨着，Batch才可能会合并，和NGUI调整图层可以优化性能意思差不多。 其实只要把材质使用的Shader里没有的关键字删除就可以了： public static void RemoveRedundantMaterialShaderKeywords(Material material) { List<string> materialKeywordsLst = new List<string>(material.shaderKeywords); List<string> shaderKeywordsLst = new List<string>(); var getKeywordsMethod = typeof(ShaderUtil).GetMethod("GetShaderGlobalKeywords", BindingFlags.Static | BindingFlags.NonPublic); string[] keywords = (string[]) getKeywordsMethod.Invoke(null, new object[] {material.shader}); shaderKeywordsLst.AddRange(keywords); getKeywordsMethod = typeof(ShaderUtil).GetMethod("GetShaderLocalKeywords", BindingFlags.Static | BindingFlags.NonPublic); keywords = (string[]) getKeywordsMethod.Invoke(null, new object[] {material.shader}); shaderKeywordsLst.AddRange(keywords); List<string> notExistKeywords = new List<string>(); foreach (var each in materialKeywordsLst) { if (!shaderKeywordsLst.Contains(each)) { notExistKeywords.Add(each); } } foreach (var each in notExistKeywords) { materialKeywordsLst.Remove(each); } material.shaderKeywords = materialKeywordsLst.ToArray(); } 用工具改完之后，在编辑器上看，效果还是可以的。一个相机看整个场景，CPU渲染性能提升接近20%。 感谢题主仇磊@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/61deac0ad8413e18eb7f87a6 AssetBundle Q：项目中使用Git进行版本管理，在每次生成AssetBundle时都是使用 BuildAssetBundleOptions.Determinestic对所有的资源生成AssetBundle，并且生成的缓存目录都是统一的。但是发现在切换Branch后，本身没变化的资源生成的AssetBundle发生了变化。 通过Editor/Data/Tools中的webextract和binary2text工具对比发现其中的preloadIndex发生了变化，但实际上资源没有变。 请问大家的项目中对于AssetBundle增量打包有好的方案吗？还是需要手动管理每一个变化的资源再进行AssetBundle的生成？ A：通过版本管理维护好每一次增量打包的AssetBundle和Library应该能解决不同分支/不同机器增量打包的问题。 比如： 第一次打完上线包：上传Assetbundle + manifest + Library； 第二次打包前，重置并拉取最新的Assetbundle + manifest + Library，资源发生变化的AssetBundle包才会被重新打包；上线后再上传Assetbundle + manifest + Library； 感谢Richard Yu@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/615538998f8c834241c3dbdd IL2CPP Q：各位大佬问一个问题，就是最近的两个版本发现我们的il2cpp.so这个库mmap内存变大了，这块有什么好的办法查吗？ 1. 不是Mono内存变大 2. 静态文件il2cpp.so本身没变大 3. 也不是数据段变大 不知道是谁用到了特殊的代码。请问有什么好的排查方法吗？试过二分法，如下图：79456k这个值是异常的，正常下只有35808k。 iOS下并无明显异常，只是安卓有问题。 用的很多方法都没查到，后面在测试时，让测试同学切后台，再开很多新的应用（这时mmap的内存应当会降下去），再把应用杀掉，如果这个mmap的内存降了不再涨，让测试同学就把问题的优先级降了。 原本的思路是想： 1. 通过物理内存—>找到对应的虚拟内存地址，再算出偏移---->对应.so的地址，再找到目标代码---->再找到源代码的，失败了。 2. 使用二分法的话，有操作系统在干扰，不能必现。 如果后面有同学有想法或方法能查到增大部分的内存对应的代码的，可以一起讨论一下。 A：有个思路： 先看下进程的maps，一般一个so有3个映射，看看是不是可执行段（权限带x的）变大了，顺便记一下基地址，如果是： 可借助bugly符号表工具导一份il2cpp.so的符号表出来，符号表是文本格式的，可以知道任意地址范围对应的符号是什么。 拉一个游戏进程的smaps，过滤出il2cpp.so的地址范围，减上面的基地址。 写个小工具标出2里的范围对应1里的符号范围，能得知大概哪些代码进page了。 感谢littlesome@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/617262f78f8c834241ea604b iOS Q：我们最近升级Unity到2019.4.29f1，在iOS上（目前发现的是iPhone 12 Pro + iOS 14.7.1）某些时候画面freeze，无法恢复只能退出。但是，只是画面被freeze（画面完全不动），逻辑仍然在跑（后端收到了网络包等，而发送网络包是在客户端主线程），所以排出了主线程死循环的问题。 请问这可能是什么原因呢？是某种Shader问题引发的GPU挂起么？ A：我们之前遇上过，原因是由于Shader报错导致系统crash，现象是画面卡死，Log会刷IOAF code 4。我们之前的解决方法可以参考：https://zhuanlan.zhihu.com/p/335293011 感谢梅辰@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/617232f28f8c834241ea1775 封面图来源于网络 今天的分享就到这里。当然，生有涯而知无涯。在漫漫的开发周期中，您看到的这些问题也许都只是冰山一角，我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入，也许你的方法恰能解别人的燃眉之急；而他山之“石”，也能攻你之“玉”。 官网：www.uwa4d.com 官方技术博客：blog.uwa4d.com 官方问答社区：answer.uwa4d.com UWA学堂：edu.uwa4d.com 官方技术QQ群：793972859（原群已满员）
1）DLL混淆问题 ​2）Unity主程如何做项目管理 3）将ASTC格式转换为png格式 4）iOS 14在iPhone正常，但在iPad上会卡住 这是第276篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） Scripting Q：如果不用收费软件和加固，我们自己使用免费软件，如何对DLL进行混淆。 注：之前是用Microsoft.NET/Framework64/v3.5/csc进行打DLL，但是今天我回顾一下发现，DLL并没有混淆。 A1：若在Unity上使用，可以参考开源的方案：Unity Obfuscator Demo 简介 这是一款基于Mono.Cecil库，对C#编译后程序集进行IL代码注入实现的轻量Unity混淆插件，混淆发生在编译后，开发过程无需关心。此插件已在带Lua热更方案的商业MMO手游项目上验证过可行性。 主要功能 对命名空间、类、属性和字段的命名混淆 插入垃圾代码 在原代码中插入对垃圾代码的调用 特色功能 命名混淆支持随机字符串或从词库抽取名字 支持随机种子，可实现重复Build后混淆结果一致 支持黑白名单，排除部分在混淆后不能正常工作的代码，确保项目正常运行 混淆后输出混淆前后的名字对应关系文件 支持多DLL 感谢马三小伙儿@UWA问答社区提供了回答 A2：可以看一下AssetStore上的插件，我之前有个项目也用过： https://assetstore.unity.com/packages/tools/utilities/obfuscator-free-89420 免费版基本上可用： https://assetstore.unity.com/packages/tools/utilities/obfuscator-48919 收费版支持IL2CPP，支持程序集定义文件。 感谢萧小俊@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/61922be9d8413e18eb14a43f Unity Q：Unity主程如何做项目管理？比如资源管理、代码管理和工程管理。可以从多个维度讨论下吗？ A1：资源还是比较简单的，首先按照功能或者需求进行文件夹分类，资源的格式可以写一些AssetPostprocessor的代码来强制转换，整个工程的资源管理自动化。 开发的人员比较多，又对代码质量有一定要求，可以考虑用Git，不要用SVN，主程负责Review所有PR的代码，然后定期进行UT和BVT。 工程管理也可以依赖于Git的Tag和Branch来管理，尽量保证每个版本都是ZBB。 主程要做的事情还是蛮多的，简单写了一下，欢迎大家来讨论。 感谢萧小俊@UWA问答社区提供了回答 A2：身为一个合格的主程，我觉得应该具备以下素质： 1.首先是技术方面，就当独当一面，一马当先。 强大的技术支撑是要具备的，这里其实也可以细分，一个是专业性和广度。先提升某一方面的专业度，同时了解学习新技术，在不同领域的知识要有相对的了解。 2.再之就是管理方面，抓主线，控支流。 应该有好的项目框架。框架是为了更好的迭代和规范项目。一切都是为了开发跟成品服务的。所以不管代码规范，资源管理，甚至是使用习惯，都要遵循简单易用，通俗易懂为原则。比如开发了一个工具，功能非常强大，但是没人会使用它。那意义就大打折扣了。 技术上没有捷径，全靠努力跟积累。管理上需要自己思维上变通，多做尝试。但是有一点我觉得要注意，不能什么都面面俱到，主程是要把控大方向的，不能什么都要干预，适当放手，要培养人，不是带人。这样团队才有创新力，团队成员才会有成就感。而不是个人成就。管理是门大学问，不像技术可以有固定的学习思路。需要自己不断探索，才会有自己的风格和魅力。 感谢廖武兴@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/61947fe3d8413e18eb17e003 Texture Q：.astc类文件如何转换为.png文件，Windows操作系统。 A：ARM提供了压缩ASTC和解压的工具。 对应命令： 压缩：astcenc-sse2.exe -cl origin.png example.astc 6x6 -medium 解压：astcenc-sse2.exe -dh example.astc example.png 可以参考：https://github.com/ARM-software/astc-encoder 感谢范世青@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/61925149d8413e18eb14e0cb iOS Q：在iOS上遇到了一个比较棘手的问题，我们的游戏在iPhone上能正常跑，但是在iPad上会卡在进入主城的加载界面中，具体的表现是这样的： 1. 测试的iPad型号，2台A12处理器，1台M1处理器 2. iOS版本，全部都是iOS 14.8 3. 结果： 其中一台iPad A12处理能够正常运行，其余两台IPad都在加载中卡住。 4. 出错的表现为：在进入加载界面之后，会卡住在界面，但其实CPU逻辑是在跑，只是GPU因为渲染错误导致无法更新的画面信息，主要依据是在xCode Capture的时候，是能够正常看到主界面的已经在渲染，点击到相应的屏幕位置，Caputure也能看到UI能正常响应，只要退出Capture继续运行，还会回到加载界面。 5. 报错的Log： Execution of the command buffer was aborted due to an error during execution. Ignored (for causing prior/excessive GPU errors) (IOAF code 4) 不知道大家有没有遇到过类似的问题，或者说有没有什么建议，谢谢！ A：可以参考梅辰写的《解决iOS GPU报错导致游戏卡死IOAF code 4》 感谢马古斯@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/6193beedd8413e18eb16cbdf 20211122 更多精彩问题等你回答～ Unity增量打包AssetBundle没变化的资源也会被重新打包 在模型有UV2的情况下开启Generate Lightmap UVs 如何实现AAB包的增量更新 封面图来源于：Unity Obfuscator Demo Unity代码混淆插件使用demo。 https://lab.uwa4d.com/lab/5e94d57e0f247485d923d7d2 今天的分享就到这里。当然，生有涯而知无涯。在漫漫的开发周期中，您看到的这些问题也许都只是冰山一角，我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入，也许你的方法恰能解别人的燃眉之急；而他山之“石”，也能攻你之“玉”。 官网：www.uwa4d.com 官方技术博客：blog.uwa4d.com 官方问答社区：answer.uwa4d.com UWA学堂：edu.uwa4d.com 官方技术QQ群：793972859（原群已满员）
1）TextMeshPro备用字体疑问 ​2）iOS的部分语言的float分隔符变成了逗号 3）ASTC格式支持与官方文档不符 4）关于音效背景音乐的音频文件的格式设置请教 5）LightProbe的信息位置 这是第269篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） Text Q：TextMeshPro设置的Fallback “字体B”， 文本字体是“字体A”，如果文本显示的字符都是字体A的，CPU会不会收集字体B的贴图信息数据发送给GPU用来渲染？ 不是很理解这个Fallback字体，发现字体A、字体B都在内存中，也就是说其实都是关联上的。是不是所有的后备字体都会在内存中出现？ A：问题一：TMP中所谓Fallback，也就是后备字体，其含义在于当实际使用中出现了当前字体所不支持的字符时，按照：主字体（也就是当前字体）、主字体的后备字体、后备字体的后备字体、通用后备字体、通用后备字体的后备字体、通用默认字体、通用默认字体的后备字体等等的序列遍历所有设置的后备字体，直到找到能够支持的字体为止。 所以，引擎只有在内存中保留Fallback字体资源，才能在当前字体无法显示所有字符时采用Fallback字体。问题中提到的字体B也在内存中是合理的。 当然，如果开发者能确定字体A可以支持项目中出现的所有字体，那么完全可以检查Project Settings中全局的Default Font Asset、全局的Fallback Font Assets List、字体A的Fallback Font Assets，以上三处设置为空，则可以一定程度上节省内存。 问题二：我补充做了实验。对照情况是用某一种主字体显示“New Text”这一串字符，显然足够支持、而内存中也只有该主字体。然后在刚才提到的主字体的后备字体、后备字体的后备字体、通用后备字体、通用后备字体的后备字体、通用默认字体、通用默认字体的后备字体这个序列的每个环节加上不同的字体，显然它们没有被实际用到，但都进入内存了。List里面有几种字体也是一样。 感谢Faust@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/61455c7a8f8c834241ad6caf iOS Q：最近我们打包的时候发现，在iOS设备上，部分语言的小数的分隔符变成了逗号，比如俄罗斯语。后来发现是因为CurrentCulture变成了设备的语言，Android和之前的iOS设备都是en-US，也就导致了读取配置时用float.TryParse会转换失败。 我们的Unity版本是2018.4.33，目前还没有定位是什么原因导致的，不知道有没有人碰到过？如果在游戏启动时强制把CurrentCulture改成英语不知道可不可行？ A：我们项目踩过这个坑，原因就是一些语言里面小数点分隔符不一样，比如法语里分隔符是逗号，属于文化差异。解决方案是游戏启动时设置CurrentCulture为CultureInfo.InvariantCulture： CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture; CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture; Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; 参考链接：CultureInfo.InvariantCulture 感谢张迪@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/614bf82a8f8c834241b6484d Texture Q：ASTC格式支持与官方文档不符，根据官方文档（https://docs.unity3d.com/Manual/class-TextureImporterOverride.html）。理论上我们的测试机中，红米2是不支持的ASTC格式的。但实际测试中发现，它是支持的。这是怎么一回事？ A：之前做过相关的测试，红米2（Adren 302）是支持ASTC的，但红米Note2（PowerVR Rogue G6200）是不支持的。并且从Unity 2017.4的Profiler中可以看到纹理的大小是正确的。 这和官方提供的：tvOS (all), iOS (A8), Android (PowerVR 6XT, Mali T600 series, Adreno 400 series, Tegra K1)不符。 从目前的测试来看，可以认为实际支持情况和文档提供的GPU型号并不完全一致。在不支持的机型上会软解成RGBA32或RGB24，实际内存也是一样。 感谢OCEAN@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/613acc768f8c8342419e93fd Audio Q：在UWA的报告中看到要用Streaming的方式读取音频。想问一下关于音频格式，有优化角度比较全的建议吗？ 之前项目里的设置大概是这样子的，合适吗？大家常见的做法是怎样的？有没有一个相对合理的经验值，比如10s的音效大小在100KB这样的参考值？ A：并不推荐使用MP3播放音乐，原因是使用MP3制作素材会无法避免在循环点引入空白音频，参见：https://sound.stackexchange.com/questions/25846/is-it-possible-to-loop-mp3-without-gaps 之前使用过类似于MP3Loop的小工具，但是编码质量也无法控制，最后选择用Ogg（Vorbis）一了百了。 早一些的开发者（1990-2000年前后）会采用MIDI，但MIDI只是记录音乐信息用的格式，实际发声取决于所使用的音源，而音源设计通常会倾向于大而全所以为了有限的MIDI音乐加载完整的音源也会造成资源冗余。 关于PCM或者ADPCM，通常被称为WAV及“三分之一的WAV”，可以根据音效具体内容来决定优化策略，有一个概念需要了解——奈奎斯特采样定理。 简单讲，如果一个声音比较低沉，那么可以适当降低采样率来提升PCM或者ADPCM的“压缩比”，这样可以既保留PCM/ADPCM的低功耗和快速响应，又降低资源占用。假设一个声音比较明显的能量都分布在4000hz之下，那么只需要8000hz的采样率就可以非常好的记录及还原这个声音了。 事实上Unity原声音频最理想的音乐格式是Tracker Module，只是国内开发者了解Demo Scene的比较少，音乐创作者为此类格式创作的经验也非常稀少。 这里贴一个Tracker音乐的外网视频连接，大家可以听一下看看会不会唤起一些童年回忆：https://www.youtube.com/watch?v=gHQYYh7J1O4 翻译了Unity官方十一年前的一篇Blog：《.mod in Unity》 文章的中文翻译可以戳原问答查看。 几个常用Tracker音乐制作软件的网站链接：OpenMPT，MilkyTracker，schismtracker。有兴趣的朋友可以尝试一下用这种古老的格式创作音乐，可以做到既不牺牲音质也不占用多少空间。 关于进一步的音频优化技巧，个人比较推荐刷一遍Wwise的251认证课程内容，免费而且实际上都是些通用的技巧：https://www.audiokinetic.com/zh/courses/wwise251 感谢Icarus@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5c189a63bf256b207515158b Rendering Q：场景中的LightProbe信息是保存在lightingData.asset文件中吗？ A1：如果要保存，可以考虑这样存： AssetDatabase.CreateAsset(Instantiate(LightmapSettings.lightProbes), “Assets/lightProbe.asset”); 感谢萧小俊@UWA问答社区提供了回答 A2：不确定，lightingData.asset中主要存放Lightmap的对应关系，但LightProbe是否也在里面就不确定了。 感谢OCEAN@UWA问答社区提供了回答 A3：对于LightProbes更多的操作可以参考这篇文章：《聊聊LightProbe原理实现以及对LightProbe数据的修改》 感谢Xuan@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/6139d52c8f8c8342419d3885 20210927 更多精彩问题等你回答～ Vulkan API的性能及兼容性 Unity TMP字体方案如何选择 如何实现AAB包的增量更新 封面图来源于网络 今天的分享就到这里。当然，生有涯而知无涯。在漫漫的开发周期中，您看到的这些问题也许都只是冰山一角，我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入，也许你的方法恰能解别人的燃眉之急；而他山之“石”，也能攻你之“玉”。 官网：www.uwa4d.com 官方技术博客：blog.uwa4d.com 官方问答社区：answer.uwa4d.com UWA学堂：edu.uwa4d.com 官方技术QQ群：793972859（原群已满员）
1）Lua与C#传参 ​2）Unity发布iOS版本出现屏幕问题 3）安卓的View成为Unity界面的一部分 4）Unity升级导致项目启动时间过长 5）Unity中Cascaded Shadows在移动端的设置 这是第258篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） Lua Q：游戏中是先在Lua中String.format好再传入C#，还是在Lua里把参数传入C#，在C#里用String.format好？ 即一个是Lua加载文字表，String.format后传给C#显示，另一个是C#读表，Lua把参数传给C#，再string.format使用，哪个方式更好些，或者有没有其他更好的方式？ A1：搬运群里大佬的问答：第二种比较好，因为传参越简单越好，参数可以打包传。 感谢Tao@UWA问答社区提供了回答 A2：可以参考一下这篇文章：《用好Lua+Unity，让性能飞起来——Lua与C#交互篇》，总之Lua与C#传参，优先考虑int、float和double等类型，其次bool、string及object等类型，同时尽可能降低交互次数。 感谢羽飞@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/60e41d96e58b4719dd3e2916 iOS Q：Unity发布iOS版本在iOS 11之后出现屏幕显示问题：半屏被压缩，另一半黑屏。 A：直接在编辑器中设置这几个参数，不要在代码中设置这个，7p就不会出现这个问题： Screen.autorotateToLandscapeLeft = true; Screen.autorotateToLandscapeRight = true; Screen.autorotateToPortrait = false; Screen.autorotateToPortraitUpsideDown = false; Screen.orientation = ScreenOrientation.AutoRotation; 感谢许家胜@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5ab9ef650b827e2c0bfdd1b6 Unity Q：加载了一个安卓的Activity，会遮挡住Unity的界面，如何让安卓的View，成为Unity界面的一部分呢？Unity界面的一部分使用安卓原生SDK的界面实现。 A：安卓混合Unity的界面，已经完成了。 https://blog.csdn.net/Yzw_92_4_11/article/details/68952529 感谢题主韩飞@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/60e6caa7e58b4719dd3e296b Editor Q：查看了Unity的editor.log发现里面： RefreshInfo: InitialScriptRefreshV2(NoUpdateAssetOptions) RefreshProfiler: Total: 0.000ms InvokeBeforeRefreshCallbacks: 1115393.587ms ...... OnSourceAssetsModified: 340.325ms ...... ImportAndPostprocessOutOfDateAssets: 1032441.185ms (82533.117ms without children) ImportManagerImport: 82501.381ms (0.000ms without children) ...... 有没有大佬知道这个是在处理什么东西？科学上网了也没有查到相关信息，这里看耗时就很长时间了1115393.587ms。 A：参考以下几点： 检查一下项目是不是放在机械硬盘上，建议放NVME的固态上。因为高版本的数据结构更复杂了，不用固态来不及序列化。 检查一下是不是开了PlasticSCM。 感谢萧小俊@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/60e2afece58b4719dd3e28ed Rendering Q：Unity的Shadow Cascade功能在移动平台中是否生效？ 在场景使用了Unity自带的实时阴影，具体参数如下： 用Frame Debug观察阴影绘制过程： Shadowmap为1024＊1024，场景远处会有黑色的阴影覆盖。 当Cascade设置为2则远处阴影消失： 用Frame Debug观察阴影绘制过程： Shadowmap还是1024＊1024，但一分为二，各占1024＊512。 以上是在PC上验证的，证明Cascade确实起作用。但当在Unity编辑器中的BuildSettings中切换到Android平台时，无论怎么修改Cascade的值，场景远处均有阴影，用Frame Debug观察阴影绘制过程如下： 似乎在安卓平台中这个参数不起作用，查阅Unity官服文档也并没说明Shadow Cascade不支持移动平台。 请问有同样遇到这种问题的吗？ A：Graphics设置那里需要在对应的Tier里面启用Cascaded Shadows。 感谢题主x21@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/60e7fa6d038436106ddf2955 20210712 更多精彩问题等你回答～ 1.如何实现AAB包的增量更新 2.关于Unity出AAB包的问题 3.RTS 手游技术难点 封面图来源于网络 今天的分享就到这里。当然，生有涯而知无涯。在漫漫的开发周期中，您看到的这些问题也许都只是冰山一角，我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入，也许你的方法恰能解别人的燃眉之急；而他山之“石”，也能攻你之“玉”。 官网：www.uwa4d.com 官方技术博客：blog.uwa4d.com 官方问答社区：answer.uwa4d.com UWA学堂：edu.uwa4d.com 官方技术QQ群：793972859（原群已满员）
1）多个Submeshes模型合并，显示异常 ​2）Addressable如何删除旧资源 3）对NGUI字体错乱的解决方案 4）GLSL link error: L0010 Uniform '_Color' differ on precision 5）iOS键盘上的输入框提示内容如何去掉 这是第233篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） Script Q：测试一个Skinmesh合并功能，发现当Mesh包含多个Submeshes时，合并成功后，无法渲染显示出来。当测试的Mesh不包含Submeshes时，可以合并显示。难道CombineMeshes只能合并不带Submeshes的Mesh？ 注：不管是使用r.sharedMesh.CombineMeshes(combineInstances.ToArray(), false, false)；带上所有材质，还是r.sharedMesh.CombineMeshes(combineInstances.ToArray(), true, false) ；合并一张贴图材质，带多个Submeshes的模型只能合并无法渲染显示出来。不带多个Submeshes的模型却能够正常合并显示。 A：测试发现，需要对每个CombineInstance重新指定三角面，才能正常显示带多个Submeshes的模型。如下代码： foreach (SkinnedMeshRenderer smr in allSkineMeshList) { for (int sub = 0; sub < smr.sharedMesh.subMeshCount; sub++) { CombineInstance ci = new CombineInstance(); ci.mesh = smr.sharedMesh; ci.mesh.triangles = smr.sharedMesh.triangles; //这里重新指定 ci.subMeshIndex = sub; ci.transform = matrix * smr.transform.localToWorldMatrix; combineInstances.Add(ci); } 感谢题主牛头人不服@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5fe55b1a10a17c6c2b09d778 Addressable Q：目前计划使用Addressable来实现资源热更新，实际真机测试发现当资源更新后，旧的资源Addressable并不会把它删除，同时可以看到App占用的数据文件会越来越大。请问有什么办法可以把指定的Group或Label的资源删除吗？ A：我们用的是覆盖式更新的流程（不是增量更新），Addressables版本是1.15.1。在把Bundle Naming设置为Filename后发现，在Caching中的AssetBundle目录还是带有 Hash值的。 图中可看到AssetBundle包名已经是Group的名字了，但是下载到Caching中还是有Hash。 然后我们是这么解决的：还是开启文件名的Hash，将Caching中的AssetBundle文件夹名保存到PlayerPrefs中，当检测到有下载的时候，读出PlayerPrefs中的值，把旧的对应AssetBundle包删除，并更新PlayerPrefs。 获取当前Catalog中所有AssetBundle文件夹名的方法，是从Addressables中复制出来的。 // 获得当前catalog中所有 assetbundle 保存的文件夹名 // 这个函数中引用到的方法没有列出，可以去 addressables 中源码中找 // 示例：CollectBundleNames(new string[]{ "SkllIcons", "ItemIcons", "AvatarIcons" }) private static List<string> CollectBundleNames(object[] keys) { List<string> result = new List<string>(); #if ENABLE_CACHING foreach(var key in keys) { IList<IResourceLocation> locations; if (key is IResourceLocation resourceLocation && resourceLocation.HasDependencies) { foreach (var dep in resourceLocation.Dependencies) { if (dep.Data is AssetBundleRequestOptions options) { result.Add(options.BundleName); } } } else if (GetResourceLocations(key, typeof(object), out locations)) { var deps = GatherDependenciesFromLocations(locations); foreach (var dep in deps) { if (dep.Data is AssetBundleRequestOptions options) { result.Add(options.BundleName); } } } } #endif return result; } 删除AssetBundle包文件夹的方法： // 这里的 bundleName 就是 CollectBundleNames 的返回值 private static void ClearCacheForBundle(string bundleName) { List<Hash128> hashList = new List<Hash128>(); Caching.GetCachedVersions(bundleName, hashList); foreach (Hash128 hash in hashList) { Caching.ClearCachedVersion(bundleName, hash); } } 需要注意的是调用CollectBundleNames的时机，如果已经更新了Catalog，那么返回的是即将要写入Caching中的AssetBundle文件夹名。如果要得到当前AssetBundle文件夹名，要在更新Catalog之前调用。 感谢jim@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5ee9ea195d07d80acd262421 Script Q：对NGUI字体错乱有什么好的解决方案吗？ A：究其原因是NGUI的代码逻辑Bug。 NGUI文字破碎 NGUI_DynamicFont_Bug_Fix 感谢毛尹航@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/58d2558d7dc35e7f0efb4728 Rendering Q：Android真机报错，表现未发现异常，但是Bugly检测到报错日志： 相关信息： 异常进程#线程：com.go7game.jewelclassic#main(1) 用户 ID：unknown 发生时间：2020-12-23 15:10:53 上报时间：2020-12-23 14:11:21 应用包名：com.go7game.jewelclassic 应用版本：1.20.11 使用时长：39 秒 前后台状态：前台 设备机型：金立 M5 系统版本：Android 6.0,level 23 ROM：LEAGOO/full_wf562k_leagoo CPU架构：armeabi-v7a 报错的详细信息请戳原问答查看。 A：问题中有提到这个Error是金立M5上发现的，从网上资料可以查到这款手机的SoC为联发科MT6735，对应的GPU为Arm Mali-T720。 Google类似问题时发现有几个类似问题会出现在部分Mali设备。 https://github.com/cocos2d/cocos2d-x/issues/17256 https://forum.unity.com/threads/glsl-link-error-l0010-uniform-_-differ-on-precision.639451/ 所以猜测是由于GPU硬件或者驱动导致的浮点数精度的问题。上面帖子里也有提到一些能绕过这个Bug的方案，可以参考下。 感谢范君@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5fe2e55f10a17c6c2b09d743 iOS Q：iOS平台，NGUI输入框中的默认内容会显示在键盘上，这栏怎么去掉，请指导一下。 A1：iOS可以修改XCode工程中的Keyboard.mm代码定制。 感谢Kenji@UWA问答社区提供了回答 A2：遇到类似问题，是接入第三方SDK导致的。 感谢谢志勇@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5fd096f610a17c6c2b09d5bd 封面图来源：GLTFUtility https://lab.uwa4d.com/lab/5bc4223b04617c5805d4d437 今天的分享就到这里。当然，生有涯而知无涯。在漫漫的开发周期中，您看到的这些问题也许都只是冰山一角，我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入，也许你的方法恰能解别人的燃眉之急；而他山之“石”，也能攻你之“玉”。 官网：www.uwa4d.com 官方技术博客：blog.uwa4d.com 官方问答社区：answer.uwa4d.com UWA学堂：edu.uwa4d.com 官方技术QQ群：793972859（原群已满员）
1）Unity Batches与glDrawElements的关系 ​2）渲染大面积草地时，如何降低消耗 3）HUD随着摄像机偏移 4）Unity中如何在竖屏模式的UI之上显示强制横屏的UI 5）iOS能耗问题 这是第222篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） Rendering Q：Unity里用FrameDebug显示DrawCall是422个，Batches是435个，在SnapDragonProfiler里抓取出来glDrawElements数目是1449个，怎么理解这种差异? A1：可参考以下几点： 题主的数据有一点问题，DrawCall数目应该大于等于Batches。根据特定的规则，多个DrawCall可以视为一个Batch，一个Batch中包含多个DrawCall，节省了一部分CPU提交数据的操作。 调用glDrawElements函数进行绘制就是DrawCall的一种形式。 感谢Vest@UWA问答社区提供了回答 A2：这部分可以参考UWA Day 2020里张强老师的分享《Unity移动游戏项目优化案例分析（上）》中的第二小节。 感谢范君UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5f33b10e9424416784ef1bdd Rendering Q1：渲染大面积草地时，如何降低消耗？ A1：有以下几点： 使用DrawMeshInstance。 上面这个API是不会进行视距剔除，视锥体剔除和遮挡剔除的。 下面有两种方案： a. 将草地按区域分组，用每组的中心点计算视距，依据距离切换网格LOD或剔除。 还能用向量点乘简单剔除在相机后方的草地。（注意临界问题） b. 借助CullingGroup。 CullingGroup.onStateChanged事件绑定，通过事件触发调整传入DrawMeshInstanced的Matrix顺序和渲染数量。（比较难的是，DrawMeshInstanced只能指定渲染前几个Matrix） 通过cullingGroup.SetBoundingSpheres实现视锥体剔除和遮挡剔除； 通过cullingGroup.SetBoundingDistances实现视距剔除和LOD； 这个方案也最好进行区域分组，不然CullingGroup的事件监听占用会比较高。中端机上4000个监听会占约2ms。 以后如果有对比两种方案的性能，我再进行补充。 附： CullingGroup API的使用说明 Unity 3D研究院之Lightmap支持GPU Instancing 如何高效使用GPU Instancing技术来进行草丛渲染 升级Unity 2018过程中，遇到的DrawMeshInstanced不生效的问题 感谢题主李先生@UWA问答社区提供了回答 A2：可以使用Indirect模式的Instancing，配合ComputerShader实现视锥剔除和遮挡剔除。 感谢邹春毅@UWA问答社区提供了回答 Q2：手机上能用吗？ A：推荐一个使用URP制作的草海效果，亲测可在Mobile端使用。 Unity URP Mobile Draw Mesh Instanced Indirect Example 性能测试： can handle 10 million instances on Samsung Galaxy A70 (GPU = adreno612, not a strong GPU), 50~60fps, performance mainly affected by visible grass count on screen(draw distance = 125) can handle 10 million instances on Lenovo S5 (GPU = adreno506, a weak GPU), 30fps, performance mainly affected by visible grass count on screen(draw distance = 75) 感谢Vest@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5e919a528cabe84a011afcde Rendering Q：HUD为什么会随着摄像机偏移？ 代码如下： Vector3 midVe1 = obj.transform.position; Vector2 viewPose = worldCamera.WorldToViewportPoint(midVe1 + new Vector3(0, 2, 0)); viewPose.x *= Screen.width; viewPose.y *= Screen.height; hud.anchoredPosition = viewPose; 图片如下： A：题主说的这个现象是合理的。 Vector2 viewPose = worldCamera.WorldToViewportPoint(midVe1); Vector2 viewPose = worldCamera.WorldToViewportPoint(midVe1 + new Vector3(0, 2, 0)); 这两个算出来的viewPos.x是不一样的。所以可以改成先算x，再偏移y。大概是这样： Vector3 midVe1 = obj.transform.position; Vector2 viewPose = worldCamera.WorldToViewportPoint(midVe1); viewPose.x *= Screen.width; viewPose.y *= Screen.height; viewPose.y += 130; hud.anchoredPosition = viewPose; 这里面y方向上的偏移值（130）就要自己调整了。 感谢Xuan@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5f804eff9424416784ef2587 UGUI Q1：针对Unity中如何在竖屏模式的UI之上显示强制横屏的UI，我们现在有两种思路： 1. 改Screen.orientation之后再显示。 - 需要考虑外层RectTransform是否已经“完成”了转屏导致的变化，然后才能去适配内层。尚未找到可靠的事件。 - 需要处理背景，半透明背景可能透出后面的UI排版混乱。 2. 将新UI旋转依z轴转-90度显示。 - 对刘海屏的适配需要做相应的修改。 - 无法转屏（因为还是竖屏，且不支持Upside Down）。但是这个应该可以克服。 请问，两者哪种更好呢？ A1：一个简单的方式： Canvas的RenderMode改成World Space，管它摄像机怎么裁剪，UI画布也不会发生变化。 如果自适应不了，在Canvas上根据你自己的需求做好自适应就好。 感谢郑骁@UWA问答社区提供了回答 A2：我们之前项目里刚好有个类似的需求，在横屏游戏中，个别玩法切换到竖屏。 当时采用的解决方案是修改Screen.orientation，同时修改UI全局根节点上的CanvasScaler的referenceResolution（竖屏时设置为1080，1920，横屏设置为1920，1080），matchWidthOrHeight（和项目的适配策略相关，竖屏时设置为0，横屏时为1），切换时会有一个全屏遮罩的fade效果，来避免切换时显示错误。 感谢范君@UWA问答社区提供了回答 Q2：请问为什么不考虑转90度的做法？ A：我们当时没有测过旋转的方案。现在大概想想有两个问题，不知道想的对不对。 单纯旋转角度应该只能在横屏的中间部分显示一个竖屏界面吧？感觉还需要其他处理。 对工作流是否有影响，如果要一个竖屏界面是否是要在制作时先做成一个横屏界面？内部控件是否要处理？例如最终呈现出竖屏效果的剧情文字从左到右出现，旋转之前应该是横屏的从下到上出现，同时每个单一文字也是旋转的。 感谢范君@UWA问答社区提供了回答 Q3：RectTransform的尺寸会被延迟修改这件事， 没有造成什么问题么？ A：记不太清了，印象中没有遇到什么大问题。不过我们当时这类需求切换时都是全屏UI，加了遮罩Fade后没有什么明显的穿帮。 感谢范君@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5f8166d99424416784ef25b0 iOS Q：我在Xcode真机调试中发现能耗始终处于Very High，而我项目的基本情况是（每帧GPU渲染3.5ms，每秒60帧，渲染分辨率为750*1624，设备iPhone XS，场景中只有UGUI没有其它3D或2D物体），麻烦大家帮忙看看这个电量消耗属于正常吗？还有没有优化的空间（帧数和分辨率估计是没有办法下降了，会影响项目效果），谢谢。 A1：测试过空场景Average Energy Impact也会显示Very Hight（如下图），题主的GPU能耗占比较大说明CPU相对而言还是压力比较小的： 这个帖子也是类似的问题，看上去是因为Unity引擎本身相对于普通APP体量较大，所以能耗表现较高，降低目标帧率会有所改善。 Energy Impact表征的是全局（非单个APP）的能耗，而且测试的时候USB连接充电是如何在统计中避免的不太清楚机制，建议使用Xcode Instruments工具的Energy Log模版测一下单个APP的能耗情况。 Energy Log文档 关于能耗的优化先关注整体的是GPU还是CPU（或其他方面），GPU的用FrameCapture定位一些比较高耗时的Shader进行优化，CPU结合Time Profiler模版定位一些高能耗的CPU Bound。 感谢羽飞@UWA问答社区提供了回答 A2：GPU的用FrameCapture定位一些比较高耗时的Shader进行优化。 关键是Capture哪一帧，这个会很盲目。 感谢山中千年@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5f81af2d9424416784ef2642 封面图来源于网络 今天的分享就到这里。当然，生有涯而知无涯。在漫漫的开发周期中，您看到的这些问题也许都只是冰山一角，我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入，也许你的方法恰能解别人的燃眉之急；而他山之“石”，也能攻你之“玉”。 官网：www.uwa4d.com 官方技术博客：blog.uwa4d.com 官方问答社区：answer.uwa4d.com UWA学堂：edu.uwa4d.com 官方技术QQ群：793972859（原群已满员）
1）开发期资源管理的策略选择 ​2）iOS14启动就Crash 3）IL2CPP加密：global-metadata.dat在iOS下的解密问题 4）如何实现可程序控制的3D动作 5）Unity Editor内Screen的Width和Height 这是第212篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） Resource Q1：因为打包需要用AssetBundle，但是开发中用AssetBundle不太友好，以上两种加载都会有各自的问题： Resources：需要放在Resources文件夹下，打包不好处理。 AssetDatabase：没有异步加载方法，开发中没办法模拟一些需要异步加载的情况。 目前项目用的Resources，打包机分了两个项目，打APK的项目阉割了Resources，写了单独版本管理更新命令，但是依然挺麻烦。大部分公司都是用的AssetDatabase，请问是否有一些方法可以模拟异步加载？ 另外以上两种方法都无法模拟真实的卸载情况，导致组员不合理操作时，打AssetBundle后会有内存泄漏或者丢失引用的情况，可以说一些大家公司开发时用的资源管理方案吗？ A1：用AssetDatabase可以加一些随机延时模拟异步，资源加载的接口可以封装一下，做到根据配置来决定走AssetDatabase还是走AssetBundle。 我们打包机会把打好的AssetBundle自动提交到SVN，可以随时更新下来，在编辑器下测AssetBundle比较方便。 另外：新的Addressable也可以试试看。 感谢littlesome@UWA问答社区提供了回答 A2：听说过一个项目组做法是：平时开发使用Resources来加载；打AssetBundle或者正式包时，按某些规则根据Resources的目录自动生成一个新工程，这样就不用维护两个工程了。 感谢张迪@UWA问答社区提供了回答 A3：之前是协程模拟AssetDatabase下的异步，即LoadFromFileAsync。 后面尝试过一种方法，就是使用单独的美术工程处理AssetBundle，然后程序工程不负责任何资源，只使用美术工程打包生成的AssetBundle。初听上去流程比较复杂，一点点小的改动即需要操作2个Unity工程。但是其优点也是非常多的。 代码上可以保留AssetDatabase的加载部分用于调试，当然能在日常开发中使用AssetBundle大部分时候能把AssetBundle的Bug暴露在Editor端，而不是上了真机才出问题。 感谢cloud@UWA问答社区提供了回答 A4：以前是用Resources来加载，只不过会把资源放到Editor/Resources目录下来避免被打进包内。 然后要发布的时候切换Flag，并读取Editor/Resources目录下资源进行打AssetBundle包。不过现在全部交给Addressables来管理了。 感谢黄程@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5f0acbca39b05c2c143aa37e iOS Q：在iOS 14发布之后，就出现闪退问题了。和机型没关，只要是iOS 14就必闪退的那种，iOS 13就正常。用的Unity版本是2018.2.3。请教有人遇到过吗？ A：我们iOS14也出了状况，有两个表现： 启动就闪退，多起几次可以过去。 启动后到某个阶段之间卡死（必卡跳不过）。 XCode里看，始终是GfxDriver报错，我们渠道方发现，XCode里【BuildSetting - Packaging - Product Name】不能含有中文，有中文就出这个问题，改掉就好了。 根本原因尚不明确，个人猜测Product Name会影响Header Folder Path，可能是代码加载路径中出现中文会出问题（类似早期Unity的状况）。希望对你有帮助。 感谢Walker@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5f0c6d02423c965a6f40736c iOS Q1：为了加大破解难度，需要对global-metadata.dat文件进行加密。 实现方式是： 1. 加密在导出Android和Xcode工程后进行，对global-metadata.dat按字节加密。 2. 修改： Android：\Editor\Data\il2cpp\libil2cpp\vm\MetadataLoader.cpp Mac：Unity.app\Contents\il2cpp\libil2cpp\vm\MetadataLoader.cpp 文件中的LoadMetadataFile函数，对从文件中读取出来的内容按字节解密。 现在出现的问题是：在Android上没有问题，可以正常加密和运行游戏。但是在Mac上，貌似解密函数没有生效，导致启动游戏崩溃。 请教一下各位大佬：在Mac上，global-metadata.dat的读取是不是不是通过这个函数。我看到Mac上Unity安装目录还有一个PlaybackEngines文件夹，里面也有IL2CPP相关文件，例如MetadataLoader.h，但这个文件是只读的，无法修改，而且也没有找到MetadataLoader.cpp。Mac上解密不生效和这个文件有关吗？ A：iOS上是直接链接预编译好的PlaybackEngines\iOSSupport\Trampoline\Libraries\libil2cpp.a 可能需要自己把.a从工程里移除，把IL2CPP源码引入到工程里。 Q2：工程是指iOS Support/Tramponline文件夹下的Xcode工程吗？要把Unity.app\Contents\il2cpp\libil2cpp中的文件全部加入到这个工程里面是吗？ A：是指导出的项目工程。具体哪些文件可能需要自己试试了。可以在Windows上导个IL2CPP的VS工程对照一下文件和编译参数。 Q3：我们最近遇到这个iOS加密Metadata的问题，请问最后有找到解决方案吗？https://forum.unity.com/threads/how-to-cross-compile-libil2cpp-for-ios-platform.785315/ 看这个帖子，似乎是需要Unity源码才可以？ A：IL2CPP的代码直接拖到XCode工程里应该就可以了。 感谢littlesome@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5edf80de55f66053ed8029d0 Animation Q：我们的需求是希望用程序实现灵活的拍掌动作，如下图： 中间一个大模型，左右两手，两手掌要做拍掌动作，蓝色点都可作为拍掌点，就是说要让程序控制拍到哪里。目前想到的方案是： 1. 做很多个拍掌动画，然后在Blend Tree里用二维混合，但那样不够精确。 2. 用Final IK，控制两手掌运动，但那样做的动作不自然。 我们希望尽量减少K动作工作（外包耗不起），问有没有其它方案可用？ A1：这种需求基本上都需要使用IK来做，Final IK是目前看到的Unity引擎中最为成熟的IK解决方案了。如果还是不行，可能需要考虑自行研发了。 该问答由UWA提供 A2：我们之前用过2D Freeform Directional的Blend Tree来融合前后左右移动的动作，融合效果是比较理想的。道理上你分别做最左最右最上和最下四个拍掌动作，然后通过两个参数分别控制左右和上下的融合，能够比较线性地对应起来，精确度应该能接受，不过我没资源测试，也不确定你对精确度要求程度，还是建议做个Demo试试。 感谢邓永健@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5f0de05f125d6020412cc118 Editor Q：在Unity 2018.4.23版本中测试，新增一个9:16的分辨率，此时获取到的Width与Height是515x916，如果改动Game窗口大小，这个值也会变，请问这个具体规则是怎样的呢？ 发现应该是乘以了对应分辨率下的Scale值，比如在720x1280的分辨率下看Game窗口的Scale值是0.741，切成9:16后的分辨率正好是533x948(720x0.741 : 1280x0.741)。现在有API能获取到这个值么？ 因为有一些UI操作，比如会把一张图设为和屏幕一样大的大小，但在Editor下UI分辨率是720x1280，所以会和期望的值不一样。如果把分辨率设为720x1280（也是9:16），那么获取到的值就是对的。 主要是想知道规则，然后能根据515x916换算出来720x1280。 A：编辑器下，如果Game窗口采用的比例（Aspect Ratio）的模式，Screen获取的就是Game窗口的实际大小。如果Game窗口采用的是固定分辨率（Fixed Resolution）。Screen获取的就是设定的窗口大小。 感谢张首峰@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5f0d6e2f6ef758272c63739e 封面图来源于网络 今天的分享就到这里。当然，生有涯而知无涯。在漫漫的开发周期中，您看到的这些问题也许都只是冰山一角，我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入，也许你的方法恰能解别人的燃眉之急；而他山之“石”，也能攻你之“玉”。 官网：www.uwa4d.com 官方技术博客：blog.uwa4d.com 官方问答社区：answer.uwa4d.com UWA学堂：edu.uwa4d.com 官方技术QQ群：793972859（原群已满员）