Manual: Rigid Body Functions
Creating and Destroying Bodies
dBodyID dBodyCreate (dWorldID);
Create a body in the given world with default mass parameters at position (0,0,0). Return its ID.
void dBodyDestroy (dBodyID);
Destroy a body. All joints that are attached to this body will be put into limbo (i.e. unattached and not affecting the simulation, but they will NOT be deleted).
Position and orientation
void dBodySetPosition (dBodyID, dReal x, dReal y, dReal z); void dBodySetRotation (dBodyID, const dMatrix3 R); void dBodySetQuaternion (dBodyID, const dQuaternion q); void dBodySetLinearVel (dBodyID, dReal x, dReal y, dReal z); void dBodySetAngularVel (dBodyID, dReal x, dReal y, dReal z); const dReal * dBodyGetPosition (dBodyID); const dReal * dBodyGetRotation (dBodyID); const dReal * dBodyGetQuaternion (dBodyID); const dReal * dBodyGetLinearVel (dBodyID); const dReal * dBodyGetAngularVel (dBodyID);
These functions set and get the position, rotation, linear and angular velocity of the body. After setting a group of bodies, the outcome of the simulation is undefined if the new configuration is inconsistent with the joints/constraints that are present. When getting, the returned values are pointers to internal data structures, so the vectors are valid until any changes are made to the rigid body system structure.
dBodyGetRotation()returns a 4x3 rotation matrix.
Mass and force
void dBodySetMass (dBodyID, const dMass *mass); void dBodyGetMass (dBodyID, dMass *mass);
Set/get the mass of the body (see the mass functions).
void dBodyAddForce (dBodyID, dReal fx, dReal fy, dReal fz); void dBodyAddTorque (dBodyID, dReal fx, dReal fy, dReal fz); void dBodyAddRelForce (dBodyID, dReal fx, dReal fy, dReal fz); void dBodyAddRelTorque (dBodyID, dReal fx, dReal fy, dReal fz); void dBodyAddForceAtPos (dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); void dBodyAddForceAtRelPos (dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); void dBodyAddRelForceAtPos (dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); void dBodyAddRelForceAtRelPos (dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz);
Add forces to bodies (absolute or relative coordinates). The forces are accumulated on to each body, and the accumulators are zeroed after each time step.
RelForce and ...
RelTorque functions take force vectors that are relative to the body's own frame of reference.
ForceAtPos and ...
ForceAtRelPos functions take an extra position vector (in global or body-relative coordinates respectively) that specifies the point at which the force is applied. All other functions apply the force at the center of mass.
const dReal * dBodyGetForce (dBodyID); const dReal * dBodyGetTorque (dBodyID);
Return the current accumulated force and torque vector. The returned pointers point to an array of 3
dReals. The returned values are pointers to internal data structures, so the vectors are only valid until any changes are made to the rigid body system.
void dBodySetForce (dBodyID b, dReal x, dReal y, dReal z); void dBodySetTorque (dBodyID b, dReal x, dReal y, dReal z);
Set the body force and torque accumulation vectors. This is mostly useful to zero the force and torque for deactivated bodies before they are reactivated, in the case where the force-adding functions were called on them while they were deactivated.
void dBodySetDynamic (dBodyID); void dBodySetKinematic (dBodyID); int dBodyIsKinematic (dBodyID);
Bodies in the "kinematic" state (instead of the default, "dynamic" state) are "unstoppable" bodies, that behave as if they had infinite mass. This means they don't react to any force (gravity, constraints or user-supplied); they simply follow velocity to reach the next position. Their purpose is to animate objects that don't react to other bodies, but act upon them through joints (any joint, not just contact joints). For contact joints against moving geometry it's still faster to use the contact's motion parameters in a joint attached to the world ("null body"). Joints between two kinematic bodies, or against a kinematic body and the world, are completely ignored.
Note: setting the mass on a kinematic body will make it dynamic again. Calling dBodySetDynamic restores the original mass, so it's just a shortcut to dBodyGetMass followed by dBodySetMass.
void dBodyGetRelPointPos (dBodyID, dReal px, dReal py, dReal pz, dVector3 result); void dBodyGetRelPointVel (dBodyID, dReal px, dReal py, dReal pz, dVector3 result); void dBodyGetPointVel (dBodyID, dReal px, dReal py, dReal pz, dVector3 result);
Utility functions that take a point on a body (
pz) and return that point's position or velocity in global coordinates (in
dBodyGetRelPointXXX functions are given the point in body relative coordinates, and the
dBodyGetPointVel function is given the point in global coordinates.
void dBodyGetPosRelPoint (dBodyID, dReal px, dReal py, dReal pz, dVector3 result);
This is the inverse of
dBodyGetRelPointPos. It takes a point in global coordinates (
z) and returns the point's position in body-relative coordinates (
void dBodyVectorToWorld (dBodyID, dReal px, dReal py, dReal pz, dVector3 result); void dBodyVectorFromWorld (dBodyID, dReal px, dReal py, dReal pz, dVector3 result);
Given a vector expressed in the body (or world) coordinate system (
z), rotate it to the world (or body) coordinate system (
Automatic Enabling and Disabling
Every body can be enabled or disabled. Enabled bodies participate in the simulation, while disabled bodies are turned off and do not get updated during a simulation step. New bodies are always created in the enabled state.
A disabled body that is connected through a joint to an enabled body will be automatically re-enabled at the next simulation step.
Disabled bodies do not consume CPU time, therefore to speed up the simulation bodies should be disabled when they come to rest. This can be done automatically with the auto-disable feature.
If a body has its auto-disable flag turned on, it will automatically disable itself when
- It has been idle for a given number of simulation steps.
- It has also been idle for a given amount of simulation time.
A body is considered to be idle when the magnitudes of both its linear velocity and angular velocity are below given thresholds.
Thus, every body has five auto-disable parameters: an enabled flag, a idle step count, an idle time, and linear/angular velocity thresholds. Newly created bodies get these parameters from world.
The following functions set and get the enable/disable parameters of a body.
void dBodyEnable (dBodyID); void dBodyDisable (dBodyID);
Manually enable and disable a body. Note that a disabled body that is connected through a joint to an enabled body will be automatically re-enabled at the next simulation step.
int dBodyIsEnabled (dBodyID);
Return 1 if a body is currently enabled or 0 if it is disabled.
void dBodySetAutoDisableFlag (dBodyID, int do_auto_disable); int dBodyGetAutoDisableFlag (dBodyID);
Set and get the auto-disable flag of a body. If the
do_auto_disable is nonzero the body will be automatically disabled when it has been idle for long enough.
void dBodySetAutoDisableLinearThreshold (dBodyID, dReal linear_threshold); dReal dBodyGetAutoDisableLinearThreshold (dBodyID);
Set and get a body's linear velocity threshold for automatic disabling. The body's linear velocity magnitude must be less than this threshold for it to be considered idle. Set the threshold to
dInfinity to prevent the linear velocity from being considered.
void dBodySetAutoDisableAngularThreshold (dBodyID, dReal angular_threshold); dReal dBodyGetAutoDisableAngularThreshold (dBodyID);
Set and get a body's angular velocity threshold for automatic disabling. The body's linear angular magnitude must be less than this threshold for it to be considered idle. Set the threshold to
dInfinity to prevent the angular velocity from being considered.
void dBodySetAutoDisableSteps (dBodyID, int steps); int dBodyGetAutoDisableSteps (dBodyID);
Set and get the number of simulation steps that a body must be idle before it is automatically disabled. Set this to zero to disable consideration of the number of steps.
void dBodySetAutoDisableTime (dBodyID, dReal time); dReal dBodyGetAutoDisableTime (dBodyID);
Set and get the amount of simulation time that a body must be idle before it is automatically disabled. Set this to zero to disable consideration of the amount of simulation time.
void dBodySetAutoDisableAverageSamplesCount (dBodyID, unsigned int average_samples_count); int dBodyGetAutoDisableAverageSamplesCount (dBodyID);
To be written ...
void dBodySetAutoDisableDefaults (dBodyID);
Set the auto-disable parameters of the body to the default parameters that have been set on the world.
void dBodySetMovedCallback (dBodyID, void (*callback)(dBodyID));
Use it to register a function callback that is invoked whenever the body moves (that is, while it is not disabled). This is useful for integrating ODE with 3D engines, where 3D entities must be moved whenever a ODE body move. The callback must have the prototype
Damping serves two purposes: reduce simulation instability, and to allow the bodies to come to rest (and possibly auto-disabling them).
Bodies are constructed using the world's current damping parameters. Setting the scales to 0 disables the damping.
Here is how it is done: after every time step linear and angular velocities are tested against the corresponding thresholds. If they are above, they are multiplied by (1 - scale). So a negative scale value will actually increase the speed, and values greater than one will make the object oscillate every step; both can make the simulation unstable.
To disable damping just set the damping scale to zero.
Note: The velocities are damped after the stepper function has moved the object. Otherwise the damping could introduce errors in joints. First the joint constraints are processed by the stepper (moving the body), then the damping is applied.
Note: The damping happens right after the moved callback is called; this way it still possible use the exact velocities the body has acquired during the step. You can even use the callback to create your own customized damping.
dReal dBodyGetLinearDamping (dBodyID); dReal dBodyGetAngularDamping (dBodyID); void dBodySetLinearDamping (dBodyID, dReal scale); void dBodySetAngularDamping (dBodyID, dReal scale);
Set and get the body's damping scale. After setting a damping scale, the body will ignore the world's damping scale until dBodySetDampingDefaults() is called. If a scale was not set, it returns the world's damping scale.
void dBodySetDamping (dBodyID, dReal linear_scale, dReal angular_scale);
Convenience function to set both linear and angular scales at once.
dReal dBodyGetLinearDampingThreshold (dBodyID); dReal dBodyGetAngularDampingThreshold (dBodyID); void dBodySetLinearDampingThreshold (dBodyID, dReal threshold); void dBodySetAngularDampingThreshold (dBodyID, dReal threshold);
Set/Get the body's damping thresholds. The damping will be applied only if the linear/angular speed is above the threshold limit.
void dBodySetDampingDefaults (dBodyID);
Resets the damping settings to the current world's settings.
dReal dBodyGetMaxAngularSpeed (dBodyID); void dBodySetMaxAngularSpeed (dBodyID, dReal max_speed);
You can also limit the maximum angular speed. In contrast to the damping functions, the angular velocity is affected before the body is moved. This means that it will introduce errors in joints that are forcing the body to rotate too fast. Some bodies have naturally high angular velocities (like cars' wheels), so you may want to give them a very high (like the default, dInfinity) limit.
Miscellaneous Body Functions
void dBodySetData (dBodyID, void *data); void *dBodyGetData (dBodyID);
Get and set the body's user-data pointer.
void dBodySetFiniteRotationMode (dBodyID, int mode);
This function controls the way a body's orientation is updated at each time step. The
mode argument can be:
- 0: An "infinitesimal" orientation update is used. This is fast to compute, but it can occasionally cause inaccuracies for bodies that are rotating at high speed, especially when those bodies are joined to other bodies. This is the default for every new body that is created.
- 1: A ``finite orientation update is used. This is more costly to compute, but will be more accurate for high speed rotations. Note however that high speed rotations can result in many types of error in a simulation, and this mode will only fix one of those sources of error.
int dBodyGetFiniteRotationMode (dBodyID);
Return the current finite rotation mode of a body (0 or 1).
void dBodySetFiniteRotationAxis (dBodyID, dReal x, dReal y, dReal z);
This sets the finite rotation axis for a body. This is axis only has meaning when the finite rotation mode is set (see dBodySetFiniteRotationMode).
If this axis is zero (0,0,0), full finite rotations are performed on the body.
If this axis is nonzero, the body is rotated by performing a partial finite rotation along the axis direction followed by an infinitesimal rotation along an orthogonal direction.
This can be useful to alleviate certain sources of error caused by quickly spinning bodies. For example, if a car wheel is rotating at high speed you can call this function with the wheel's hinge axis as the argument to try and improve its behavior.
void dBodyGetFiniteRotationAxis (dBodyID, dVector3 result);
Return the current finite rotation axis of a body.
int dBodyGetNumJoints (dBodyID);
Return the number of joints that are attached to this body.
dJointID dBodyGetJoint (dBodyID, int index);
Return a joint attached to this body, given by
index. Valid indexes are 0 to n-1 where n is the value returned by dBodyGetNumJoints.
dWorldID dBodyGetWorld (dBodyID);
Retrieves the world attached to the given body.
void dBodySetGravityMode (dBodyID b, int mode); int dBodyGetGravityMode (dBodyID b);
Set/get whether the body is influenced by the world's gravity or not. If
mode is nonzero it is, if
mode is zero, it isn't. Newly created bodies are always influenced by the world's gravity.
dGeomID dBodyGetFirstGeom (dBodyID); dGeomID dBodyGetNextGeom (dGeomID);
Give access to all geoms associated with a body. Use dBodyGetFirstGeom() to retrieve the first geom, then call dBodyGetNextGeom() with the previous geom as argument, to retrieve the next.