UWA问答 | 博客 | 游戏及VR应用性能优化记录分享 | 侑虎科技 - 动画
type: channel
link: https://blog.uwa4d.com/tag/动画/
items: 粒子系统优化：Mesh模式下的优化策略
items: Unity引擎模块分析—注重效率的你不妨这么做！
items: 技术分享连载（九十四）
items: 虚幻引擎学习之路：动画模块进阶篇之动画融合
items: 虚幻引擎学习之路：动画模块之基础篇
items: 技术分享连载（八十）
items: Unity动画文件优化探究
items: 技术分享连载（六十七）
items: 技术分享连载（四十八）

粒子系统优化：Mesh模式下的优化策略
type: item
date: 2020-11-25T04:17:00+02:00
description: 在上一期《动画优化：关于AnimationClip的三两事》中，我们针对动画优化中的“AnimationClip的压缩方式”以及“AnimatorController挂载的AnimationState”做了解释。这些看似细小的知识点，很容易在大家的开发和学习过程中被疏忽，而长期的问题积累最终都会反映到项目的性能表现上。为此，我们将这些规则列出，并且以一个个知识点的形式向大家逐一解读。 本期，我们将面向粒子系统，讲解UWA本地资源检测中的规则：“网格发射数超过5的粒子系统”、“检测粒子系统使用的网格Read/Write选项”、“引用网格面片数超过500的粒子系统”和“引用纹理数超过5的粒子系统”。我们将力图以浅显易懂的表达，让职场萌新或优化萌新深入理解。 1、网格发射数超过5的粒子系统 关于粒子系统的定义，我们在此不再赘述。我们重点来看一下粒子系统的渲染模式。 粒子的渲染模式可分为两大类：2D的Billboard（公告牌）图形模式和Mesh模式。Billboard是3D游戏中用的非常多的一种技术，使用该模式，粒子会以一个平面的形式存在，并始终以一定的角度对着我们的镜头。举个例子来讲，场景中有一棵树，是实体存在的；但在各种Billboard模式下，你只需要看到这棵树的一个“面”。在展示效果上表现其实一样，但渲染一个“面”和渲染一整个实体，前者在消耗的内存和运算量上会更有优势。 Billboard模式，粒子会始终面向摄像机； Stretched Billboard模式下，粒子在面向摄像机的同时，会在速度的方向上进行拉伸，可以设置粒子的各种缩放和拉伸效果； Horizontal Billboard模式下，粒子平面会和XZ面平行； Vertical Billboard模式下，粒子平面在面向摄像机的同时，会在Y轴方向上直立（垂直于XZ平面）； 而“Mesh”模式就是我们今天的主题。这个模式允许粒子系统发射3D网格而非2D的Billboard，以此来实现更为复杂和贴合需求的粒子效果。 3D网格性能开销显然是高于2D的Billboard的。如果粒子系统的发射的网格数量过大，会带来较高的CPU计算开销、GPU渲染压力甚至较高的堆内存分配。所以我们对使用Mesh进行渲染的粒子系统的“最大粒子数”要求更为严苛。一般的粒子系统中，粒子发射数上限建议不超过30（我们在之前的文章中有进行讨论，详见《【性能黑榜】掌握了这些规则，你已经战胜了80%的对手！》）。经由UWA的测试结果表明：渲染模式为Mesh、网格发射数在不超过5的情况下，能够维持粒子效果和性能消耗上的一个相对平衡。 所以开发团队在本条规则执行后，需要对筛选出来的粒子系统进行显示效果和性能消耗上的平衡考量，并对相应的粒子系统进行修改。 2、所使用的网格未开启Read/Write选项的粒子系统 由于粒子系统的渲染对象从传统的粒子变成了3D网格，所以引用的网格对象本身的属性也会对整个粒子系统产生影响。在这种情况下，很多针对网格的优化建议也同样适用于Mesh模式下的粒子系统，只不过针对特定应用环境，部分优化建议需要“反着看”。 在之前的文章《网格优化：溃堤之穴，一个也不能放过》中，我们对于网格的Read/Write选项进行过一定的说明。仅仅针对网格而言，我们是不建议开启相关的读写权限。 但是在粒子系统应用中，往往需要去实现各种各样的动态效果。所以当渲染模式为Mesh时，网格就需要开启Read/Write选项以实现对3D网格的动态修改，来更好地实现相应的渲染展示效果。 Unity官方文档告诉我们，网格必须设置为Read/Write Enabled才能在粒子系统上工作。若不开启，在某些设备上运行时，可能会出现模型丢失的情况。可见问答：https://answer.uwa4d.com/question/5cf732fed27511377098284e。因此我们将该类异常的资源检测出来，希望研发团队进行规范，防止出现意外的显示结果。 3、引用网格面片数超过500的粒子系统 和上一条规则不同，这条便是网格优化在粒子系统中的正向应用。在以前文章《那些年给性能埋过的坑，你跳了吗？》中，我们对于网格的面片数有过相关的简单讲解。对3D网格而言，过多的面片数会带来内存，加载和渲染上的额外消耗。在粒子系统中也是同样如此。 在Mesh模式下，发射的3D网格对面片数的要求也是同样严苛的。所以开发团队需要在本条规则下，去检查相关粒子系统引用的网格是否存在面片数过多的情况，并视实际的表现效果和性能消耗去决定是否需要做出相关的修改。 4、引用纹理数超过5的粒子系统 在之前的文章《材质优化：如何正确处理纹理和材质的关系》中，我们简单讲了下材质的Shader中引用了过多纹理会在内存和计算上带来的影响。 同样的，在粒子系统中，如果在材质内…

Unity引擎模块分析—注重效率的你不妨这么做！
type: item
date: 2018-09-28T16:21:00+03:00
description: UWA GOT是UWA推出的本地性能优化工具，其Online功能限时免费中，并受到了大量开发者的试用和积极反馈。其中，它的总体性能分析模式主要便于研发团队直观地定位、验证和解决逻辑代码中的效率瓶颈。 然而我们知道，引擎模块的性能同样至关重要，仅仅逻辑代码的检测还无法实现系统、完整地定位瓶颈的目的。所以今天，我们在该工具中推出Unity引擎模块的检测。您只需要拥有一个UWA GOT，在本地真机上测试后即可把数据同步到官网，这些详细的数据就能立马呈现。 详细的引擎模块参数 目前，UWA GOT Online报告支持渲染、UI、粒子、动画、加载和物理这六大主流引擎模块的重要参数检测。如下图，在渲染模块页面中，我们可以查看不透明、半透明、视域裁剪CPU和相机后处理等CPU耗时的走势以及某一帧上的耗时。 我们也可以缩放某段测试区域，结合运行截图更直观地定位某些峰值处的表现。 对于引擎模块的重要参数，我们提供了UWA推荐值和相关的优化建议，便于研发团队进行有的放矢的排查和优化。 精准的逻辑代码堆栈 堆栈信息是我们定位性能瓶颈的鹰眼，这次版本的更新不仅丰富了引擎模块的重要参数检测，在逻辑代码中也可以查看更细致的引擎函数堆栈信息，并且通过总体、指定场景和指定帧来定位具体的调用详情。 特别的，在堆栈信息列表中，我们也提供了历史数据对比功能，针对于研发团队定制的性能或功能回归测试，我们可以直接在报告中查看指定重要参数的变化趋势，便于开发团队可以在第一时间验证测试结果。 这次的新功能小编就安利到这里啦！目前，该功能也在限免使用中，研发团队只需要拥有一个UWA GOT，就可以在总体性能分析模式中体验到该功能！还不快打开你的黑科技试一试呀^_^！ 关于UWA GOT Online UWA GOT 是UWA推出的本地性能测评工具，它方便研发团队在本地真机测试，并能在编辑器中搭建本地服务器查看性能数据。现在，在UWA GOT现有的本地测评模式上，我们增加了线上同步和分析功能，研发团队可以将本地测评的数据快速同步到UWA官网，生成在线测评报告，提供更高效的性能分析数据及有针对性的优化建议。同时，贴心的版本对比功能，方便研发团队轻松监测每次测试中的重要性能参数变化趋势，从质量管控上为项目的研发保驾护航。

技术分享连载（九十四）
type: item
date: 2018-01-09T03:39:00+02:00
description: 本期聚集了这些话题：ShaderLab内存优化、Static Batch使用注意事项、foreach的堆内存分配问题修复、Unity 2017场景光照烘焙信息过大...... 我们将从日常技术交流中精选若干个开发相关的问题，建议阅读时间15分钟，认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系我们，一起探讨。 UWA QQ群：793972859 UWA 问答社区：answer.uwa4d.com 渲染 Q1：我们的版本是Unity 2017，我们的美术烘焙出来的场景光照贴图中，还带了一个Lighting Data Asset这样的文件，查询相关资料显示是包含了贴图采样信息等内容，按理说应该不会很大，可是现在项目里，这个文件达到了90MB一个场景很不正常。有人建议是把这个东西删掉索引，不要打包。但是不知道这样场景里的灯光贴图还可以正常加载么？ 建议题主可以看下文档（https://docs.unity3d.com/Manual/LightmapSnapshot.html）里的两条描述： The asset is an Editor only construct so far, so you can’t access it in the player. Currently, this file is a bit bloated as it contains data for multiple platforms - we will fix this. Also we are considering adding some compression for this data. 所以这90MB并不是全都打到包里去的，但里面所保存的必要信息，打进包里后，具体有多大确实不好评估。一般来说，不开启Precomputed GI的话，应该是不大的。“把这个东西删掉索引”再打包的话，理论上Lightmap是会丢失的，得自己来动态加载和设置的。 该问题来自UWA问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/5a4f4367e041ef3c50c9ce64 内存管理 Q2：真机测试环境下，在Profiler里查看内存使用情况，发现ShaderLab一项占用内存很大，里面主要是什么？减少了Shader的变体后这部分内存有所下降，没有使用Unity内置的Standard Shader。能否在不减少变体的情况下，减少这一部分占用的内存？ 另外，也发现同一项下的Objects占用也很大，这是为什么呢？ ShaderLab是项目在编译Shader时产生的解析Buffer，其内存增长的特点就是Key words越多、变体越多，其内存占用越大。目前，还没有看到有不减少变体的情况下，可以减少该内存占用的有效方法。如后续有找到，我们也会来及时更新这块的内容。 至于Objects，建议搜索题库，来查找之前相应的回答，比如这里： https://answer.uwa4d.com/search/objects 该问题来自UWA问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/5a4d8df42b7c402cc97294a3 动画 Q3：我们导入anim后缀的文件进行精度处理后某些信息丢失，如下图所示： 修改的代码如下： AnimationClip theAnimation = AssetDatabase.LoadAssetAtPath<AnimationClip> (path); Keyframe key; Keyframe[] keyFrames; foreach (EditorCurveBinding binding in (AnimationUtility.GetCurveBindings(theAnimation))) { AnimationCurve curve = AnimationUtility.GetEditorCurve(theAnimation, binding); if (curve == null || curve.keys == null) { continue; } keyFrames = curve.keys; for (int i = 0; i < keyFrames.Length; i++) { key = keyFrames[i]; key.value = float.Parse(key.value.ToString(“f3”)); key.inTangent = float.Parse(key.inTangent.ToString(“f3”)); key.outTa…

虚幻引擎学习之路：动画模块进阶篇之动画融合
type: item
date: 2017-12-22T03:43:00+02:00
description: 上周UWA介绍了Unreal 4引擎动画模块中的基本功能，接下来我们将进一步介绍Unreal 4引擎动画模块中提供的进阶功能。其中主要包括：动画融合、动画重定向、反向运动学、顶点动画。鉴于篇幅原因，今天我们先来讲解动画融合。 在此，特别感谢Unreal中国团队对于本篇文章中Unreal引擎相关内容的审核，并在UWA团队学习其引擎的道路上提供的大力支持。 动画融合 动画融合是游戏引擎动画模块中的重要功能。本节将介绍Unreal 4引擎中提供的动画融合功能，主要包括：Blend节点、Blend Space、Animation Montage、Animation Composite以及Post Process Animation Blueprint。 1、Blend节点 Unreal 4引擎的Anim Graph中提供了一系列的Blend节点可以实现不同的动画融合功能，其类似于Unity引擎中的Blend Tree功能。Blend节点的输入是来自多个不同动画文件的Pose数据以及Alpha权重参数，它会根据权重参数计算出最后融合的Pose，如下图所示： 其中，A和B为两个输入Pose，Alpha为[0,1]的浮点数表示A和B的权重。当Alpha为0时输出Pose全部来自A，当Alpha为1时输出Pose全部来自B，当Alpha为0~1之间时输出Pose为A和B的融合结果。类似功能的节点还有：Apply Additive、Blend Multi等。 Time Based Blend类型节点可用于连接两个或多个动画，并在动画切换时进行融合。Blend Poses by bool节点是其中一种，该节点根据输入的Bool值（红框中的Active Value）来控制True Pose和False Pose的切换，并且可分别设置两个Pose的融合时间（蓝框所示），其分别表示切换到True Pose的融合时间和切换到False Pose的融合时间，如下图所示： 类似功能的节点还有：Blend Posed by int，支持多个动画Pose的切换融合。 Layered Blend per bone节点可以将多个动画的不同骨骼融合在一起，例如：将Locomotion的下半身体和射击以及近战的上半部分身体进行融合，可以实现一边行走一边射击等动作。该节点需要配合Animation Montage的Slot使用，本文将在Animation Montage小节中进行介绍。 2、Blend Space Blend Space是Unreal 4引擎动画模块中用于实现复杂动画融合功能的资源。它最多可提供两个控制参数，并支持在二维平面上摆放动画采样点对多个动画进行融合。当变量取值在二维平面中的某一坐标位置时，Blend Space会根据采样点处的动画和坐标插值计算出当前坐标的动画。下图显示了1D和2D的Blend Space示意图： 其中，左图为1D的Blend Space，包含一个参数Speed。右图为2D的Blend Space，包含两个参数Speed和Yaw。 Blend Space的创建与其他资源创建过程类似，点击Add New按钮或在Content Browser中点击右键，在弹出菜单中选择Blend Space即可。Blend Space资源分为1D和2D，分别支持一个和两个控制参数的动画融合。创建好Blend Space资源后双击即可打开编辑界面，如下图所示： 上图例子使用了1D的Blend Space，实现了根据Speed参数对Idle、Walk以及Run三个动画进行采样融合效果。其中，区域1显示了资源的参数设置，区域2显示了控制参数坐标轴以及动画采样点，区域3显示了动画文件列表。通常在使用Blend Space时首先需要设置坐标轴，如下图所示： 其中，在Interpolation Type选项中可以设置动画插值计算方式，默认设置是Averaged Interpolation。 设置好坐标轴即可从区域3动画列表中选取采样动画拖动到区域2中。上述例子中设置了三个动画采样点：Idle、Walk和Run。在区域1中可查看其参数设置，如下图所示： 上图参数设置表示Idle动画位于Speed取值为0处，Walk动画位于Speed取值为93.75处，Run动画位于Speed取值为375.0处。在区域3中可查看采样动画分布，如下图所示： 其中，三个白色菱形点表示三个采样动画在Speed坐标轴上的位置，蓝色菱形点表示当前Speed取值。点击播放动画，并拖动蓝色菱形点在Speed坐标轴上移动，即可看到不同的动画插值结果。上述例子为1D的Blend Space，2D的Blend Space比1D多了纵坐标，使用方式与1D类似。 Blend Space资源设置完成后，即可…

虚幻引擎学习之路：动画模块之基础篇
type: item
date: 2017-12-15T07:59:00+02:00
description: 在之前的微信文章推送中，我们陆续为大家详细介绍了Unreal 4引擎的渲染模块（包括光照系统、材质系统、相机后处理和全局光照明），接下来我们将讲解动画模块的基础功能，并且将在后续文章中陆续推出该模块中进阶功能和特殊用途的介绍。 在此，特别感谢Unreal中国团队对于本篇文章中Unreal引擎相关内容的审核，并在UWA团队学习其引擎的道路上提供的大力支持。 前言 动画模块是游戏引擎中的重要部分，是驱动游戏中场景、角色能够活灵活现地做出动作的基础。UWA将分三块内容介绍Unreal 4引擎中的动画模块功能，其中包括：基础功能、进阶功能以及特殊功能。在介绍基础和进阶功能时，UWA不仅会对其功能进行重点讲解，同时也将结合Unity引擎中的相似功能进行类比，以求让大家可以更明晰地掌握Unreal引擎动画模块的功能使用。在特殊功能中，UWA将对Unreal 4引擎中针对特殊用途提供的功能进行重点解读。 本节主要介绍Unreal 4引擎动画模块中提供的基础功能。其中主要包括以下几个部分： 蒙皮网格 骨骼文件 动画文件 加粗文字动画逻辑 Unreal 4引擎的动画模块提供了四个编辑器：蒙皮网格编辑器、骨骼编辑器、动画文件编辑器和动画蓝图编辑器。上述基础功能可以分别在这四个编辑器中完成。在接下来的内容中，本文将在介绍基础功能的同时对相应编辑器的使用进行介绍。 一、 蒙皮网格 Unreal 4引擎支持从外部FBX文件中导入蒙皮网格和动画。导入操作可通过Content Browser->Import按钮完成。导入界面如下图所示： 其中，包含了网格、动画以及材质相关的导入设置。默认情况下Unreal 4引擎会为网格创建材质、物理以及骨骼文件。若选择导入动画，也会同时创建相应动画文件。 蒙皮网格在Unreal 4引擎中被称为Skeletal Mesh，其相当于Unity引擎中的Skinned Mesh，表示了带有蒙皮信息的网格。双击Content Browser中的蒙皮网格文件，即可打开蒙皮网格编辑器，如下图所示： 其中，左边区域（1区）是Skeletal Mesh的参数设置，右边区域（2区）是Morph Target（Blend Shape）以及预览场景设置。在Skeletal Mesh参数设置中，可以设置模型的材质、LOD、Clothing、骨骼、物理（Rigidbody）、Capsule Shadow等相关参数。其中，Clothing支持Nvidia的apex文件。骨骼文件即为下文中将介绍的Skeleton Asset。Capsule Shadow是Unreal 4引擎中Skeletal Mesh特有的软阴影。它使用形状不同的Capsule对Mesh进行近似表示，在渲染阴影时则使用该近似表示进行渲染，从而节省了渲染开销。右上角区域（3区）显示了与当面Skeletal Mesh相关的文件，点击即可快速打开相关文件。 二、骨骼文件 Unreal 4引擎中的骨骼文件被称为Skeleton Asset，其相当于Unity引擎中的Avatar文件。双击Content Browser中的Skeleton Asset文件即可打开该文件，如下图所示： 其中，左边区域（1区）显示了当前Skeletal Mesh的骨骼信息，可以选中其中某一骨骼进行编辑。同时，还可进行Retargeting的设置。右上角区域（2区）显示了选中骨骼的详细信息以及预览场景设置。在骨骼详细信息中可以设置其Transform和Name参数。右下角区域（3区）显示了动画事件和Animation Curve。其中，Animation Curve可以用于在动画过程中修改模型材质以及修改Morph Target曲线。Animation Curve的具体修改过程需要在动画编辑器中完成，此处只提供了预览。 在Unity引擎中，查看骨骼信息的方式是将其拖入场景，即可在左边Hierarchy页面中看到骨骼信息。需要注意的是，FBX模型不要开启Optimize GameObject选项。 在Unreal 4引擎中，共用Skeleton Asset的网格可以共享动画文件，即动画重定向（Animation Retargeting）。但要共享Skeleton Asset需要满足一定条件，即两个网格中的骨骼命名顺序要保持一致，如下图所示： 其中，骨骼(1,2,3)与骨骼(1,2,3,4)可以共用Skeleton Asset，但是与骨骼(1,3,2)无法共用。 在Unity引擎中，通过对Humanoid类型动画网格的骨骼进行映射也可以支持动画重定向。但是Unity中的动画重定向只能支持骨骼长度相近的网格，对于骨骼相差较大的网格会出现穿插或者分离的现象。Unreal 4引擎提供了该问题的解决方案，我们将在后续文章的动画重…

技术分享连载（八十）
type: item
date: 2017-09-26T11:17:00+03:00
description: 本期聚集话题：LightingDataAsset Delete后Lightmap展开问题、Gamma和Linear颜色空间问题、AlphaTest和Alpha Blend的性能差异... 我们将从日常技术交流中精选若干个开发相关的问题，建议阅读时间15分钟，认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系我们，一起探讨。 UWA QQ群：793972859 UWA 问答社区：answer.uwa4d.com 制作 Q1：我这边做了个测试，把场景中的物件进行StaticBatch，用Lightmap烘焙，并且在烘焙完记录每个物件Renderer的lightmapindex and offset，然后在运行中，我删除了生成的LightingData.Asset，自己设置了Lightmapsetting，并且恢复了每个物体Renderer的Lightmapindex and offset, 结果我发现烘焙出来的场景Lightmap还是不对的。我怀疑是不是LightingData.Asset 还记录了别的东西，想问问看UWA有没有什么经验呢？ 我在answer.uwa4d.com上打包一个测试用例，打开Scene/LightMapTest.unity 这个场景即可。 这个问题还是出在Static Batching上。经过测试我们发现如果去掉场景中物件的“Static Batching”标记，换成手动Batching，即采用StaticBatchingUtility.Combine的方式结果就正确了。 同时，我们发现使用LightingData.Asset时，开启Static Batching与不开启都正确，因此我们认为LightingData.Asset可能记录了与CombinedMesh有关的数据，导致如果仅仅使用gameobject的LightMap参数无法正确读取CombinedMesh的LightMap UV。另外一种可能是Unity的一个Bug。 最后，我们建议采用上述手动Batching的方式，即可解决此问题。 该问题来自UWA问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/59c0d16c5cd7219d3bbfb3b3 制作 Q2：我们场景中有两种Unlit物体，一种是在脚本中通过Mesh顶点色（Mesh.colors）赋颜色值，一种是用Shader属性传递颜色值，在Gamma颜色空间时两种物体的渲染颜色是一致的： 但是切换到Linear空间发现不一样了，如下图，左边是顶点色，右边是Shader属性颜色： 顶点颜色和属性都没改过，只是切换了颜色空间，请问是什么情况？ 我能想到的有两种可能性： 1）顶点色的颜色值在Shader中没有被正确处理； 2）右边使用贴图的导入设置中sRGB的选项有错误。 看上去左边的在线性空间下变亮了，而右侧的方块颜色在两种Space下差别不大，因此推测第一种的可能性比较大，顶点色在很多情况下并不被当作颜色处理，而作为值来存储，所以有可能这里处理有问题。至于为什么变亮了，感觉是值经过了伽马校正变大了。 Unity有接口在两种颜色空间下转换，建议题主可以查一下，在Shader中修改代码来排查下是哪里的问题。 该问题来自UWA 社区，感谢贾伟昊提供了回答，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/59c387de79a00b1e16da7414 UI 制作 Q3：当使用Linear设置时，UI上图片透明度等也跟着变化，出来的效果与美术人员的需求不一样。请问有什么办法可以让UI不使用Linear或者让UI可以在Linear影响下也正常呢？ 推荐题主可以看下这个帖子 https://forum.unity.com/threads/bug-with-bypass-srgb-sampling.282469 “When switching to linear mode it (greatly) changes how blending works, this is because when sampling only the rgb channels are linearised as it is assumed the alpha is a linear scale representation already.” 简单说，这是正常现象，里面有三种解决方法： 1）改资源的 alpha 通道： Reauthor the content for linear blending (this is supported in photoshop). …

Unity动画文件优化探究
type: item
date: 2017-06-28T11:41:00+03:00
description: 为了优化Unity动画文件，作者从两个角度出发：1）压缩浮点数精度和 2）去除scale曲线，通过多次实验观察，得出了通过精度优化降低内存的本质，文末附工具代码和使用说明，值得大家探究和借鉴。 前不久笔者在UWA群里和一些朋友们讨论动画文件精度优化的问题，参考了UWA问答上王亮的代码后，我也尝试优化了动画文件，发现如下的一个很奇怪的现象。下图中Inspector中显示的大小并没有任何变化，但是文件大小和Profiler中的内存大小确实是减小了。那么Inspector中显示的Size是什么含义呢？ 下图中的动画文件不包含Scale曲线，所以这次优化中只压缩了浮点数精度。 我分别对比了动画文件优化前和优化后的大小。 FileSize FileInfo.Length取得的文件大小 可以在操作系统的文件系统中看到 MemorySize Profiler.GetRuntimeMemorySize取得的内存大小 可以在Profiler中通过采样看到 分别在真机和Editor下进行了采样 BlobSize 反射取得的AnimationClipStats.size二进制大小 显示在AnimationClip的Inspector的面板上 红色框内即是BlobSize，在我的理解，FileSize是指文件在硬盘中占的大小，BlobSize是从文件反序列化出来的对象的二进制大小。Editor下的MemorySize不仅有序列化后的内存大小，还维护了一份原文件的内存。就像我们在Editor下加载一张Texture内存是双份一样，而真机下就约等于BlobSize。真机下的MemorySize和Inspector里的BlobSize非常接近，BlobSize可以认为是真机上的内存大小，这个大小更有参考意义。 同时，我也对去除Scale曲线的方法进行了实验。下图这个动画文件原来Inspector中Scale的值为4，即有Scale曲线，原始文件BlobSize为10.2KB，去除Scale曲线后，Blob Size变为7.4KB，所以BlobSize减小了27%。 Curve减少导致内存减小 从上面的实验可以看出来，只裁剪动画文件的压缩精度，没有引起Curve减少。BlobSize是不会有任何变化的，因为每个浮点数固定占32bit。而文件大小、AB大小、Editor下的内存大小，压缩精度后不管有没有引起Curve的变化，都会变小。 裁剪动画文件的精度，意味着点的位置发生了变化，所以Constant Curve和Dense Curve的数量也有可能发生变化。由于是裁剪精度所以动画的点更稀疏了，而连续相同的点更多了。所以Dense Curve是减少了，Constant Curve是增多了，总的内存是减小了。 Constant Curve只需要最左边的点就可以描述一个曲线段。 只裁剪精度使BlobSize减小的实例 裁剪精度前，大小为2.2kb，ScaleCurve为0， ConstantCurve为4(57.1%)，Stream(使用Optimal模式这部分数据将储存为Dense)为3(42.9%)。 裁剪精度后，大小为2.1kb，ConstantCurve为7(100%)，Stream为0(0%)。裁剪完精度后导致ConstantCurve增加了3，Stream(Optimal模式下即为Dense)减少了3，BlobSize减小了0.1kb。 因此，可以看出，通过精度优化降低内存的方式，其实质是将曲线上过于接近的数值（例如相差数值出现在小数点4位以后）直接变为一致，从而使部分曲线变为constant曲线来降低内存消耗。 总结 隔壁项目组对他们项目中所有的动画文件都进行了优化。其中文件大小从820MB->225MB, ab大小从72MB->64MB, 内存大小从50MB->40MB。总的来说动画文件的scale越多优化越明显。 取BlobSize代码 AnimationClip aniClip = AssetDatabase.LoadAssetAtPath<AnimationClip> (path); var fileInfo = new System.IO.FileInfo(path); Debug.Log(fileInfo.Length);//FileSize Debug.Log(Profiler.GetRuntimeMemorySize (aniClip));//MemorySize Assembly asm = Assembly.GetAssembly(typeof(Editor)); MethodInfo getAnimationClipStats = typeof(AnimationUtility).GetMethod("GetAnimationC…

技术分享连载（六十七）
type: item
date: 2017-06-13T05:03:00+03:00
description: 本期我们聚集了这些话题：资源泄漏、ETC压缩后图片质量模糊、降低动画文件的浮点数精度、iOS内存的提升... 我们将从日常技术交流中精选若干个开发相关的问题，建议阅读时间15分钟，认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系我们，一起探讨。 UWA QQ群：465082844 UWA 问答社区：answer.uwa4d.com 资源管理 Q1：使用AssetBundle.Unload(true)释放AnimationClip , 但发现AnimationClip在Profiler看到还存在，请问要怎样才释放干净呢？ 如果这个AnimaitonClip是从AssetBundle中加载过来的，那么当这个AssetBundle调用unload(true)时，该AnimationClip理论上是会被强行卸载的。如果Profiler中查看还有，那么只有两种情况： （1）仍然存在的AnimationClip是从其他地方加载来的，而不是来自于该卸载的AssetBundle； （2）Unity引擎的Bug，这种概率不是没有，但很小。 此问答来自于UWA 问答社区： https://answer.uwa4d.com/question/5937adc70ded23f1039c67ff 如您对该问题仍有疑问，可以转至社区进行进一步交流。 资源管理 Q2：如何处理ETC压缩完图片质量模糊和ARGB32内存占用太大这种关系？ 研发团队可以从参考以下几个方法： 1）使用ETC压缩的图片尽量减少过渡，这是美术制作时需要注意的，很多情况下并不需要明显的过渡，只是需要半透明而已； 2）当然，有部分过渡色是必须的，这时候就要把相关小图整合到一张RGBA32的图片上； 3）在资源管理上入手。一般情况下，我们是允许部分资源使用RGBA32，但是要注意，及时卸载掉不使用的资源，以保证内存峰值在可控范围内。 感谢UWA 问答社区的郑骁提供了以上回答。 在我们团队里面有一个意识，品质高和性能好有些时候是一对矛盾，有些情况要无损压缩是很难做到的。我们目前如果ETC压> 缩效果不好的，会使用RGBA32并降一个尺寸规格来压缩，这样虽然图片会模糊点，但是过渡还是平滑的。 感谢UWA 问答社区的邓永健提供了以上回答。 此问答来自于UWA 问答社区： https://answer.uwa4d.com/question/593629f27780cfc82fa5f867 资源管理 Q3：如何降低动画文件的浮点数精度？之前UWA给过思路，但具体怎么个执行方法？ 动画文件后处理可以做两件事，1）精度压缩，2）scale曲线剔除。比起用工具修改原始fbx文件，这样比较灵活。 实际测试，在开启Optimal压缩的情况下，加上这个后处理，能再节省40%左右。 void OnPostprocessModel(GameObject g) { // for skeleton animations. List<AnimationClip> animationClipList = new List<AnimationClip>(AnimationUtility.GetAnimationClips(g)); if (animationClipList.Count == 0) { AnimationClip[] objectList = UnityEngine.Object.FindObjectsOfType (typeof(AnimationClip)) as AnimationClip[]; animationClipList.AddRange(objectList); } foreach (AnimationClip theAnimation in animationClipList) { try { //去除scale曲线 foreach (EditorCurveBinding theCurveBinding in AnimationUtility.GetCurveBindings(theAnimation)) { string name = theCurveBinding.propertyName.ToLower(); if (name.Contains("scale")) { AnimationUtility.SetEditorCurve(theAnimation, theCurveBinding, null); } } //浮点数精度压缩到f3 AnimationClipCurveData[] curves = null; curves = AnimationUtility.GetAllCurves(theAnimation); Keyframe key; Keyframe[] k…

技术分享连载（四十八）
type: item
date: 2017-01-17T04:00:00+02:00
description: 本期话题：频繁GC是否能真正提升手游流畅度？如何优化UI中的动静元素？关于UI Panel重绘，你需要知道的一些Tips、动画文件定格位移不一致，如何切换？ 精选5个性能优化问题，建议阅读时间15分钟，认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系我们，一起探讨。 UWA QQ群：793972859 动画 Q1：我有一个带位移动画A，有位置有旋转的变化，需要播完这个动画后切换到一个原地的动画B。现在我发现动画A没播放就会切换到B了，导致一些位移数据并没有作用到模型上，这种情况怎么处理？ Mecanim动画系统提供了“Apply Root Motion”功能来满足两个动画文件顶点位移不一致的切换的需求。当开启“Apply Root Motion”功能后，角色的GameObject位置会随着动画的更新而更新，因此，问题中的A切到B后，GameObject的位移将不会改变。建议该研发团队检测GameObject Animator组件的“Apply Root Motion”功能是否开启。 性能优化 Q2：关于GC优化，Unity官方文档中有如下两个推荐的方法，请问在手游上是否适用？（1）频繁GC，隔几秒主动调用一次，保证不需要的堆内存能够及时释放。适用于对内存总量较小的情况。（2）尽量避免GC，可以考虑先撑大内存。 上述两种方法在目前的移动游戏中并不适用。 （1）中频繁地调用GC是否会降低GC的CPU开销吗？理论上会，但实际上，即便是降低后的GC开销也会导致频繁的卡顿。下图为UWA上一款实际测评项目在红米Note2上频繁调用GC的开销。可以看到在红框处，其GC调用非常频繁，但是其CPU占用并没有因频繁调用而降低。 （2）中尽可能避免GC是非常推荐的，但撑大堆内存的方式是欠妥当的。最好的方式是通过降低不必要的堆内存分配来尽可能避免的GC的到来。UWA建议GC的调用频率应该在1000帧/次以上。具体的做法建议查看我们之前的技术推送：Unity内存的深度剖析。 性能优化 Q：如下图所示，什么情况下会触发MaskableGraphic.Enable() ？现在我得到的结论是只要用到了Image组件，然后禁用启用带有这个组件的物体，都会触发进而产生GC。大家都怎么显示隐藏图片这种需求的，SetActive这种方式容易产生GC。 在UGUI中，Image组件并没有重写其父类的OnEnable函数，所以在激活时会出现MaskableGraphic.OnEnable。其中出现堆内存开销的话，通常是因为其父类函数Graphic.OnEnable中，UGUI在进行全局容器的Add等类似的操作时，遇到了扩容等产生堆内存的操作。 总之，在UGUI中，UI元素的激活和禁用所导致的堆内存分配，通常是不会持续出现的，其实不需要特别地处理。但对于其CPU开销，在UI元素数量较大时，依然是可观的，所以我们依然建议，对于激活禁用操作较为频繁的UI元素，可以尝试通过移出屏幕，缩放为0等方式来避免SetActive的调用。 UI 性能 Q：UWA建议“将较多的动态UI元素分组放在不同的UI Panel中”，那么请问如果是ScrollView里面多个item的话，是否意味着每个Item都加一个Panel会更好一些？ “动态元素”其实是相对的。在 ScrollView 中，一般情况下，如背包，其中的Item在滑动过程中是相对静止的，因此这种情况下只需要将这些Item放在一个UIPanel中即可。但在类似于聊天界面中，存在一些UI元素是有持续的动画的，那么就需要考虑对这类元素进行特殊处理，可以尝试将这部分有动画的UI放在独立的UIPanel中，或者在个数不多的情况下，各自变为一个UIPanel等。 UI 性能 Q：如果我在UIPanel下面放的是Sprite Renderer而不是NGUI的Sprite，是否会引起整个UIPanel的重绘？ 在NGUI中使用Unity2D的Sprite有两种情况，一种是直接使用Unity2D的SpriteRenderer组件，这种情况下，NGUI和Unity2D之间是互不影响的，只是在深度的设置上相对会比较麻烦一些。另一种是使用NGUI的UI2DSprite组件，而该组件是NGUI对Unity2D的SpriteRenderer组件上进行封装的，方便使其深度与其他UI元素进行穿插，因此其行为和其他的UI元素一致，在某些情况下是有可能引起UIPanel的重绘。 今天的分享就到这里。也欢迎热爱进步的你加入UWA的QQ群（793972859），也许你的方法恰能解别人的燃眉之急；而他山之“石”，也能攻你之“玉”。 比起闭门造车，我们更乐意与大家各抒己见，畅所欲言；比起形而上的泛泛而谈，我们更乐意与大家直击痛点，对症下药。