当前位置: 代码迷 >> 综合 >> Unity 之 Physics 一
  详细解决方案

Unity 之 Physics 一

热度:36   发布时间:2023-11-21 16:34:14.0

Rigidbody overview

 Rigidbody 组件是打开物理引擎的窗口,当它挂在到物体上时,物体会立即响应重力,如果还有collider组件的话,回响应碰撞

因为Rigidbody组件接管了它所附加的GameObject(游戏物体)的移动,你不应该通过改变Transform属性(如位置和旋转)来移动物体,相反,你应该施加力force来推动GameObject并让物理引擎physics engine计算结果。就是带有刚体组件的物体,它的移动应该用rigidbody.addforce来驱动,这样物理引擎就会模拟它的运动,更真实

在某些情况下,你可能希望GameObject(游戏物体)有一个刚体,而不需要物理引擎来控制它的运动. 比如:你想直接从脚本当中控制人物的走动,但是还想要触发器触发而不是碰撞,这种非物理运动称之为 kinematic运动学运动 .  Rigidbody组件有个Is Kinematic属性,用来把本身脱离掉物理引擎的控制,允许运动学运动,该属性可以通过脚本来打开或关闭,但是这样耗性能。

Sleeping

当一个刚体运动的速度低于设定的速度之后,物理引擎就假设它已经停止了,可以认为它进入了休眠模式,直到它重新受到力或者碰撞运动起来,这种优化意味着,在Rigidbody下一次被“唤醒”(即再次启动)之前,处理器不会花费时间来更新它。

但是,如果一个只有Collider组建的物体Static Collider (that is, one without a Rigidbody),是不能被唤醒的, 它的运动时通过改变transform的位置来实现的.可以使用WakeUp函数显式地唤醒GameObject.

 

Colliders

Collider 组件定义了碰撞体的形状physical collisions.

Compound colliders

Compound colliders 组合碰撞体通常是由很多小碰撞体组成的,它来定义一些单个碰撞体不能代表的形状;当您创建一个像这样的复合碰撞器时,您应该只使用一个Rigidbody组件,放在层次结构中的根对象上。

 

Mesh colliders

3D中, Mesh Colliders 完全匹配物体的形状t, 2D中, the Polygon Collider 2D 并不能完全匹配sprite的形状,但是你可以细化形状一个 mesh collider不能和另一个mesh collider发生碰撞,即它们接触时不会发生任何事情,但是你可以打开Mesh Collider中的 Convex 属性, 这样就可以碰撞了

这样做的好处是一个凸网格碰撞器可以与其他网格碰撞器碰撞.

Static colliders

Colliders 只有collider组件没有rigidbody组件的物体称为Static colliders, 比如地板,墙体,在运行时不能更改这些静态碰撞体的位置,否则会很耗性能,即拥有 Collider组件也有Rigidbody组件的物体称为动态碰撞体 dynamic colliders. Static colliders 可以和动态碰撞体交互,但是它们碰撞后不会发生移动.

Physics materials

当发生碰撞时,它们的表面需要模拟出碰撞之后的属性. 例如,一层冰会很滑,而一个橡皮球会有很多摩擦,很有弹性.虽然碰撞体的形状没有发生改变,但是可以通过Physics Materials来模拟弹力和摩擦力 .例如将有零(或非常低)摩擦和橡胶材料具有高摩擦和近乎完美的弹性.r Physic Material 和 Physics Material 2D不同是: 3D asset 叫 Physic Material 没有s, 2D 叫 Physics Material 2D 有s

Triggers

 但是,您也可以使用物理引擎来检测一个碰撞器何时进入另一个碰撞器的空间,而不会造成碰撞.  collider 组件勾选上Is Trigger 属性,物理引擎不会把它作为一个实体,允许其它物体通过,通过OnTriggerEnter 方法检测

碰撞发生的条件:至少有一个物体有一个Is Kinematic不勾选的碰撞体和刚体组件,如果两个物体都勾选上了

Is Kinematic属性,则  OnCollision Enter方法不会触发

 

Collider interactions

Colliders根据Rigidbody组件的配置方式不同,它们之间的交互也不同。有三种不同的配置 Static Collider (ie, no Rigidbody is attached at all), the Rigidbody Collider and the Kinematic Rigidbody Collider.

Static Collider

有 Collider 但是没有 Rigidbody. Static colliders 用于始终停留在同一位置,从不移动的水平几何图形,与之碰撞的rigidbody对象会发生碰撞,但不会移动它。

理引擎假设静态碰撞器不会移动或改变,并且可以基于此假设进行有用的优化. 因此,静态碰撞器不应该在游戏中被禁用/启用,移动或缩放。如果你改变了一个静态碰撞器,那么这将导致额外的内部重新计算的物理引擎,这将导致一个主要的性能下降. 更糟糕的是,这些改变有时会使对撞机处于未定义的状态,从而产生错误的物理计算。例如,对改变后的静态对撞机的光线投射可能无法检测到它,或者无法在空间中的随机位置检测到它。如果你想要一个collider对象不受碰撞体的影响,但可以从脚本中移动它,那么你应该附加一个a Kinematic Rigidbod运动学刚体组件,就是添加rigidbody组件,打开is Kinematic 属性

Rigidbody Collider

有 Collider ,Rigidbody,且is Kinematic关闭. Rigidbody 刚体碰撞是完全模拟的物理引擎,可以从脚本中施加力,它们可以与其他对象碰撞(包括静态碰撞器),是使用物理的游戏中最常用的碰撞器配置。

Kinematic Rigidbody Collider

有 Collider 和一个a kinematic打开的 Rigidbody. 你可以通过脚本改变它的位置,但是他们不会受到里的影响
运动学刚体应用于可偶尔移动的碰撞器,否则应像静态碰撞器一样工作. 比如一个滑动门,通常应该作为一个固定的障碍,但可以在必要时打开。与静态对撞机不同,运动刚体会对其他物体产生摩擦,并在其他刚体接触时“唤醒”它们。

即使在静止状态下,运动刚体碰撞与静止碰撞也有不同的行为。如果你想要接收到触发的消息,需要添加一个刚体组件. 如果不想要被接收到触发事件,勾选上刚体组件的 IsKinematic

可以通过 IsKinematic 实时更改其状态

一个常见的例子是“布偶”效应,即一个角色通常在动画下移动,但由于爆炸或严重碰撞而被物理抛出. 每个角色的肢体可以被赋予自己的刚体组件,默认情况下是IsKinematic enabled. 通过动画,肢体会正常运动,直到所有肢体的IsKinematic都被关闭,它们会立刻像物理物体一样运动.在这一点上,一个碰撞或爆炸的力量将使人物的四肢飞出。

 

Joints

 Joint组件连接把一个Rigidbody和另一个 Rigidbody 或者是点连接起来. Joints对移动的刚体物体施加力,限制它的运动, Joints 给刚体以下自由度:

 

Property: Function:
Character Joint 模仿球窝关节,如臀部或肩部。约束刚体在所有线性自由度上的运动,实现所有角度的自由。刚体附着在一个特征关节上,围绕每个轴和枢轴转动。
Configurable Joint 模仿任何骨骼关节,就像布偶。您可以配置此关节,以强制和限制刚体在任何自由度的运动。
Fixed Joint 限制刚体的运动,使其跟随所附刚体的运动。当你需要容易分开的刚体,或者你想要连接两个刚体的运动而不需要转换层次结构中的父类时,这是很有用的.就是两个单独层级的物体的运动
Hinge Joint 将一个刚体与另一个刚体或空间中的一个共享原点上的点相接触,并允许刚体从该原点绕特定的轴旋转。适用于模拟门和手指关节。
Spring Joint 保持刚体之间的距离,但让它们之间的距离稍微拉伸。弹簧的作用就像一块橡皮筋,试图将两个锚点拉到完全相同的位置。

例如,当刚体施加的力超过某个阈值时,可以将关节设置为断开。一些关节允许在连接的刚体之间产生一个驱动力,使它们自动运动。

 

Character Controllers

在第一人称或第三人称游戏中,角色通常需要一些基于碰撞的物理机制,这样它就不会从地板上掉下去,也不会穿过墙壁. 通常情况下,角色的加速和移动在物理上是不真实的,所以它可以在几乎不受动量影响的情况下瞬间加速、刹车和改变方向。

在3D物理中,这种行为可以通过Character Controllers来创建,这个组件给了角色一个简单的,胶囊状的碰撞器,它总是垂直的。控制器有自己的特殊功能来设置物体的速度和方向,但不像真正的对撞机,它不需要刚体

 character controller 无法在场景中通过静态碰撞器
,因此将遵循地板和被墙壁阻挡. 它可以在运动时将刚体物体推到一边,但不会因碰撞而加速
. 这意味着你可以使用标准的3D对撞机来创建一个场景,控制器可以在其中走动,但你不受角色本身的现实物理行为的限制。

 

Continuous collision detection (CCD)

CCD 确保快速移动的物体与物体碰撞,而不是通过这些物体,或通过隧道。Unity提供了以下CCD方法:

  • Sweep-based CCD
  • Speculative CCD

要设置 sweep-based CCD, 设置刚体 RigidBody的 Collision Detection 属性为 Continuous or Continuous Dynamic.要设置speculative CCD, 设置 Collision DetectionContinuous Speculative.

Sweep-based CCD

Sweep-based CCD 使用碰撞时间(TOI)算法计算一个物体的潜在碰撞,通过扫描其前进轨迹使用其当前速度. 如果在物体的运动方向上有接触点,算法计算碰撞时间,并将物体移动到该时间.该算法可以从那时起执行子步骤,计算TOI之后的速度,然后重新扫描,以牺牲更多的CPU周期为代价。

然而,由于该方法依赖于线性扫描,忽略了物体的角运动,当物体以一定速度旋转时,会产生隧道效应.例如,弹珠机的弹珠一端是固定的,围绕一个固定点旋转。flipper只有角运动,没有线性运动。因此,它很容易错过弹珠的碰撞:

A thin stick GameObject with its Continuous Dynamic property enabled. When rotating quickly around the pivot point, the stick doesn’t make contact with the sphere.

一个很薄的GameObject 设置为Continuous Dynamic 属性 当快速旋转时, 不会和球发生碰撞

 

此方法的另一个问题是性能。如果你有大量的高速物体与CCD靠得很近,由于额外的扫描,CCD开销会迅速增加,而物理引擎必须执行更多的CCD子步骤。

Speculative CCD

Speculative CCD 通过增加一个对象的边界,基于对象的线性和角运动 ,这个算法是推测性的,因为它在接下来的物理步骤中选择所有可能的接触点。然后将所有接触点输入求解器,以确保满足所有接触约束,从而使对象不会通过任何碰撞。就是根据当前的速度和角度生成了一个推测性的区域,检测这个区域可能存在的最近的点

下图显示了一个从t0移动的球体,如果在它的路径上没有墙壁,它在t1的期望位置是怎样的. 通过使AABB与它的目标位姿膨胀,推测算法获得了与n1和n2法线的两个接触点。然后,算法告诉触发器这些碰撞点,这样球体就不会通过墙壁隧道。

Inflated AABB 基于当前的速度,检测所有潜在的触发点

Speculative CCD比 sweep-based 性能好,因为他只在接触阶段检测,不是实时检测,并且他是根据角速度和线速度一起来检测的,所以不会漏掉点

A thin stick GameObject with the Speculative CCD enabled. When rotating quickly around the pivot point, the stick makes contact with the sphere and a collision occurs.

一个很薄的 Speculative CCD 打开的物体. 会和小球发生碰撞

speculative CCD 会造成 ghost collision, 一个物体的运动受到一个不应该受到的推测的接触点的影响。这是因为推测的CCD是基于最近点算法来采集所有可能的接触点,所以接触法线的精度不高. 这通常会使高速物体沿着镶嵌的碰撞特征滑动并跳起来,尽管它们不应该这样做. 例如,在下面的图中,一个球体从t0开始向右水平移动,预测位置为t1. An inflated AABB 把box分为b0 and b1,  CCD在c0和c1处产生两个投机触点. 因为speculative CCD 使用最近点算法生成接触点, c0 有一个非常倾斜的法线, 类似一个斜坡

The solver assumes that the contact point at c0 is a ramp because the closest point algorithm generated an inaccurate contact normal

The solver

假设c0处的接触点是一个斜坡,因为最近点算法产生了一个不准确的接触法线 ,这样一个非常倾斜的法线使得t1在积分后向上跳,而不是直线前进:

A ghost collision generated at c0 causes the sphere to erroneously jump up instead of move straight forward

 

Speculative CCD 也会造成隧道效应,因为推测性接触只在碰撞检测阶段计算.如果碰撞在整合之后的外部发生了碰撞,就有可能穿过它

例如,下图显示一个球体从t0向左移动,而一根棍子顺时针旋转。如果球体从撞击中获得太多的能量,它可能会在t1离开膨胀的AABB(红色虚线矩形)。如果在AABB外发生了碰撞,如下面的蓝色方框所示,球体可能会直接穿过它的隧道。这是因为求解器只计算膨胀AABB内部的接触,在求解和积分阶段不进行碰撞检测。

The sphere with inflated AABB using speculative CCD, which only computes contacts during the collision detection phase, so tunnelling may occur

The sphere with inflated AABB using speculative CCD, which only computes contacts during the collision detection phase, so tunnelling may occur

 

Physics Debug Visualization

TWindow > Analysis > Physics Debugger.打开

  帮助你显示collider ,其它没啥作用

  相关解决方案