Bullet Wrapper Using models - s76/libgdx GitHub Wiki
Model
and ModelInstance
are typically used for the visual representation of objects. btCollisionObject
or btRigidBody
are used for the physical representation of these objects.
To synchronize the location and orientation between a ModelInstance
and btRigidBody
, Bullet provides the btMotionState
class that you can extend. A very basic example of such synchronization is:
static class MyMotionState extends btMotionState {
Matrix4 transform;
@Override
public void getWorldTransform (Matrix4 worldTrans) {
worldTrans.set(transform);
}
@Override
public void setWorldTransform (Matrix4 worldTrans) {
transform.set(worldTrans);
}
}
Which you can use as follows:
btRigidBody body;
ModelInstance instance;
MyMotionState motionState;
...
motionState = new MyMotionState();
motionState.transform = instance.transform;
body.setMotionState(motionState);
Now the location and orientation of ModelInstance
will be updated (by Bullet) whenever the btRigidBody
moves. This approach is not restricted to ModelInstance
, it will work for any object that contains a Matrix4
transformation, like e.g. also Renderable
. Moreover, it is possible to add simple logic to a motion state, for example:
static class PlayerMotionState extends btMotionState {
final static Vector3 position = new Vector3();
Player player;
@Override
public void getWorldTransform (Matrix4 worldTrans) {
worldTrans.set(player.transform);
}
@Override
public void setWorldTransform (Matrix4 worldTrans) {
player.transform.set(worldTrans);
player.transform.getTranslation(position);
if (position.y < 0)
player.die();
}
}
Note that the transformation (location and rotation) of a btRigidBody
is typically relative to the center of mass (most commonly the center of the shape). When needed, a btCompoundShape
can be used to move the center of mass. It is advised to keep the origin of the visual model the same as the origin of the physical object. If this is not possible, then you can modify the transformation in the motion state accordingly.
Keep in mind that Bullet's transformation only supports translation (location) and rotation (orientation). Any other transformation, like scaling, is not supported.
The motion state has to be disposed when no longer needed: motionState.dispose();
.
A Model boils down to a bunch of triangles with some properties which are rendered with a specific transformation. It is optimized for rendering, not for physics. Therefore a Model is rarely useful for an efficient representation of a physics shape.
To understand why this is, consider a simple box model. The physics shape of a box would contain eight corners. The visual model however, will contain 24 corners (vertices). This is because the vertices are specified for each face of the box, where each vertex contains the "normal" of the face. Otherwise visual effects, like lighting, would not be possible. So, instead of a solid box, the visual model is actually made up of six independent rectangles. Theses rectangles (or the triangles it is made up) are infinitely thin, they have no volume. This makes it unsuitable for dynamic physics.
There are several more issues, e.g. a model typically contains more detail than would be needed for the physics. In fact, for some shapes it is possible to use a much cheaper collision detection algorithm than using the model's vertices. For example, in case of the box shape, it would be possible to use a single detection against a box, instead of a detection against the 12 triangles it is made of.
There are several ways to work around these problems, ranging from approximating a model using primitive shapes to using a dedicated model or sharing vertices between visual model and physics shape. The Bullet manual provides a decision chart to help you decide which method you should choose:
For the case of a static model, the Bullet wrapper provides a convenient method to create a collision shape of it:
btCollisionShape shape = Bullet.obtainStaticNodeShape(model.nodes);
In this case the collision shape will share the same data (vertices) as the model. This will include node transformation by using a btCompoundShape
if needed, but will not include any scaling applied to nodes.