编程文汇

bullet物理引擎(4) 刚体

介绍

基本3d引擎里都有刚体的概念,u3d,ue,都有。
刚体动力学在碰撞检测模块的顶部实现。它增加了力量,质量,惯性,速度和约束。.

  • btRigidBody用于模拟单个6自由度的移动对象。 btRigidBody是从btCollisionObject派生的,因此它继承了其世界的tranform,摩擦和弹力,并增加线速度和角速度.
  • btTypedConstraint是刚体约束的基类,包括btHingeConstraint,btPoint2PointConstraint,btConeTwistConstraint,btSliderConstraint和btGeneric6DOFconstraint。
  • btDiscreteDynamicsWorld是UserCollisionAlgorithm btCollisionWorld,并且是用于刚体和约束的容器。它提供了stepSimulation来驱动模拟。
  • btMultiBody is an alternative representation of a rigid body hierarchy using generalized
    (or reduced) coordinates, using the articulated body algorithm, as discussed by Roy
    Featherstone. The tree hierarchy starts with a fixed or floating base and child bodies, also
    called links, are connected by joints: 1-DOF revolute joint (similar to the btHingeConstraint
    for btRigidBody), 1-DOF prismatic joint (similar to btSliderConstraint)。

刚体分类

There are 3 different types of objects in Bullet,这个分类基本和u3d里的分类类似:

  • 动态刚体:常见刚体,可以移动,受力的作用。
    • 质量大于0
    • 物理系统每一帧都更新动态刚体的的world tranform
  • 静态刚体
    • 零质量
    • 不能移动,只能碰撞
  • 运动刚体(Kinematic)
    • 0质量
    • 可以移动、旋转、碰撞,运动规律不受力的影响。但是它会单方面影响动态刚体:动态物体会被它推开。

所有这些都需要添加到动力学世界中。可以为刚体分配碰撞形状。此形状可用于计算质量分布,也称为惯性张量。

重心 Center of mass World Transform

The world transform of a rigid body is in Bullet always equal to its center of mass, and its basis also
defines its local frame for inertia. The local inertia tensor depends on the shape, and the
btCollisionShape class provides a method to calculate the local inertia, given a mass.
This world transform has to be a rigid body transform, which means it should contain no scaling,
shear etc. If you want an object to be scaled, you can scale the collision shape. Other transformation,
such as shear, can be applied (baked) into the vertices of a triangle mesh if necessary.
In case the collision shape is not aligned with the center of mass transform, it can be shifted to match.
For this, you can use a btCompoundShape, and use the child transform to shift the child collision
shape.

What's a MotionState?

MotionStates 是bullet中,把所有被模拟物体的transform状态同步到渲染引擎的一种机制。

在大部分情况下,渲染物体时,游戏主循环需要遍历所有被模拟的物体。并把每个物体的位置、朝向更新到渲染引擎。Bullet使用MotionStates来简化这个过程。

MotionStates还有其它好处:

  • 仅更新实际发了移动、旋转的物体到渲染层。如果渲染对象不移动,则每帧更新其位置都没有意义。
  • 你不紧急可以做渲染操作,还可以通过网络通知远端一个物体移动了需要远程更新。.
  • 插值计算往往只在屏幕可见的场景下才有意义,Bullet通过MotionStates管理物体插值。
  • You can keep track of a shift between graphics object and center of mass transform.
  • They're easy

插值 Interpolation

如果你通过btCollisionObject::getWorldTransform或者btRigidBody::getCenterOfMassTransform来获取物体的位置,得到是上次物理tick模拟的结果。很多时候,这个结构足够用了,但是对于渲染,你可能需要插值。bullet在setWorldTransform之前进行插值。如果想要非插值的位置,直接调用物体的btRigidBody::getWorldTransform()方法。

怎么用呢?

Bullet中有两处用到了MotionStates.

第一个是创建实体时。Bullet在物体进入模拟时从motionstate 获取物体的初始化状态

Bullet calls getWorldTransform with a reference to the variable it wants you to fill with transform
information

Bullet also calls getWorldTransform on kinematic bodies. Please see the section below。

After the first update, during simulation Bullet will call the motion state for a body to move that body
around

Bullet calls setWorldTransform with the transform of the body, for you to update your object
appropriately

所以要想实现MotionStates,继承btMotionState ,并重写getWorldTransform 和setWorldTransform。

DefaultMotionState

顾名思义,这是个MotionState的默认实现,可以直接用。
Although recommended, it is not necessary to derive your own motionstate from btMotionState
interface. Bullet provides a default motionstate that you can use for this. Simply construct it with the
default transform of your body:
btDefaultMotionState* ms =new btDefaultMotionState();

Kinematic Bodies (运动学物体,不受力学影响)

如果你想自己移动静态物体,那么就应该把它标记为kinematic,同时禁用sleeping/deactivation。这就意味着,Bullet每帧需要从btMotionState 获取物体的世界坐标。

body->setCollisionFlags( body->getCollisionFlags() |
btCollisionObject::CF_KINEMATIC_OBJECT);
body->setActivationState(DISABLE_DEACTIVATION);

如果你使用运动学物体,那么getWorldTransform 每帧都会被调用。这就意味着你的运动学物体应该有一个机制把物体的当前位置推送到motionstate(也就是通过motionstate来移动物体)。

模拟帧和插值帧

Bullet物理模拟的内部默认帧率是60赫兹(1/60=0.1667)。游戏本身可能有不同的帧率,甚至是变化的帧率。为了和游戏本身频率解耦,stepSimulation中内置了一种自动插值法:如果游戏的deltatime小于内部时间步长(0.1667),那么Bullet会插值worldtransform ,并把插值的worldtransform 发送到btMotionState,而不进行物理模拟;如果deltatime大于内部时间步长(0.1667),那么stepSimulation内可能会进行至少一次的物理模拟。用户可以用第二个参数,限制一次stepSimulation能模拟的最多步数。

刚体创建以后,他们的初始worldtransform 从btMotionState::getWorldTransform获得。档模拟开始后,新的worldtransform 会在stepSimulation中通过btMotionState::setWorldTransform进行更新。

Dynamic rigidbodies have a positive mass, and their motion is determined by the simulation. Static
and kinematic rigidbodies have zero mass. Static objects should never be moved by the user.
动态刚体有质量,他们的动作会被自动模拟。静态和运动学刚体没有质量。禁止移动静态物体