This post will outline the process I used to build a post-rig deformation system for better shaping of characters.
The goal of this system is to provide higher control over the shape and silhouette of characters, after the main pose. I saw a similar system from a paper written at Dreamworks called the "Contour Cage." I wanted to try to create something similar within Maya.
GOALS
Deformations like this could pretty easily be achieved by creating a local rig and piping the deformation into the render mesh via a blendshape, however, a solution like this would be rather expensive, and unable to take advantage of Maya's parallel evaluation.
With that in mind, I had a couple of main goals when developing this system:
1. The setup itself should be fast and fully optimized for parallel evaluation
2. To speed up the creation and maintain editability the only input would be a poly mesh. We can build the controls and skinning from this!
3. The system should be flexible enough to add onto most rigs
Overview
To give a rough overview of the system works:
First model an input mesh, we can skin this mesh and use it to drive a series of controls and bind joints.
The bind joints will be skinned to a duplicate of the mesh, and using the bindPreMatrix attribute of the joints deform the skin based on the offset between the bpm(bindPreMatrix) joint and the bind joint.
This skin cluster can finally be stacked on top of the existing skinCluster to produce the final deformation.
Data flow overview
The Input mesh
The control points for the rig are built from an input mesh called the cage mesh. This is a manually modeled mesh that fits the shape of the character, with resolution around the areas you want to control. Of course, there is a trade-off with the number of vertices and the speed of the rig later on so it's helpful to keep this mesh really low. I found that using N-gons can be a great trick to adding a bit more resolution where you need it (similar to the profile curves used at Pixar).
Deform Cage geometry for Diagoro
Later on, we will use the cage to create and drive the control points for the rig, but to make the system more intuitive it would be helpful to have them follow along with the rig. For this, we can skin the deformCage to the bind joints of the main rig. An important note here is that each vertex should maintain a maximum influence of 2. This will important later when we drive the controls from the cage.
The control Cage
The control cage will be used to drive the final deformation. Each control point has a small hierarchy consisting of an offset, control as well as two joints, a bind and a bpm (bindPreMatrix), these will come into play later!
Control Hierarchy for each control point
We can then pretty easily create a series of control points based on the vertex position and orient them to the vertex normals.
Now comes the fun part! Since we only skinned each vertex to a maximum of two joints we can now get the influences of the vertex and create a blended matrix constraint between the two influences with weights based on the weights from our skin cluster.
Each control point is weighted based on the skin cluster weights
Notice the skinCluster influence joints are connected as inputs to the blend matrix node, and the skin weight is used as a blend between the influences. Now when the rig is deformed the controls "stick" to the vertices, but they have a completely independent DG graph from the geometry!
While it may look like these controls are connected to the verts, they're only driven by their offset parent matrix.
One final thing I added to the controls was a way to display the connectivity of vertices, without this the controls tend to get lost and can be confusing as to what part of the body they control.
Even Daigoro doesn't know what these controls do!
For this, we can create a new NURBS curve with CVs connected to each control point of the rig. The result is a bunch of NURBS control points curves with connections to the controlPoint.position of the curve. Each Control point of the curve follows the appropriate rig Control, resulting in something that looks a bit like a lattice.
Complete connectivity display for Diagoro
Skinning and connecting
Finally, we need to connect our control rig points to the actual mesh. There are really two major parts to this step, skinning the deformation cage and connecting that deformation to the existing skinning.
Luckily we modeled a super nice low poly proxy earlier that we can also use for skinning the deformation cage. By smoothing it a couple of times and skinning it to the control cage joints we can get some really nice and smooth skinning.
Output high res-skinning proxy
We can now copy the skinning from the high res proxy geometry we created to the final mesh. Here the bpm joints we created earlier become super important. If we look back at the hierarchy they are parented under the offset but not the control. That means they follow along with the matrix connection to the bind joints, but not when we move the control.
If we connect the worldInverseMatrix of the bpm joints to the BindPreMatrix attribute of the skin cluster (following the order in which the influences were connected) we can essentially offset the 'bind pose' of the joints.
Example bpm matrix connections. For a real skin cluster you'd have tons of inputs so its easier to script this.
Connecting the bpm joints makes the deformation relative to the distance between the start(bpm) and end (bind). I like to think about this as converting the deformation from being based on a point, to a vector.
By repeating this setup on the skinned mesh we get a result that looks like this:
Deform cage skinCluster is calculated only from relative offsets. so it looks 'disconnected' from the main rig.
While this may look a bit awkward on its own, once this skin cluster is stacked on top of the existing skinning it works really nicely with the existing deformations. (for more information about stacking skin clusters check out Charles Waldraws article and course on rigging Dojo)
If you want to use this in your own projects or just dig into the code this is all written into my larger rigging system Rigamajig2 which you can check out here!