Unity最佳实践-物理计算
参考文献:https://unity3d.com/cn/learn/tutorials/topics/physics/physics-best-practices
层次(Layer)和层次碰撞矩阵(Layer Collision Matrix)
所有新建的GameObject默认处于 Default
层,该层中的所有物体都可以相互碰撞,这样会比较消耗性能。
应该为不同类型的GameObject设置不同的层,来设定哪些GameObject之间可以发生碰撞。
新添加的层默认设置为可与所以已存在的层发生碰撞,要在碰撞矩阵中去掉不必要的碰撞关系,以减少碰撞监听和碰撞事件。
碰撞矩阵界面位于 Edit-Project Settings-Physics : Layer Collision Matrix。
射线(Raycasts)
射线比较消耗性能,其性能开销与射线的长度和场景中的碰撞器(Collider)的类型关系密切。
下面列出一些优化射线性能的提示:
- 尽量减少射线的数量。
- 射线的长度够用即可。射线越长,引擎要检测的对象就越多。
- 不要在
FixedUpdate()
中使用射线,也尽量不要在Update()
中使用射线。 - 注意射线所检测的碰撞器的类型,MeshCollider 的射线处理性能开销非常大。
- 对于具有复杂网格的物体,一个比较好的解决方案是为其创建多个带有基础碰撞器的子对象,然后调整子对象碰撞器的形状到与父物体相近。
- 若确实需要使用MeshCollider,尽量将其设置为
convex
。
- 明确射线需要与哪些层发生碰撞,尽量在射线方法中使用层次遮罩。
- 射线方法中的
layerMask
参数用于设置层次遮罩,它是位掩码而不是层id。 - 要设置射线只与第10层(层id为10)的物体发生碰撞,layerMask参数应该为
1<<10
。 - 要设置射线不与第10层的物体发生碰撞,layerMask参数应该为
~(1<<10)
,不能省略括号。 - 可以通过
LayerMask.NameToLayer("LayerName")
方法获取层的id。 - 示例1:
Physics.Raycast(ray, out hit, 1 << 10)
。 - 示例2:
Physics.Raycast(ray, out hit, ~(1 << 10))
。
- 射线方法中的
刚体(Rigidbody)
刚体是在对象间进行物理交互所必须的组件,即使是只将碰撞器作为触发器(Tigger),也应该为对象添加刚体组件,这样可以确保 OnTrigger
事件正常工作。
当多个对象具有层级关系且子对象具有碰撞器时,只需在最外层的父对象上添加一个刚体即可,无需为每个子对象添加刚体。
不带有刚体的碰撞器对象会被引擎认为是 静态碰撞器(Static Collider)。要避免移动静态碰撞器对象,这一操作开销很大,因为这会导致引擎重新计算整个场景的物理数据。
Profile 窗口的 CPU Profile 栏会在移动静态碰撞器时输出警告(warning)。
这里我在Unity 5.6.3和Unity 2018.1.0中做了下测试,感觉反而是加了刚体之后每帧耗时增加了,Profile中也没看到警告,不知道是Unity内部做了升级还是我哪里没设置好,如果有人懂这里的改动,希望能给讲解一下!
Fixed时间步长(Fixed Timestep)
在时间管理器(Time Manager)中调整 Fixed Timestep
会直接影响到 FixedUpdate()
和 物理计算
的更新频率,通过更改该值来在物理计算精度和CPU消耗中寻求平衡。时间管理器界面位于 Edit-Project Settings-Time : Time Manager。