每天一点UWA:第十一周

字体

优化字体资源

方向:内存和数量峰值

  • 主要是因为在字体资源的使用过程中采用了不同的方式。比如一开始的UI没有考虑使用AssetBundle,从而直接从Resources或者其它文件夹加载了字体资源。而后面的UI又依赖了AssetBundle中的字体,虽然也没有主动load,但是因为unity在load asset的时候会自动加载(有待验证)所以导致字体资源又被加载一次。从而峰值数量会不止一个。
  • 内存:很多情况下我们对于一个字体库中的字体只是用了个别的,但是却加载了整个字体库。

image

优化方案

  • 字库裁切
    • 针对不同字体的应用场景,设计有效精简的裁切字库。
    • 需要注意同一个字体资源在AssetBundle内外可能都会有依赖,如果依赖不能避免,那么就要各自设计裁切字库。
  • 工具:FontSubsetGUI
    image

结果

image

UI

什么情况下会触发MaskableGraphic.Enable() ?现在我得到的结论是只要用到了Image组件,然后禁用启用带有这个组件的物体,都会触发进而产生GC。大家都怎么显示隐藏图片这种需求的,SetActive这种方式容易产生GC。

  • 在UGUI中,Image组件并没有重写其父类的OnEnable函数,所以在激活时会出现MaskableGraphic.OnEnable。其中出现堆内存开销的话,通常是因为其父类函数Graphic.OnEnable中,UGUI在进行全局容器的Add等类似的操作时,遇到了扩容等产生堆内存的操作。
  • 总之,在UGUI中,UI元素的激活和禁用所导致的堆内存分配,通常是不会持续出现的,其实不需要特别地处理。但对于其CPU开销,在UI元素数量较大时,依然是可观的,所以我们依然建议,对于激活禁用操作较为频繁的UI元素,可以尝试通过移出屏幕,缩放为0等方式来避免SetActive的调用。

UWA建议“将较多的动态UI元素分组放在不同的UI Panel中”,那么请问如果是ScrollView里面多个item的话,是否意味着每个Item都加一个Panel会更好一些?

  • “动态元素”其实是相对的。在 ScrollView 中,一般情况下,如背包,其中的Item在滑动过程中是相对静止的,因此这种情况下只需要将这些Item放在一个UIPanel中即可。
  • 但在类似于聊天界面中,存在一些UI元素是有持续的动画的,那么就需要考虑对这类元素进行特殊处理,可以尝试将这部分有动画的UI放在独立的UIPanel中,或者在个数不多的情况下,各自变为一个UIPanel等。

如果我在UIPanel下面放的是Sprite Renderer而不是NGUI的Sprite,是否会引起整个UIPanel的重绘?

  • 在NGUI中使用Unity2D的Sprite有两种情况,一种是直接使用Unity2D的SpriteRenderer组件,这种情况下,NGUI和Unity2D之间是互不影响的,只是在深度的设置上相对会比较麻烦一些。
  • 另一种是使用NGUI的UI2DSprite组件,而该组件是NGUI对Unity2D的SpriteRenderer组件上进行封装的,方便使其深度与其他UI元素进行穿插,因此其行为和其他的UI元素一致,在某些情况下是有可能引起UIPanel的重绘。

模型&动画

有一个带位移动画A,有位置有旋转的变化,需要播完这个动画后切换到一个原地的动画B。现在我发现动画A没播放就会切换到B了,导致一些位移数据并没有作用到模型上,这种情况怎么处理?

  • Mecanim动画系统提供了“Apply Root Motion”功能来满足两个动画文件顶点位移不一致的切换的需求。当开启“Apply Root Motion”功能后,角色的GameObject位置会随着动画的更新而更新
  • 因此,问题中的A切到B后,GameObject的位移将不会改变。建议该研发团队检测GameObject Animator组件的“Apply Root Motion”功能是否开启。

删除模型上动画的缩放

link

  • 防止将来翻不出去了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
void Apply(GameObject g)
{
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);
}

int count = 0;

foreach (AnimationClip theAnimation in animationClipList)
{
foreach (AnimationClipCurveData theCurve in AnimationUtility.GetAllCurves(theAnimation))
{
string name = theCurve.propertyName.ToLower();
if (name.Contains("scale"))
{
for (int i = theCurve.curve.keys.Length - 1; i >= 0; i--) {
theCurve.curve.RemoveKey(i);
}
string propertyName = theCurve.propertyName;
// we can't delete "*.x", e.g. m_LocalScale.x - but only "*", e.g. m_LocalScale
if (propertyName.IndexOf(".") > 0) {
propertyName = propertyName.Substring(0, propertyName.IndexOf("."));
}
Debug.Log(string.Format("Fixing: {0} - {1}", theCurve.path, propertyName));
theAnimation.SetCurve(theCurve.path, theCurve.type, propertyName, null);
count++;
}
}
}

int checkCount = 0;
foreach (AnimationClip theAnimation in animationClipList)
{
foreach (AnimationClipCurveData theCurve in AnimationUtility.GetAllCurves(theAnimation))
{
string name = theCurve.propertyName.ToLower();
if (name.Contains("scale"))
{
checkCount++;
}
}
}

if (count > 0)
{
Debug.Log("Total number of removed curves is " + count + ". GO name: " + g.name);
Debug.Log("Number of remaining scale curves is " + checkCount);
}
}

渲染

物体的动态合批条件和是否是透明物体没什么关系吧?比如粒子系统的物体一般都是透明的,是不是也可以合批?

  • 动态合批并不限制物体是否为半透明或不透明物体。
  • 合批的首要要求是Material一致,其本身是半透明Material还是不透明Material均没有限制。
  • 粒子系统同样是可以合批的,只要其材质一致,深度较为接近且中间没有其他材质的物体阻隔,那么Unity引擎将会将其进行合批。
  • 查看Unity引擎的官方文档:https://docs.unity3d.com/Manual/DrawCallBatching.html
# UWA
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×