拓展机器人工具箱:Unity 2022.1的Physics功能更新

ANTHONY YAKOVLEV / UNITY TECHNOLOGIESContributor
May 12, 2022|6 Min
Hero image
3D rendered wagon on Unity user interface
拓展机器人工具箱:Unity 2022.1的Physics功能更新

使用新的反向动力学力传感器来模拟可感知环境的复杂机器人。完全重做后的Physics Debugger将助你更好地分析力的相互作用。此外,插值、批量查询等功能的性能也得到了改进。

物理调试器(Physics Debugger)改进

物理调试器(Physics Debugger)是了解物理引擎内部运作的重要工具,也是观察项目内特殊物理行为的主要手段。一个好的调试器在编写逼真、现代、丰富的物理模拟上起着关键作用。基于这点考虑,我们重新设计了调试器的用户界面(UI)并增加了一些有趣的功能。

为了在相同的空间内容纳更多的信息,我们将各个属性分为几组标签,并且还添加了几组新的检测属性。

Unity user interface menu

此前,Rigidbody和ArticulationBody组件在检视器内包含有一个可折叠的“Info”部分,它展开后会显示当前线性矢量等其他信息。但这样导致编辑器的整体性能出现了明显的下降。在以前,比较多个运动物体的参数很复杂,你需要同时打开两个检视器面板。为了解决这些问题,我们把所有的属性都转移到了物理调试器(Physics Debugger)窗口的“Info”选项卡上,这里会显示每个被选中对象的属性,让你可以轻松地进行并列比较。

Unity user interface menu options

工具现在支持可视化物体的接触点、接触法线和间距。

Unity user interface with a red box and manipulation arrows pointing down

类似Physics.Raycast及Physics.CastSphere等Physics查询指令通常会被用于编写自定义的角色或载具控制器等物理行为。这些指令并不能在调试器中出现,调试起来也很棘手。为了应对这个问题,新版本的调试器支持有选择地可视化物理模拟的查询指令。

Unity user interface with shapes being moved around
反向动力学(Inverse dynamics)

到目前为止,Unity工具只支持所谓的正向动力学:给定一组物体及其作用力来计算其运动轨迹。这种方法固然非常有用,但我们想进一步扩展机器人工具箱的功能。因此,我们为Unity 2022.1添加了对反向动力学的支持:给定一个物体及其运动轨迹,模拟计算出作用力。

我们将在以后的数个版本持续迭代、完善该功能。在Unity 2022.1中,我们公开了一组函数用于计算当前作用于ArticulationBodies的力的组成,在这些力抵消之后物体才能向着预定的轨迹运动。我们会在后续版本中继续披露更多有趣的概念,比如抵消解算器冲力的关节力。我们欢迎大家亲自尝试一下,并在论坛上留下你的想法。

需要特别指出,新功能可以:

  • 取得施动者当前施加给某物体的。它可以表明某个驱动力向目标运动的强度。它的大小取决于驱动力的刚度(stiffness)和阻尼(damping),以及当前的目标位置和目标速度;
  • 取得抵消物体所受重力科里奥利力(Coriolis force)和离心力所需的关节力;以及
  • 取得物体达到特定加速度所需的关节力
Unity user interface manipulating two characters
<p>插值与外推法</p>

Rigidbody同时使用插值和外推法进行较低频率的模拟,形成一种平滑运动的表象。引擎内部会在每次更新(update)计算变换(transform)的位置来实现运动。在插值时,物体前两帧的姿势会被用于计算当前帧的姿势。在外推法时,仅上一帧的姿势和矢量会被用于计算。但由于它轻量的特点,我们不会将这些姿势传回物理引擎。它们只会被传给物理引擎以外的系统(比如图形和动画)。正因为如此,一条投射出去的光线并不能检测到插值姿态下的物体。

为了不让物理引擎注意到变换的改变,我们的机制是在写入姿势前调用Physics.SyncTransforms()来调取每次更新,再调用一个内部方法来清除Physics的所有变换更新。这造成了两类问题:

如果一个场景至少有一个插值物体,那么每次更新时,所有物理组件的变换改变都会与物理引擎同步(尽管这些改动主要会在每次FixedUpdate中被处理);并且

如果一个带插值Rigidbody组件的变换被改变,则该对象的插值就会中断,因为用户作出的变换修改被传到了物理引擎,并改变了最终的模拟姿势(姿势并不会被单独存储,而是会取代物理引擎当前的姿势)。

为了解决这些问题,我们特意将插值代码修改成不在每一帧上同步所有变换。这个改动显著提高了性能;新的插值代码比以前运行得更快(与场景复杂度相关)。

<p>对论坛反馈的回应</p>

我们的论坛包含有一个版块专门讨论各种实验性质的物理模拟技术,本次新版本中应用的部分改动就源于这里的讨论:

  • 许多项目,特别是大型项目,经常会设立多层GameObject,所以描述层与层关系以及两者物理接触的矩阵也会变得相当复杂。为了方便使用,我们在这个版本中会高亮显示当前选中的行和列。
image of grid being selected
  • 关节是连接两个刚体的部位,它确定了刚体相互间运动的范围。自Unity 2020.2起,关节支持将一个Rigidbody连接到一个ArticulationBody上。为此,每个Joint类都设立了一个额外属性,属性可在检视器中查看。该属性无法连接到Rigidbody和ArticulationBody,当一个组件已经设定完成,你就没必要再用额外的两个选项来占用空间。现在,只有设置好的属性会被显示出来。
Items in menu bar being selected
  • 纯运动刚体(kinematic Rigidbody)是一种特殊的物体,它可以对其他物体施加力,但又不受这些物体的影响。这时,它类似于一个静态但会移动的碰撞体。纯运动刚体的典型用法包括角色控制器、动画驱动的物理模拟、虚拟现实(VR)的手腕模拟等等。你可以通过设置一个运动目标来控制刚体,刚体会在一张模拟帧中完成这个运动目标。它与静态碰撞体的主要区别在于,纯运动目标并非以瞬时的传送(或姿势改变)达成的,而是通过计算某帧达成目标所需的线性和角矢量并将其传给解算器。这样一来,运动就能正确地出现在矩阵中,让每一对相连关节都能做出正确的反应(没有匪夷所思的物理)。在这个Unity版本中,我们公开了一个新方法,可在一次操作中同时设置运动目标的位置和转向。
  • 在Unity 2021.2中推出的接触修改(contact modification)带有一个微观阶段(narrow phase),让你能在结算器根据接触点生成运动约束之前修改点的细节。在这个版本中,我们为护相接触物体的速度添加了新的获取器(getter),以支持更高级的用法,比如该例子中的自定义各向异性摩擦
  • PhysX更新至4.x系列的最新版本:4.1.2。这个小型发布只解决比较重要的bug和崩溃。发行说明可在此处查看。
  • 当一个运动体与一个碰撞体重叠时,结算器需要求出一个矫正冲力,在满足所有约束的前提下将两者分开。在引擎内部,该冲力根据接触双方的接触点求得,它是一个所有接触点返回而来的总值。在这个版本中,我们公开了ContactPoint结构的一个新属性,让你能检索每个接触点上的冲力。
  • 我们正在密切关注关于ArticulationBody组件的社区反馈。为了方便创建和调整细微的机器人部件行为,我们会在屏幕空间内固定关节的限制把手,以防遮挡场景内的碰撞体。
zooming in on Unity object
  • 我们从Unity黑客周获得灵感并推出了物理模拟的批处理查询,它具备最基本的功能、可支持特定的几种用法。我们将继续开发并推出更多新功能、支持更多用法,比如更复杂的线程模式、更多多样的查询类型。在这个特别的版本里,批量查询可以在任意物理模拟场景下运行,且我们还增加了一种新的批量查询(Physics.ClosestPointCommand)。
  • 一块模型网格若想应用MeshCollider,网格本身首先须被烘焙完成。烘焙是一个极度耗费系统资源的过程,它会生成碰撞检测时所用到的空间搜索结构。通常情况下,每次MeshCollider的网格属性被改变时,烘焙都会在后台完成,但整个过程会运行在主线程上,占用所有资源直至完成。自Unity 2019.3起,我们就公开了一个线程安全的方法,让你能随时在主线程之外进行烘焙。这样做的目的是为了让程序化生成的网格能更为复杂,用Job来生成模型和烘焙网格可以大大提高线程的利用率。但这个功能有一个特别的缺点,它只支持默认烹饪选项下的烘焙。在新版本里,我们公开了一个新的Physics.BakeMesh变量,让功能支持用任意烹饪选项进行烘焙。

我们迫切地希望看到大家能用新的反向动力学API和改版后的Physics Debugger创作出的内容!现在就来下载最新的Unity 2022.1版本,并在机器人板块物理模拟预览板块加入讨论吧。