Accessing Skinning Information [MEL]

 

 

Skinning data in maya is stored in MFn::kSkinClusterFilter nodes. You will have probably noticed, that the hyper-graph display has become fairly complicated, but don't fear, accessing the data is made simple by the MFnSkinCluster function set.

The skin cluster basically takes two inputs, the bone hierarchy and an undeformed mesh shape. The original mesh "meshShape1Orig" is tweaked by the skin cluster to output the deformed mesh "meshShape".

The undeformed surface shape essentially holds surface information from when the surface was bound to the skeleton. It may at first seem sensible to get the bind pose information from "meshShape1Orig". This however is generally a bad idea because modellers and animators often make small tweaks to the mesh after it has been bound. By accessing the original mesh you will lose any of those tweaks.

Instead, it is better to set all meshes back to their bind pose and read the data in that position. There may however be one or two small problems with this. If the model uses IK, then the IK will actualy prevent you from going back to the bind pose.

It is therefore a good idea to disable IK before exporting, and then re-enable before exporting animation data. Luckily there are a couple of mel commands we can execute to do this :

// disable IK, expressions etc
doEnableNodeItems false all

// enable IK, expressions etc
doEnableNodeItems true all

The other problem is that if any other deformer types (eg FFD's) are influencing the surface shape, then we will not get back the original geometry, but the deformed version. We should therefore ensure that all deformers are also disabled when accessing the bind pose.

 

 

 

 

Finding all SkinClusters in a Scene

To access the skin cluster data you can iterate through the scene searching for all of the MFn::kSkinClusterFilter nodes.

 

 

 


#include<maya/MItDependencyNodes.h>

MItDependencyNodes it( MFn::kSkinClusterFilter );
for ( ; !iter.isDone(); iter.next() ) {
 

MObject object = iter.item();


OutputSkinCluster(object);

}



 

The Skin Weights

 

To access data on a skin cluster, you should use the MFnSkinCluster function set. This will provide us with the information about which geometry objects are affected (note, they may be Nurbs, meshes etc) and which bones are affecting those objects.

 

One small issue is that Maya will return to us weights for all influence objects, even if it has no influence. To get around this, The code on the right builds up a list of vertex weights that actually have an affect on the point.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


#include<maya/MFnSkinCluster.h>
#include<maya/MDagPathArray.h>
#include<maya/MItGeometry.h>
#include<maya/MFloatArray.h>

void OutputSkinCluster(MObject& obj)
{
 

// attach a skin cluster function set to
// access the data

MFnSkinCluster fn(object);
MDagPathArray infs;

unsigned int nInfs = fn.influenceObjects(infs);

// loop through the geometries affected by this cluster
unsigned int nGeoms = fn.numOutputConnections();
for (unsigned int ii = 0; ii < nGeoms; ++ii) {

 


unsigned int index;
index = fn.
indexForOutputConnection(ii);

// get the dag path of the ii'th geometry
MDagPath skinPath;
fn.
getPathAtIndex(index,skinPath);

// iterate through the components of this geometry
MItGeometry gIter(skinPath);

// print out the name of the skin cluster,
// the vertexCount and the influenceCount

cout<< "Skin " <<endl;
cout<< skinPath.partialPathName().asChar() <<endl;
cout<< "pointcount " << gIter.count() <<endl;
cout<< "numInfluences " << nInfs <<endl;

// print out the influence object names
for (unsigned int kk = 0; kk < nInfs; ++kk) {

  cout<< infs[kk].partialPathName().asChar() <<" ";

}

cout << endl;

for ( ; !gIter.isDone(); gIter.next() ) {

 


MObject comp = gIter.component();

// Get the weights for this vertex (one per influence object)
//

MFloatArray wts;
unsigned int infCount;
fn.
getWeights(skinPath,comp,wts,infCount);

if ( 0 != infCount &&
gIter.
index() == i &&
!gIter.
isDone())

{

 

unsigned int numWeights=0;
float outWts[40]={1.0f,0};
unsigned int outInfs[40]={0};

// Output the weight data for this vertex
//

for(unsigned int jj=0;jj!=infCount;++jj)
{

  // ignore weights of little effect
if(wts[jj] > 0.001f)
{
 
if(numWeights!=0)
{
  outWts[0] -= wts[jj];
outWts[numWeights]=wts[jj];

}
outInfs[numWeights] = jj;
++numWeights;

}

}
cout<< "\t" << numWeights ;
for(k=0;k!=numWeights;++k)
{

  cout << " " << outInfs[k]
<<
" " << outWts[k];

}

cout << endl;
gIter.
next();

}

}

}

}


 

 

 

There is one final problem to deal with. If the deformed surface type is a periodic NURBS surface, then Maya actually clamps control points together where the surface wraps around. This means that it will not return any skin weights for the clamped points.

This means that we must either replicate the clamping of these points (the Advanced Exporter uses this method) or we can simply duplicate the skin weights for those clamped points during the export process.

 

 

 

 

 

What Next?

Transformation Data

Polygonal Mesh Data


Nurbs Surface Data


Blend Shape Deformers

Rigid Skinned Surfaces

Lattice Deformers

index

Rob Bateman [2004]


[HOME] [MEL] [API]