问答 Shared UI Mesh 内存占用过高

侑虎科技 · 2020年07月08日 · 861 次阅读

1)Shared UI Mesh 内存占用过高
​2)GPU Skinning 有办法实现阴影的做法吗
3)在真机上特效不跟着 Spine 运动
4)复制 AnimatorController 无效问题
5)Profiler 中的 System.ExecutableAndDlls 如何优化占用

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

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

UGUI

Q1:缓存池中的 UI 如果不隐藏,Shared UI Mesh 会比较高;如果隐藏,Shared UI Mesh 会比较低,但是 UI SetActive 又有性能消耗,该如何权衡呢?

隐藏缓存池中的 UI 时,Shared UI Mesh 内存占用:

不隐藏缓存池 UI 时,Shared UI Mesh 内存占用:

A1:如果只有 SetActive 才能降低 Shared UI Mesh,好像就没有其他选择了;但是如果切换 layer 可以降低,可以选择该办法。

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

A2:Shared UI Mesh 是源自 UGUI 框架中的一个静态全局变量 Graphic.workerMesh:

而 workerMesh 主要在以下代码中使用:

该函数是在 Rebuild 单个 UI 元素的顶点信息,红框里的 FillMesh 就是将更新后的顶点属性数组设置到 workerMesh 上,且每次调用都会先进行 Clear 操作。
看逻辑,这个 workerMesh 的内存大小应该只和单个 UI 元素的顶点量有关,但实际测试下来,是和当前所有激活 UI 元素的顶点总量相关的。

所以,Shared UI Mesh 很大,表示当前所有激活 UI 元素的顶点总量很高。需要对部分复杂元素进行简化。

常见的复杂元素有:

  1. Tiled 模式的 Image:该模式下会根据 UI 元素的区域和纹理分辨率的大小,自动生成适当数量的四边形,一旦纹理分辨率很小,而区域很大时,就会产生大量的顶点。
  2. Outline 效果的 Text:Outline 效果会将 Text 文本原来的顶点数放大为 5 倍。
  3. RichText,且包含了较多样式的 Text:样式标签部分也会产生顶点数。 注:2 和 3 同时使用时,样式标签部分的顶点数也会放大。

定位的方法:

  1. 初步定位:直接在 SceneView 下换到线框模式,肉眼找一下复杂元素;
  2. 通过 Profiler 的 UI 面板,查看各个 Canvas 下各个 Batch 产生的顶点数,并检查对应的 GameObject 即可。 需要注意的是,Canvas 组件被禁用的情况下,Profiler 里是看不到的,但其下的激活 UI 元素依然会影响 Shared UI Mesh 的大小。

该回答由 UWA 提供

A3:可以试试把 Canvas 的 enable 设置为 false。

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

Rendering

Q1:关于阴影,GPU Skinning 的 Shader 可以实现加上 Planar Shadows 的 Pass 吗?或是能套用 Projector Render Texture 吗?目前使用 Unity 2018 搭配 GPU Skinning 套用 Projector 投影是静态的,并不会有角色的动作;Unity 2019 则是投影有动态,但显示有些错误。

图为 Projector Shadow + GPU Skinning 在 Unity 2019 安卓环境的效果。

以下是想实现的阴影方案,但不知道 GPU Skinning 要如何结合?请问有什么可以搭配实现阴影的插件吗?

Planar Shadows(https://zhuanlan.zhihu.com/p/42781261
Projector rendertexture(https://zhuanlan.zhihu.com/p/42433900

A1:这个问题分两个部分:

  1. 影子要跟着动作动。
  2. 影子要显示的对。 第一个部分题主已经解决了。其实原理很简单,GPU Skinning 中,动画信息是先由 Compute Shader 或者 VS 的 TFBO 之类的东西计算好之后,传给真正绘制的 VS 中,通过顶点动画的方式实现动起来。

最开始没有动起来也许是因为使用的阴影 Shader 中,没有拿到 Compute Shader 或者 VS 的 TFBO 之类计算出来的动画信息,在阴影 Shader 的 VS 中进行顶点动画。

第二个问题。看上去像是典型的阴影 Bias 的问题(阴影中出现缝隙),题主把这个物件的阴影 Normal Bias 和 Depth Bias 都设置为 0 看下吧。

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

Q2:其实第一部分没有解决,用了 Render Texture 去投影,只是都没有处理的情况下,Unity 2019 会显上上面那张图的效果,影子也会跟着动,2019 以下的版本则是静态 Mesh 的轮廓和不会动的阴影,GPU Skinning 的 Shader 都已经封装过,直接在 Shader 上加阴影的 Pass 是不会有任何效果的。

GPU Skinning:(https://github.com/chengkehan/GPUSkinning

A1:原理就是上面那样,具体就要读代码了。据我所知 Projector 是用另外一个 Shader 绘制的,那么这个 Shader 中 VS 没做处理,肯定就不会有动画的。但是 2019 为什么又有了?就需要具体读代码了。

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

A2:Surface Shader:

Vertex&Fragment Shader:参考下这个(https://gamedev.stackexchange.com/questions/143126/how-to-receive-shadows-on-animated-object-in-optimize-wayShadow)添加一个 Pass。

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

A3:根据羽飞同学的回答,做了一个对比实验,渲染的模型是 Unity 自带的 Cylinder,在 Surface Shader 中加了顶点动画,效果如下图:

从上面的截图可以看到 addshaow 模式是可以让阴影保持正确的。上图中奇怪的部分应该是由于 Camera 产生的深度图(根据顶点变化后的物体生成)和 Light 生成的深度图(根据顶点变化前的物体生成的)对比的对象不一致导致的。

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

Script

Q:把特效直接放在 Spine 的节点上,在 Editor 里运行正常,但是在真机上特效不跟着 Spine 运动,可能是什么原因呢?试了一下如果是动态加载特效再挂在 Spine 的节点上就没问题,如果是直接保存成 Prefab 就不行。

A1:建议使用 BoneFollower 组件,让特效挂在 BoneFollower 组件的 GameObject 下。

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

A2:楼上说的对,在 Spine 下面创建一个 GameObject,然后添加上 Bone Follower Graphic 组件,选择要绑定的骨骼,然后在这个 GameObject 下面再添加上你要播放的特效就可以了。

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

Animation

Q:我用一个原始的 AnimatorController 做模板文件,在编辑器里复制出来替换 Clip 给新的人物做动画控制器。

现在出现一个问题,用 AssetDatabase.LoadAsset 加载模板文件,用 Instantiate 复制后替换 Clip 后保存,发现原始的模板 AnimatorController 也被修改掉了。

A1:可以参考一下这个工具:AnimatorGenerator
工具介绍在此。

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

A2:建议使用 AnimatorOverrideController。

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

Memory

Q:Profiler 中的 System.ExecutableAndDlls 如何优化占用?

A1:知识的搬运工:(https://answer.uwa4d.com/question/58dbbbd34e69b5ed22e68abf

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

A2:使用 IL2CPP 的情况下,可以搞这些事情。建议项目中期开始搞平时多测试,不建议在临近上线的时候做这方面的优化:

  • 减少 C# 代码,官方说 1MB 的 C# 大概会产生 3MB 的 IL2CPP 后的二进制大小。
  • Package Manager 里各种用不到的 Built-in Packages 都去除掉。
  • 如果用的是 Lua,减少不必要的 Wrap 代码的生成。
  • 减少 link.xml 里的项,preserve 到类级别。
  • Managed Stripping Level 使用 Medium,这样未被调用的 C# 函数也会被删除。 (开到 High 可能有风险,但剔除效果明显,有时间可以尝试一下,我们一个线上项目只开到了中)。
  • 开启 Strip Engine Code,尤其是安卓开启后会根据使用情况 link 出一个 libunity.so (不开启是直接拷贝 PlaybackEngines 下的完整版 libunity.so)。
  • iOS 只保留 ARM64 架构。
  • 符号剔除(注意保留打包生成的 symbol.zip,或者生成一个 Bugly 符号表,以便应对线上崩溃)。 iOS 默认会保留一部分符号,可以给 XCode 工程加个特殊处理。安卓对 so 也可以再调用一下 NDK 里的 Strip 命令。
string releaseConfig = pbxProj.BuildConfigByName(targetGuid, Release);
pbxProj.SetBuildPropertyForConfig(releaseConfig, DEPLOYMENT_POSTPROCESSING, YES);

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

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

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

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册