setWorldTransform vs setCenterOfMassTransform in Ammo.js
In Ammo.js (the Emscripten port of the Bullet Physics engine),
positioning and moving rigid bodies requires a clear understanding of
how the engine tracks spatial coordinates. While both
setWorldTransform and setCenterOfMassTransform
are used to define an object’s position and rotation in 3D space, they
target different components of a physics body. Choosing the wrong method
can lead to unexpected physics behavior, visual jitter, or broken
collision detection.
The Core Difference
The fundamental difference lies in which coordinate system you are manipulating and how the physics solver processes the change:
setWorldTransformsets the transform of the underlying collision object. It updates the spatial coordinates of the collision shape itself, but it does not update the physics solver’s internal interpolation states or account for center-of-mass offsets.setCenterOfMassTransformsets the transform of the rigid body’s physical center of mass. It updates the collision shape’s position relative to its center of mass, synchronizes the motion state interpolation transforms, and ensures the physics engine calculates gravity, inertia, and forces correctly from the new position.
Under the Hood: How Bullet Physics Sees It
To understand why this distinction matters, it helps to look at the relationship between rigid bodies, collision shapes, and the center of mass.
1. The Role of the Center of Mass
In Ammo.js, all dynamic physics calculations (such as torque, angular velocity, and gravity) are calculated relative to the rigid body’s center of mass.
If you have a symmetrical shape (like a box or a sphere centered at
[0, 0, 0]), the local origin of the shape and the center of
mass are identical. However, for compound shapes or asymmetrical meshes,
the center of mass may be offset from the shape’s local origin.
setCenterOfMassTransformrespects this offset, moving the physical center of mass to the designated coordinates and rendering the collision shape relative to it.setWorldTransformignores the physical center of mass calculations, which can result in forces (like gravity) acting on the wrong point of the object.
2. State Interpolation and Jitter
Ammo.js uses interpolation to smooth out the visual representation of objects between physics simulation ticks.
When you call setCenterOfMassTransform, Ammo.js updates
both the current transform and the interpolation transform. When you
call setWorldTransform on an active dynamic rigid body, the
interpolation transform is left unchanged. This mismatch often causes
the object to “jitter” or snap back to its previous position during the
next physics frame.
When to Use Each Method
To ensure stable physics and smooth rendering, follow these usage guidelines:
Use
setCenterOfMassTransform when:
- Teleporting dynamic objects: If you need to manually move a dynamic rigid body (an object affected by gravity and forces) to a new position mid-simulation.
- Initializing rigid bodies: Setting the starting position of active physical objects.
- Applying manual offsets: Working with compound shapes where the visual mesh origin differs from the physical center of gravity.
Note: After calling setCenterOfMassTransform on an
active body, you should also clear its forces and linear/angular
velocities using clearForces(),
setLinearVelocity(), and setAngularVelocity()
to prevent leftover momentum from carrying over to the new
position.
Use setWorldTransform
when:
- Moving kinematic objects: Kinematic bodies are
driven manually by your code rather than the physics solver. Because
they do not rely on dynamic forces or center-of-mass calculations,
updating their position via
setWorldTransform(often through abtMotionState) is standard practice. - Working with static colliders: Moving non-dynamic scenery, ground planes, or triggers that do not have physical mass or inertia.