So I was exporting some skin animation when I got to the function MFnSkinCluster::getWeights I was horrified at the prototype. I have to pass in a dagnode for the mesh? the component? float arrays then influence count. Yuck I got to use a MItGeometry to get that component. Just give me the weights and indices.
So anytime that happens I hit up the node attribs to find a better way. The first attrib in the skin cluster is the weightList, which is a compound attrib array. There is an element in this array for every CV (vertex/position, the same positions you get from MFnMesh::getPoints()). The compound attrib in weightList is an array of weights.
So im thinking, "Hey thats exactly what I want... yea....thats it but how do I know which one of those weights goes to what bone??". So I look for another array that would have the bone indices... And of course there isnt one. So im freaking out until I open up the hypergraph and start checking out the array in my skin cluster. I open the first sub of my weightList and then the weights array in there. And then I notice that the logical index for these weights werent the same as the physical. So what do these logical indices mean and what are they used for. Ah they are the freaking bone indices. Freaking maya!
Now that I totally confused anyone reading this, lets look at the code:
// Get the weights through maya's plugs...
MFnSkinCluster skinFn(skinObj);
// This plug is an array (one element for each vertex in your mesh
MPlug weightListPlug = skinFn.findPlug("weightList");
// My weight list and bone indices list
std::vector weightsList;
std::vector<blas::vec4 > boneIndicesList;
weightsList.reserve(weightListPlug.numElements());
boneIndicesList.reserve(weightListPlug.numElements());
for(size_t curVert = 0; curVert < weightListPlug.numElements(); curVert++)
{
// Get the weights for the current vertex.
MPlug weightPlug = weightListPlug.elementByPhysicalIndex(curVert).child(0);
// I only allow a four bone influences
blas::float4 weights(0.0f, 0.0f, 0.0f, 0.0f);
blas::vec4 boneIndices(0, 0, 0, 0);
if(weightPlug.numElements() > 4)
{
std::cout << "Skin has more than four weights per vertex" << std::endl;
return MS::kFailure;
}
// For each of the weights for this vertex
for(size_t curWeight = 0; curWeight < weightPlug.numElements(); curWeight++)
{
// This weights logical index is the index to the bone that influences it
boneIndices[curWeight] = weightPlug.elementByPhysicalIndex(curWeight).logicalIndex();
// Get the weight.
weightPlug.elementByPhysicalIndex(curWeight).getValue(weights[curWeight]);
}
weightsList.push_back(weights);
boneIndicesList.push_back(boneIndices);
}
So it ends up that the weightList vector I made is a one to one mapping to the points I get from MFnMesh::getPoints(). Now that bone index indexes into the matrix arrays held in the skin cluster (bindPreMatrix which is the bind pose)