Unity最佳实践-物理计算

发表于2018-05-10
评论0 7.2k浏览

参考文献: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

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引