Recreating Skin Clusters Using Matrix Math
So I originally wrote up a lot of text to explain how to use this technique to create a rivet that worked well for parallel evaluation. This technique does work for a rivet, but it's rarely more useful than the other rivet methods, so instead I decided to explain the techniques that I used and maybe people will come up with some other applications for them.
Recreating SkinCluster Math:
So imagine being able to skin a locator (or a really a transform matrix). You of course can't do that using a skinCluster node because skinCluster nodes use component positions as inputs and give component positions as output, and we want to input a matrix, and output a matrix.
So you may not have thought about the math behind skinClusters, so without getting too mathy lets think through what the skinCluster node does for each vert (I'm only covering linear skinning).
The skinCluster basically takes the vert and pretends it is parented to a joint in the skinCluster. When the joint is moved the vert moves with it. The skinCluster does this for every joint in the bindSet, So for every joint in the bindset you get the position that vert would be at if the vert were waiting 100% to that joint. Then it takes each position and multiplies them by the painted weight, and adds them all together. You probably already had a rough idea of how that worked but going through it step by step is going to help us when we....
So instead of a vert we have locator/matrix, and we want to create a node network that will give us the resulting world matrix if we parented the locator to each joint. We can do this using a simple matrix-based constraint, like this:
Using a multMatrix node perform the following
An offset matrix (the worldMatrix of the locator x the worldInverseMatrix of the joint)
(this value is set not connected)
The worldMatrix of the joint
So that will result in the worldMatrix of the locator if it were parented to any given joint.
Then we take all those resulting matrices and multiply them by the painted weight and add them together. We can do this easily using a wtAddMatrix.
We can then decompose the matrix and plug it into a locator. But it would have strange scale and shear transforms, so just don't plug those into the locator.
Recreating Blendshape Math:
So now we know we can perform skinCluster math on locators/matrices but what about blendShape math? Well again let's think about how blendShapes work.
Each blendShape target is associated with a translation of each vert. When you have multiple targets it multiplies that translation by the target weight and adds them together. So immediately we've run into an issue, blendShapes don't even care about orientation, so it looks like the math for a matrix would be pretty trivial. So let's try and redefine the question a bit. Imagine we have a little nurb surface with a rivet on it (that rivet represents our locator/matrix). Then we create two duplicate of that nurbs surface, and set up some joints and a skinCluster for each nurbs surface that drives them. Then we take those two duplicates and use them as targets of a blendShape for the the original surface with the rivet on it. Our mission is to find out what the matrix of that rivet would be.
So step one is to create the skinCluster math network for each of the skinClusters. So now you might think wee could just add those two matrices together but that's not quite right. Let's say the surface's starting position is 10 units up in the y axis. Even if we didn't move any of the joints, if we added the matrices together the resulting matrix would give us a a translation of 20 in the y axis. So what we actually need to do is calculate the delta matrix, by taking the resulting matrix from the two skinCluster node networks, and multiply them by the worldInverseMatrix of the locator (set this value don't connect it). Then we can add those two delta matrices together, and multiply them by the locators (worldMatrix (set this value don't connect it).
Sculpted BlendShape Targets:
If you have sculpted blendShapes that you want to use with this system, you basically just need to manually create the delta matrix manually by using a composMatrix node.
I originally looked into this stuff to create a rivet that worked well with parallel evaluation, but I think it'll be helpful down the road if I try to script out my own deformer, and if you come up with any cool uses for this math, let me know!