PhysX Actors

[ source: NVIDIA PhysX SDK Help documentation SDK v2.7.3]  

About the Ageia PhysX Actors

Actors are the protagonists of a simulation. In the current version of the SDK, actors have two basic roles: static objects, fixed in the world reference frame, or dynamic rigid bodies. We do not use the word "body" to describe all of them because body refers only to dynamic (moving) rigid bodies.

One important aspect of actors is that they can have shapes assigned to them. Collision detection ensures that the shape of one actor does not intersect with the shape of another actor. Shapes can also be used to trigger various behaviors when another shape intersects them. Shapes and Triggers are discussed in detail in the Collision Detection section.

Static actors’ primary purpose is collision detection, so they should always have shapes assigned to them. Dynamic actors, on the other hand, may represent abstract point masses, which can be connected with joints to form pendulums and similar mechanisms. It is possible, though not always necessary, to add shapes to such bodies. Kinematic actors are a special kind of dynamic actor.

According to the laws of physics, any rigid object of any shape may be perfectly represented by an intertia tensor and by a point mass located at the object's center of mass. This is the approach used by the AGEIA PhysX SDK and most other rigid body dynamics libraries. The SDK will optionally compute the inertia properties of the bodies using the assigned shapes, or the user can supply custom parameters.

The below images show three different ways that the same scene is represented: graphical, collision detection, and dynamics.

 

The graphical representation of a scene with two stacked teapots. This is what the user would see. The graphics engine works with the mesh and texture data needed for such a representation. This graphical representation is provided by the user and is not included in the Physics SDK.

The same scene, from the perspective of the SDK's collision detection functions. In this case the teapots are approximated with a set of bounding volumes. It is also possible to use a more accurate mesh representation.

Finally, the representation of the scene used for dynamics. The contacts provided by collision detection are associated with the frames representing the bodies' masses.

 

 

 

Creating Actors

Note: Some resources relating to actors are not released until the engine goes through a simulate() call. Therefore, you should not allow unrestricted repeated creation and deletion of actors without any intervening calls to simulate().

 

Actors:

An Actor is the main simulation object in the Ageia PhysX  physics world.

The actor is owned by and part of a Scene.

An actor by default will be static (fixed in the world).  Optionally an Actor can be a dynamic rigid body by setting the actor's description type (when created).  

 

If you change the type of an actor from static to dynamic or vice-versa you will need to ReBuild the PhysXforQuest scene via the Core Rebuild command.

 

Static Actors

Static actors do not have any of the dynamic properties discussed in the Rigid Body Properties section. Create a static actor by setting the body member to NULL in the actor descriptor.

Once the static actor is created, do not do anything with it. Even though operations such as changing the position, adding more shapes, or even deleting the static actor are not explicitly forbidden, they are not recommended for two reasons: 1) the SDK assumes that static actors are indeed static, and does all sorts of optimizations that rely on this property. Changing the static actor may force time consuming re-computation of such data structures, and 2) the code driving dynamic actors and joints is written with the assumption that static actors will not move or be deleted for the duration of the simulation, which permits a number of optimizations for this very common scenario. For example, moving a static actor out from under a stack of sleeping boxes will not wake these up, thus they will levitate in midair. Even if they are woken up, the collision response between moving static and dynamic actors is of low quality.

To achieve the behaviors of movable static actors, use 'kinematic' actors. Read about them in the Kinematic Actors section.

 

Reference Frames

The most important property of an actor is its pose (position and orientation) in the world. Because the SDK provides a good deal of flexibility in this area, it is important to understand some spatial relationships involved.

For example, suppose we would like to simulate a table. The table is modeled in 3d software using a rectangular table top and four rectangular legs. The table will be an art asset for a computer game, and it will be instanced and placed at various spots using a level editor.

Both high detail geometry and bounding boxes for the table top and legs are exported from the 3d software (either manually or automatically). The physics SDK is not concerned with the graphical representation, but the bounding boxes will be instanced in the SDK as shape objects. The image below shows what the table may look like in the game editor, along with its significant reference frames.

NOTE: To make things more interesting, our table has a large chunk cut from one leg.

The space in which all the actors are positioned is called the world or global space. A space is also sometimes called a frame or reference frame.

The actor object corresponding to the entire table has its own frame, the actor frame. This is also known as the local space of the actor. The actor frame is defined so that when placed at zero height in the world, the legs of the table touch the floor, making it easy for people editing the level to place tables in a simple way, eventually using the editor's snap-to-grid functionality to make sure the table is at a correct height. In other words, actor frames can be randomly placed and are usually chosen with other practical or artistic considerations in mind.

In regards to collision detection, the table is made up of five bounding box shapes. These have fixed poses relative to the actor frame. At its origin, defined as center, each box has its own local frame called the shape frame, oriented along the primary axis of the box. Other types of shapes have similar local frames defined. For example, the local frame of a triangle mesh is the space in which the triangle vertices are defined (which can otherwise be arbitrary).

Given the placement of shapes, the SDK computes the actor's center of mass, assuming it is dynamic. (You may manually specify a center of mass if preferred.) The center of mass is the point around which real physical objects rotate unless they are constrained in some way. The center of mass may have an orientation which is not always the same as that of the actor frame. In our example, the table is missing half of a leg. This makes the mass distribution a bit asymmetric, physically expressed by the center of mass frame's rotation. The center of mass frame is often abbreviated to body or mass frame. The center of mass pose is stored relative to the actor frame.

 

The NxActor methods,

setGlobalPose

setGlobalPosition

setGlobalOrientation

setGlobalOrientationQuat;

serve to position the actor frame in world space, and the corresponding get*() methods retrieve it.

Note that the method,

    getGlobalPose

is normally the most convenient way to obtain the actor's transform for rendering.

The methods,

setCMassLocalPose

setCMassLocalPosition

setCMassLocalOrientation;

set the mass frame's pose relative to the actor frame, or in other words, determine the actor's center of mass. This is computed and defaulted by the SDK to the correct values based on the mass distribution of the actor's shapes.

To set the pose of the component boxes (or other shapes) relative to the actor frame, the following methods of NxShape may be used:

    setLocalPose

setLocalPosition

setLocalOrientation;

Setting the position of an object directly is sometimes unavoidable (most commonly at the start of a simulation, or if you want to 'teleport' an object to a different place), but may also be convenient.

The SDK does not prevent you from setting the poses of constrained objects. For example, if you had a linked chain of bodies, and added a certain value to the bodies' positions, the simulation would continue without problem. However, if you changed the position of only one body, the simulation would try to fix the constraint error you have inadvertently introduced by applying huge forces to the bodies during the next time step. This may lead to the simulation failing or the scene 'exploding'. To summarize, setting the pose of objects directly is not necessarily a bad thing, just watch out that you don't accidentally pull joints apart or put bodies into each other - your collision detection system won't like it.

 

Rigid Body Properties

Dynamic actors have a set of special properties that are used for rigid body simulation. One additional property of a body is that it has a center of mass position and orientation, as discussed in the Reference Frames section. At this center point, some of the mass is concentrated; its spatial distribution is expressed using the inertia tensor. Another is that it has velocity. Forces may act on the body to produce the motion, as long as this is not prevented by colliding shapes or joints.

NOTE: All rigid body properties have a linear and angular version. The linear version is used in computations involving rectilinear motion along a path, and the angular version is used when the body is rotating. Most movement is a combination of both.

 

Linear Quantity
Angular Quantity
mass (scalar) inertia (3-vector) - The mass distribution of the body along its three dimensions.
position (3-vector) - The position of the body's center of mass relative to the actor's frame. orientation (quaternion or 3x3-matrix) - The orientation of the principal moments relative to the actor's frame.
velocity (3-vector) - Linear velocity. angular velocity (3-vector) - Represented as an axis of rotation with a length equal to the magnitude of the angular velocity.

force (3-vector) - The amount of force that is being exerted on this body.

torque (3-vector) - The amount of angular force that is being exerted on this body. Represented as an axis of rotation with a length equal to the magnitude of the angular velocity.

 

The Inertia Tensor

For developers lacking dynamics experience, inertia tensor may be the most unusual aspect of a body. As mentioned in the Rigid Body Properties section, its purpose is to describe the bodies mass distribution, which may not be available otherwise, since the actual shape is not always stored. Even if shapes are available, sometimes it is preferred to use mass settings not strictly compatible with the shapes in order to achieve some particular effect.

Thus the inertia tensor expresses how hard it is to rotate the shape in various directions. For example, one can intuitively imagine that a long thin cylinder (like a printing drum) is easy to turn along its length axis, but if it were suspended on a chain, it would be much more difficult to swing around (especially if you push it near the middle where the chain is attached, as opposed to the ends which give a great deal more leverage).

Formulas in high school physics books tell you how to compute the moment of inertia for a particular shape. Unfortunately, these entry-level books only give you a scalar value, which is the moment of inertia along some specified axis. In the SDK we need to use a matrix quantity, which describes the inertia along all possible axes. The inertia can be expressed either in the local space of the body or the global space, as can all vector or matrix quantities.

Internally, this matrix is decomposed into a rotation and a vector, which is both faster and more intuitive to use than the dense matrix because the rotation gives the center of mass an orientation relative to the actor.

When you create a body, you will want to specify a moment of inertia. The default is the identity, which is most likely inappropriate for your shape. The easiest option is to assign collision detection shapes to the actor, along with either a density or a total mass. The inertia tensor will be automatically computed from this data. You may, of course, set the tensor yourself (having computed it earlier with the previous method), which is more efficient.

 

Manual Computation of Inertia Tensors

At times, it can be useful to manually specify a center of mass and inertia tensor in actors with an uneven mass distribution (e.g., a toy with a spherical base and a weight at the bottom to make it stand up). Specifying an unusually low center of mass can enhance the effect.

By default, the SDK computes a center of mass and inertia tensor when the actor is created. However, the user can override this by setting the actor's massLocalPose, massSpaceInertia and mass for the body

 

Applying Forces and Torques

The most physics friendly way of interacting with a body is to apply external force. In classical mechanics, most interactions between bodies are typically solved by using force because of the following law:

    f = m a (force = mass * acceleration) Force directly controls a body's acceleration, and indirectly controls its velocity and position. For this reason, control by force may be inconvenient if you need immediate response. Its advantages, however, are regardless of what type you apply to the bodies in the scene, the simulation will be able to keep all the defined constraints (joints and contacts) satisfied. The spring and damper effector and gravity also work by applying force to bodies.

Unfortunately, applying large forces to articulated bodies at the resonance frequency of the system may lead to ever-increasing velocities, and eventually to the failure of the constraint solver to maintain the joint constraints. This is not unlike a real world system where the joints would simply break.

The forces acting on a body are accumulated before each simulation frame, applied to the simulation, and then reset to zero in preparation for the next frame. You can apply your own forces and torques to a body in a variety of ways. The relevant methods of NxActor are listed below. Please refer to the API reference to see further detail:

addForceAtPos

addForceAtLocalPos

addLocalForceAtPos

addLocalForceAtLocalPos

addForce

addLocalForce

addTorque

addLocalTorque;

 

 

Gravity

Gravity is such a common force in simulations that we have made it particularly simple to apply. If you need a scene-wide gravity effect, or any other uniform force field, you can apply the NxScene class' gravity vector using setGravity().

The parameter is the acceleration due to gravity vector. If you work with meters and seconds, this equals about a 9.8 magnitude on earth. It should point downwards in your scene. The force that will be applied at each body's center of mass is this acceleration vector multiplied by the actor's mass.

NOTE: Be careful changing gravity (or enabling/disabling) during the simulation.

 

Setting the Velocity

Setting a body's velocity will immediately get it moving in a certain direction. Setting its momentum is another option, which may be more convenient if you don't know the mass of the body but want its speed to depend on it.

If you set the velocity of a body and then run its scene, after the simulation is complete, the velocity of the body may no longer be what you specified. This is because the simulation overrides your settings if they are in conflict with a specified constraint. For example, if a ball is resting on a table and you give it a downward velocity, it will change back to 0 when the constraint is resolved in the solver. If you set the velocity of a chain link that is joined to other chain links, the velocity of the chain link you set will decrease, and the other chain links' velocity will increase, in order for the chain to stay together.

For linear velocity, note that it is the velocity of the actor's center of mass you set. If this does not coincide with the origin of the actor's frame, then the velocity of the actor frame may be different, if the actor is also rotating.

The methods of NxActor that help to set the velocity of a body are summarized below:

setLinearVelocity

setAngularVelocity

setLinearMomentum

setAngularMomentum

Note: Setting a velocity large enough to carry an actor outside of the range of a float is a user error and might produce artifacts; this situation should be avoided.

 

 

Static, Dynamic and Kinematic Actors

Static actors’ primary purpose is collision detection, so they should always have shapes assigned to them.

Dynamic actors, on the other hand, may represent abstract point masses, which can be connected with joints to form pendulums and similar mechanisms. It is possible, though not always necessary, to add shapes to such bodies.

Kinematic actors are a special kind of dynamic actor.

 

Static Actors

Static actors do not have any of the dynamic properties discussed in the Rigid Body Properties section. Create a static actor by setting the body member to NULL in the actor descriptor.

Once the static actor is created, do not do anything with it. Even though operations such as changing the position, adding more shapes, or even deleting the static actor are not explicitly forbidden, they are not recommended for two reasons: 1) the SDK assumes that static actors are indeed static, and does all sorts of optimizations that rely on this property. Changing the static actor may force time consuming re-computation of such data structures, and 2) the code driving dynamic actors and joints is written with the assumption that static actors will not move or be deleted for the duration of the simulation, which permits a number of optimizations for this very common scenario. For example, moving a static actor out from under a stack of sleeping boxes will not wake these up, thus they will levitate in midair. Even if they are woken up, the collision response between moving static and dynamic actors is of low quality.

To achieve the behaviors of movable static actors, use 'kinematic' actors.

 

Kinematic Actors

A kinematic actor is a special kind of dynamic actor that is not moved directly by the user nor by the SDK. This means that it does not move in response to user forces, gravity, collision impulses, or if tugged by joints. Further, this type of actor lacks real velocity or momentum.

Instead, it becomes mobile when the user sets a slightly different position with the moveGlobal*() functions. NOTE: Do not use the setGlobal*() functions to make the actor mobile; it will disable many of the advantages that kinematic objects provide, such as having the appearance of infinite mass and the ability to push regular dynamic actors out of the way.

The move command will result in a velocity that, when successfully carried out inside simulate() (i.e., the motion is not blocked due to joints or collisions), moves the body into the desired pose. After the move is carried out during a single time step, the velocity is returned to zero. Thus, the move command must be called in every time step so kinematic actors can continue along a path. This is because the move functions simply store the move destination until simulate() is called, so consecutive calls will overwrite the stored target variable.

To create a kinematic actor, first create a dynamic actor, and then set its kinematic flag either in the body descriptor or with NxActor::raiseBodyFlag(NX_BF_KINEMATIC). When you want the kinematic actor to become a normal dynamic body again, turn off the kinematic flag with clearBodyFlag(NX_BF_KINEMATIC). While you do need to provide a mass for the kinematic body as for all dynamic bodies, this mass will not actually be used for anything while the actor is in kinematic mode.

Kinematic actors are great for moving platforms or characters where direct motion control is desired.

Caveats

If a dynamic actor is squished between a kinematic and a static or between two kinematics, then it will have no choice but to get pressed into one of them. In future versions, it may be possible to have the kinematic motion blocked in this case.

Kinematic actors will collide with true dynamic actors but not with static actors. This may also change in the future.

When calling NxScene::simulate() with a value for elapsedTime which is not multiple of the sub step size, a different number of sub steps may be executed due to accumulated fractional sub steps. If there is a remainder, it will be accumulated until a whole sub step can be executed. The result is that kinematic actors may not move a constant distance each time step, since we have the requirement that the velocity is constant during a sub step.

 

Actor Descriptor.

This structure is used to save and load the state of NxActor objects.

If the body descriptor contains a zero mass but the actor descriptor contains a non-zero density, we compute a new mass automatically from the density and the shapes.

Static or dynamic actors:

 

Mass or density:

1) actorDesc.density == 0, bodyDesc.mass > 0, bodyDesc.massSpaceInertia.magnitude() > 0

Here the mass properties are specified explicitly, there is nothing to compute.

2) actorDesc.density > 0, actorDesc.shapes.size() > 0, bodyDesc.mass == 0, bodyDesc.massSpaceInertia.magnitude() == 0

Here a density and the shapes are given. From this both the mass and the inertia tensor is computed.

3) actorDesc.density == 0, actorDesc.shapes.size() > 0, bodyDesc.mass > 0, bodyDesc.massSpaceInertia.magnitude() == 0

Here a mass and shapes are given. From this the inertia tensor is computed.

 

Other combinations of settings are illegal.

 

When the SDK computes the inertia properties it uses the actor's shapes. For each shape, the shape geometry, shape mass (or density), and shape positioning within the actor are used to compute the body's mass and inertia properties.

Setting the individual masses or densities of the shapes of an actor is the most intuitive method to specify the mass, center of mass, and inertial properties of a multi shape actor in order to achieve correct behavior.

If the actor body has a mass, then the computed inertial properties of the actor are scaled to the specified body mass. Even then, the individual shape masses are still useful since they specify how that mass is distributed within the object. i.e. When specified, the actor/body mass properties have priority.

If you specify a shape density and an actor density then the two are multiplied together to obtain the effective density of the actor. So if you set the density of the actor to 2 and the density of the shape to 3 then the effective density of that shape will be 6.

When the sdk computes the inertial properties the default is to also compute the center of mass. To specify an actor's center of mass exactly but still let the SDK compute and diagonalize the inertia tensor raise NxActorDescBase::flags | NX_AF_LOCK_COM. In this case the center of mass (bodydesc.massLocalPose.t) will not be overridden and the computed inertial tensor will be transformed correctly so that it will be as if the volume integrals for the moments had been done from the specified point.

 

Kinematic Actors

A kinematic actor is a special kind of dynamic actor that is not moved directly by the user nor by the SDK. This means that it does not move in response to user forces, gravity, collision impulses, or if tugged by joints. Further, this type of actor lacks real velocity or momentum.

Instead, it becomes mobile when the user sets a slightly different position with the moveGlobal*() functions. NOTE: Do not use the setGlobal*() functions to make the actor mobile; it will disable many of the advantages that kinematic objects provide, such as having the appearance of infinite mass and the ability to push regular dynamic actors out of the way.

The move command will result in a velocity that, when successfully carried out inside simulate() (i.e., the motion is not blocked due to joints or collisions), moves the body into the desired pose. After the move is carried out during a single time step, the velocity is returned to zero. Thus, the move command must be called in every time step so kinematic actors can continue along a path. This is because the move functions simply store the move destination until simulate() is called, so consecutive calls will overwrite the stored target variable.

To create a kinematic actor, first create a dynamic actor, and then set its kinematic flag either in the body descriptor or with NxActor::raiseBodyFlag(NX_BF_KINEMATIC). When you want the kinematic actor to become a normal dynamic body again, turn off the kinematic flag with clearBodyFlag(NX_BF_KINEMATIC). While you do need to provide a mass for the kinematic body as for all dynamic bodies, this mass will not actually be used for anything while the actor is in kinematic mode.

Kinematic actors are great for moving platforms or characters where direct motion control is desired.

 

Caveats