Unity 性能优化三:动画模块、物理模块

目录

动画模块

Mecanim 模块

1.1 Animator active的数量

1.1.1 Culling Mode

1.1.2 Optimize Gameobject

1.1.3 Apply Root Motion

1.1.4 Compute Skinning

1.1.5 Animator Initialize

1.2 Legacy动画

物理模块

2.1 物理更新次数

2.1 减少不必要的Collision

2.5 Auto Simulation

2.6 RaycastCommand

2.7 碰撞产生GC

2.8 Raycast、BoxCast、OverlapBox等函数产生的GC


动画模块

Mecanim 模块

1.1 Animator active的数量
1.1.1 Culling Mode

1. 设置animator的culling model,主要是针对视野中看不到的动画体,animator 更新的内容主要有:Retarget、IK、回传的transform信息

Always animate: 看不见也都更新,UI要使用

Culling Update Transform:不更新上面的部分,但逻辑,根节点还是更新的,依然可以收到 OnAnimatorMove 回调,即位置保持更新,动画不再,其他动画将被跳过,比如骨骼动画,IK,OnAnimatorIK,一般推荐使用这个,但是有的复杂动画,在进入视野时会有问题,如果有问题,更改为Always animate

Culling Completely:看不见完全不更新,比如静态的花草动画,不更新也没关系

它主要影响playerloop里面的 Animator.Update()方法的耗时

1.1.2 Optimize Gameobject

在模型导入的RIG 栏中,勾选该选项,native层的骨骼数据,将不会回传到c#层,默认开启

它主要影响playerloop里面的 MeshSkinning.Update(),勾选后,将在主线程计算Animator.WriteJob

1.1.3 Apply Root Motion

对不需要使用根节点的动画,不勾选这个,它的耗时主要体现在Animator.ApplyBuiltinRootMotion函数,当该函数的耗时占比较高时,需要确认场景中Animator对象是否都需要产生位移。

1.1.4 Compute Skinning

在projectsetting 里面,可以勾选这个,表示是否是有GPU加速计算骨骼动画

经uwa测试,开启之后耗时比不开始还大,主要是主线程在等待GPU计算

1.1.5 Animator Initialize

每次setactive或Instantiate激活一个带有animator的组件,会调用这个方法,可以把该物体的animator组件关闭,然后把物体移出屏幕外

1.2 Legacy动画

Animation.Sample的调用次数显示了场景中实际在更新的Animation对象的数量,而它的父节点Animation.Update的调用次数则是显示了场景中存在的Animation对象的数量。因此,优化Legacy Animation动画耗时则是要减少Animation.Sample的调用次数。

物理模块

2.1 物理更新次数

1. Unity物理系统的性能瓶颈主要体现在CPU端的耗时,它的主要耗时函数为FixedUpdate.PhysicsFixedUpdate。在开启Physics设置时,它的主要耗时堆栈是Physics.Processing和Physics.Simulate,需要针对这两个函数进行优化。

影响原因:

调用次数越多则耗时也就越高,调用次数受到Projectsetting->Time->Maximum Allowed Timestep和Fixed TimeStep的影响

Maximum Allowed TimeStep决定fxf了单帧物理最大调用次数,该值越小,单帧物理最大调用次数越少,一般为8~10FPS;Fixed TimeStep决定了FixedUpdate的更新间隔,该值越大,每帧物理更新调用次数越少

当游戏卡顿时,单帧耗时比较长,则在下一帧会调用多次物理模拟,去跟上当前的时间进度 

2.1 减少不必要的Collision

1. Physics Layer中取消不必要的层之间的碰撞检测,避免多余的Contacts的产生。

2. 尽量不要使用MeshCollider,如果非要用,可以勾选在Projectsetting->Prebake Collision Meshes

3. collider 只控制碰撞结果,不进行物理模拟

4. 如果不使用碰撞模拟,只想要触发结果,可以用trigger替代,也可以使用Collider.Bounds实现替代Trigger,避免使用Unity的物理模块。Trigger触发是比较方便的能够使用非物理模拟的方式来进行替换的一种Collision,使用C#逻辑来替代掉Trigger可以降低部分物理模块的耗时。

6. 如果使用了rigidbody,尽量不要直接修改transform改变物体位置,这样会在物理系统里面重新计算其位置,使用add force、move position 

2.5 Auto Simulation

2. 如果项目不使用物理模拟,则在Edit>Project Settings>Physics关闭Auto Simulation选项,也可以通过脚本设置

3. Auto Sync Transforms,在Edit>Project Settings>Physics中开启或关闭,默认关闭,它表示是否在transform 发生改变时,同步到物理系统,关闭时,会把transform的变化缓存到数组里面,在fixedupdate的时候更新,也可以通过脚本设置

需要注意的是,关闭Auto Simulation的情况下,如果需要使用射线检测,则需要开AutoSyncTransform选项

2.6 RaycastCommand

如果射线比较多,可以使用RaycastCommand代替Raycas,在子线程中执行射线检测

2.7 碰撞产生GC

OnCollisionEnter/Stay/Exit 会将返回的的结果,生成新的实例,分配到内存中,所以会造成GC,可以在projectsetting->physics->勾选Reuse Collision Callbacks,默认开启,这样就不会生成新的实例,而是重复使用一个

2.8 Raycast、BoxCast、OverlapBox等函数产生的GC

这些函数,返回的结果都是一个单独的实例,分配到内存中,造成GC开销,使用其对应的NonAlloc版函数