Using ICE, you can create efficient rigs that don't require a huge hierarchy of control objects, but that instead calculate deformer transformations directly from the manipulators.
There is no universal recipe for making a rig. Each rig is a response to specific production needs. ICE provides great flexibility in this regard.
The rest of this section provides some general guidelines and recommendations for ICE-based rigs. For an example of a rig built on these principles, open the Kinematics_Rabbit_Rig.scn scene in the ICE subfolder of the Scenes folder of the XSI_SAMPLES project.
Separating Manipulators and Deformers
It is important to separate the manipulators (drivers) from the deformers (driven). This avoids cycles in evaluation, and also increases reuse and portability.
The driven hierarchy can be anything you like because it doesn't depend on traditional parents to propagate transformations. On the other hand, the manipulators can use traditional parenting for saving keys on local transformations.
Evaluating Deformer Transformations
It's a good idea to put all evaluations in a tree on a single object such as a null. The deformers' transformations can be calculated and stored as an array of matrices in a custom ICE attribute on the rig evaluation null. The array can be indexed by a deformer ID stored as a custom parameter on each deformer. The same custom property can be used to store other useful data, such as length (if you are using nulls instead of bones as deformers) and the ID of the previous deformer in the chain (for the purpose of calculating offsets).
You can use multiple groups to get data for similar elements in the rig, for example, a group for the first deformers in the legs, a group for the second deformers in the legs, and so on. This lets you pass the data for similar elements through the tree as arrays, effectively calculating the transformations of multiple elements at the same time. It also lets you easily add an extra leg or arm by adding the elements to the corresponding groups. When creating these groups you must select the elements consistently, for example first the left one and then the right one, so that the data in the arrays are coherent. If necessary, you can reorder elements in groups as described in Reordering Scene Objects in the Explorer [Interface and Tools].
Because you cannot set data on groups, each deformer needs to have a small ICE tree that gets and sets its transformation from the array on the rig evaluation null.
With a system like this, it is easy to change the rig's behavior by changing a single ICE tree. You can make fixes or even substitute a completely different tree, for example, to change a rig where a rabbit's transformations are driven by the hips as usual to one where the rabbit gets picked up by its ears.
If you need to initialize data for your rig, for example to store initial offsets based on Static_KineState properties, then you should do this in a separate ICE tree on a different null. This prevents the ICE tree from being re-evaluated unnecessarily and speeds up the execution.
Alternatively if your rig uses a simulation for secondary dynamics, you can use a tree in the Pre-Simulation region to initialize data. Operators in this region do not get updated after the first frame of a simulation. For more about using simulation with ICE kinematics, see ICE Kinematics and Simulation.