IIKChainControl

Reference Indices

The following enum constants are indices to the reference targets made by the IIKChainControl. For example, GetReference(IIKChainControl::kPBlockRef) will return a pointer to IParamBlock2. These reference indices are:

Parameter Block Indices

There is just one parameter block. Its index to Animatable::GetParamBlock() is given by enum constant kParamBlock.

Parameter Indices

The following enumerated constants represent the indices of the parameters in the parameter block:

Most parameters have separate querying methods. For example;

GetParamBlock( IIKChainControl::kParamBlock)>GetINode( IIKChainControl::kStartJoint)

will return turns the same pointer as does StartJoint(). The kStartJoing and kEndJoint parameters that define the IK Chain Delimiters can be obtained by using the INode* StartJoint() and INode* EndJoint() methods.

Swivel Angles

Most of the time, joints are drawn on a plane (planar IK chains). A desirable quality of an IK solver is not to disturb this plane. Those solvers would use only the Start Joint to rotate the plane. When the End Joint is adhered to the goal, the rotation about the axis from the Start Joint to the End Joint is called Swivel. Swivel angle is the amount of this rotation.

In order for the swivel angle to make sense, however, we need a reference point. When a chain is put at the preferred pose, meaning that all the joint angles are set to preferred angles, the plane expanded by the pivots of all the joints on the chain is called Initial Plane, and the axis from the Start Joint to End Joint is called Initial End Effector Axis (EEAxis). Since Preferred Angles are animation variable, so is the Initial Plane and EEAxis. The InitPlane() and InitEEAxis() methods return the normal to the Initial Plane and the unit vector of the Initial EEAxis. These are represented in the parent space of the Start Joint. To obtain the normal in object space, use the method ChainNormal(). The relationship between ChainNormal() and InitPlane() is (in pseudo code):

InitPlane() = ChainNormal() * StartJoint()->PrefRotation()

When the joints do not lie on a plane, the closest plane, in certain sense, can be used. Let's call this plane the solver plane.

The class ZeroPlaneMap is defined in IKHierarchy.h. This provides the functionality that, given a unit axis, which is to be substituted for by EE Axis, produces a unit vector, which will be interpreted as the normal to a plane. This plane will be taken as the zero plane to which the swivel angle is relative: the plane corresponds to swivel angle being zero. The amount of rotation that will bring the Zero Plane to the current solver plane is the Swivel Angle, which corresponds to the parameter of index kSwivel and can be obtained using the SwivelAngle() method. The following relationship holds (in pseudo code):

ChainNormal() * StartJoint()->Rotation() = ZeroPlaneMap(EEAxis) * <Rotation aboutEEAxis bySwivelAngle()>

A plugin solver may have its own ZeroPlaneMap. In case it does not have a preference, it can use the default one provided by the IK system as IKSys::ZeroPlaneMap* DefaultZeroPlaneMap().

The solver plane can be controlled by an extra node and this is often desired by the user. In this case, they want the solver plane to align with the plane defined by the Start Joint, the End Joint, and the extra node, called the swivel angle target. Since the target and the swivel angle are meant to control the same thing, only one of them can be used. The parameter of index kVHUseTarget determines which will be used. It is not animatable. If it is true, the swivel angle target will be used. The target node can be obtained from the parameter of index kVHTarget. When the target node is NULL, the swivel angle will be used.

Solver Properties

The method IKSolver* Solver() returns the IK solver whose responsibility it is to solve the IK problem. Its class name is stored as the parameter of index kSolverName. As mentioned, there is an animatable variable that determines, at a specific time, whether IK is enabled. Whether the solver is enabled or disabled can be checked using the SolverEnabled() method.

This is just an interface to the sub-controller with reference index kEnableRef. Since its value is used to determine whether joints in an IK chain depend on the IK goal when reference message is received, developers should not replace it, using the 3ds Max Reference APIs, with an arbitrary controller whose dependency structure is general. This would create a time variable dependency structure and is not desirable. The built in controller is a key-frame controller.

Sometimes, we still want to invoke IK by moving the goal even if SolverEnabled() is false. In such cases the purpose of IK is to set keys on the FK sub-controllers of the joints. The feature is called "Use IK to FK", which is only meaningful during an interactive session. For this purpose CanAutoEnabled() corresponds to the parameter of index kAutoEnable and indicates whether the feature of "Use IK to FK" is desired. The AutoEnableSet() method provides the transient state of the IK chain: whether IK is currently enabled due to this feature. It is only set, if it is ever set, during the next update cycle, with regard to when the goal is moved, or its TM is set to new value.

Valid IK Chains

A valid IK chain is one that has a good Solver, Start and End joints, where the Start Joint is an ancestor of the End Joint in the scene hierarchy. The Valid() and INode* GetNode() methods are available for this. The latter returns the node that holds it as its TM controller. The IK Chain Controller is not designed to be instanced. It is expected to have a unique node.

LinkChain - A LinkChain is a hierarchy of transformations. At the top is the RootLink and it is followed by a number of Link's . Each link, be it a RootLink or Link, evaluates to a matrix, called the link matrix (LinkMatrix). This matrix consists of two parts, one is a variable part (degrees of freedom) and the other is a relatively constant part, called rigid extend (RigidExtend). It can be graphically represented as:

RootLink - The link variable is a rotation, rotXYZ. The link matrix is defined as

RigidExtend * R x (rotXYZ.x) * R y (rotXYZ.y) * R z (rotXYZ.z)

where R x (.) stands for rotation about the x-axis, etc.

Link - The variable part of a Link is of one degree of freedom. It can be translational or rotational. A typical 3 degrees of freedom (xyz) rotational joint can be decomposed into 3 Links, with the first two being null links:

LinkChain - A LinkChain consists of a RootLink and a number of Link's. The reason that the LinkChain can start with rotation, the variable part of the RootLink, is that the IK system will collapse all the node transformations from the root of the scene to the parent matrix of the Start Joint and the translation part of the Start Joint, called the parent matrix, and transform the node hierarchy of the IK chain into this space. The author of the plugin solver does not have to be concerned about parentMatrix. They work on the problem as it is rooted at the origin of the world. The data structure of LinkChain should be sufficient for those solvers that DoesOneChainOnly() and UseSwivelAngle().