性能优化(12)编辑器创建资源优化(4)——物理

  1. 1. Unity中的物理
  2. 2. Unity下如何对默认物理部分进行优化
    1. 2.0.1. 工程设置与编辑器设置方面
  • 3. Collider与Rigidbody组件
    1. 3.0.1. Collider
    2. 3.0.2. Rigidbody
    3. 3.0.3. Unity中的RayCast与Overlap部分的优化
    4. 3.0.4. 柔体、流体部分的物理并不常用

  • Unity中的物理

    • Box2D
    • Nvidia PhysX
    • Unity Physics
    • Havok Physics for Unity

    • Unity中的默认2D物理解决方案是使用的开源Box2D库完成的,它是一套高效的2D刚体物理的C++代码库,也是在做2D物理游戏开发时经常选择的解决方案。
    • 而Unity中的3D物理默认解决方案是使用的Nvidia的PhysX库。这套库一直有一个比较大的问题,它是一套非确定性物理模拟库,也就是说,即使你两次输入相同的物理条件,依然会在后续模拟表现上呈现出不同的物理表现效果,这也让它在一些状态同步的网络游戏中无法做逻辑处理,而帧同步的网络游戏中又因其更新频率与渲染频率的不同,以及服务器演算物理时负载过重的问题,只能在一些客户端上做物理表现渲染
    • 为了物理模拟的确定性,Unity还推出了一套符合DOTS设计理念的新的物理库——Unity Physics。但它无法像英伟达的Physics那样提供完整的全套的物理模拟。只能在保证高性能的基础上实现一套更简单的功能子集。但它可以在单帧内完成多次物理模拟,以显示未来的预测,比较适合做网络游戏中的物理。虽然它无法做到基于显卡的硬件加速,但由于DOTS的存在它依然可以在一些多核CPU上做到比较高效的表现
    • 此外unity还提供了一套基于Havok物理库的物理解决方案,同样是符合DOTS的设计理念,数据也可以与Unity Physics通用,它可以用来增强Unity Physics包的功能,不过除需要安装额外的Pacage外,还需要在使用前得到微软Havok的授权

    Unity下如何对默认物理部分进行优化

    工程设置与编辑器设置方面

    • 如果是2D物理,通过Physics 2D标签设置;如果是3D物理,通过Physics标签设置
    • 这个界面最重要的是图形碰撞矩阵的设置。在默认没有配置的情况下,所有图层上的游戏对象都会默认创建与其他图层上所有对象的碰撞,这是相当低效的,所以我们需要为每种类型的对象定义不同的层,对于每个新图层,通过设置碰撞矩阵中与其他图层是否有碰撞关系来避免不必要的碰撞,以及在碰撞监听器上的检测。
    • 除碰撞矩阵外,Physics标签下还有许多选项,大部分情况下我们不需要修改,除非有一些特殊需求
    • Auto Sync Transform选项:这个选项是在Transform组件发生变化时,强制进行物理系统同步,相当于在修改Transform后立即强制执行一次对物理对象的模拟更新,这样会增加物理运算负担,一般不开启。不开启的情况下不是说不更新,而是要等到FixedUpdate过程再去对对象进行物理更新。大多数情况下不开启也能满足视觉表现效果
    • Reuse Collision Callbacks选项:这个选项应尽量保持开启,这样在物理引擎对所有碰撞回调时会重用之前的Coliision碰撞结果的实例,而不会为每个碰撞回调重新创建一个碰撞结果的实例。由于大多数情况下碰撞结果实例只是数值上的变化,重用已经创建好的碰撞结果实例可以降低托管堆上的GC开销
    • 物理解算器迭代次数的两个设置
    • Default Solver IterationsDefault Solver Velocity Iterations选项:分别与物理碰撞精度、与碰撞后物理模拟精度有关。迭代次数越高,模拟越精确。实际使用时可以根据自己项目上的物理模拟表现的精度来调整迭代次数,一般情况下选择默认设置就好,因为迭代次数越高,物理模拟计算开销越大
    • Broadphase Type选项:由于3D物理使用的时Physics SDK,在其中物理模拟扫描场景时有粗筛和细筛的阶段算法,相当于用场景划分来对物理场景进行查找加速。我们可以根据自己的场景物理物体的复杂度与场景特点去选择不同的算法,一般默认就好。如果你的场景真的过于复杂,再去根据实际情况选择另外两个选项

    • 在工程设置的Time标签下,对于FixedUpdate更新频率的设置。我们都知道,Unity默认情况下物理的更新都是在FixedUpdate中完成的。
    • 这里默认设置的0.02ms代表每秒更新50次,这个更新频率越高,物理计算开销越大
    • 对于一些低端手机如果帧率较低的情况下,50帧每秒的更新相当于每个渲染帧物理更新快2次了。可以适当降低一点物理的更新频率。但这个物理更新频率的降低也会带来一些副作用,比如对于一些高速运动的物理物体,如子弹,穿越比较窄的物理物体(如较薄的墙)时,当物理模拟更新频率不够高时,可能不会发生物理碰撞的回调,这时我们可以有两种方式来改善:
      1. 利用射线作为类似高速子弹的碰撞检测
      2. 利用两个渲染帧子弹的位置拉出一个包裹盒,再用这个包裹盒去与墙做碰撞检测
    • 我们如果在Physics标签下禁用了Auto Simulation选项后,我们可以在C#代码中通过调用Physics Simulate接口来手动在任何逻辑位置更新物理系统
    • Time标签下的Maximum Allowed Timestep选项:限制了物理计算FixedUpdate事件在帧率下降时允许更新的最大步长,如果大于这个时间会出现一些奇怪的物理行为。因此合理的阈值可以避免物理模拟的错误,一般这个值推荐在8-10个FPS之间,大概是0.1-0.16ms之间

    Collider与Rigidbody组件

    Collider

    • 物理模拟与物理碰撞不是一码事。物理碰撞只是物理对象之间发生的Collision与Overlap的回调,并不会对后续的物理反馈做模拟,因此我们需要检查我们的对象是否同时需要Collider与Rigidbody组件。如果只需要触发回调并不需要添加Rigidbody组件
    • Trigger与Collider
    • Unity Collider对象有很多种,如果能用简单的Collider替代复杂的对象的MeshCollider的话,尽量用简单的Collider。即使用多个简单的Collider代替一个复杂的MeshCollider也是值得的

    Rigidbody

    • Kinematic与Rigidbody
    • 当有物体需要按固定的方式去运动,并且能触发碰撞,同时能对其他刚体造成影响时,勾选isKinematic选项,它比rigidbody的物理开销小
    • 在Unity Profiler的物理模块中,勾选了is Kinematic选项的对象不会增加Rigidbody的数量

    Unity中的RayCast与Overlap部分的优化


    using Unity.Jobs;

    柔体、流体部分的物理并不常用