Maya API How-To #14

Back · Previous · Next Maya

How do I get accurate weights for a rigid bind - many Vertices report as having a weight of 1.0 but not all of them are members of the skin?

Yep.. I came across this problem as well. Seems to be a bug in reporting the weights for the Cluster components.

I solved it by maintaining a MSelectionList of the Cluster membership and, within my iteration, rejected components which aren't actually a member of the Cluster.

Here's an excerpt:

// obCluster: DG node of apiType MFn::kClusterFilter or MFn::kJointCluster.
// obMembers: Storage for Cluster membership.
MStatus exportClusters::GetClusterMembership( MObject & obCluster, MSelectionList & obMembers )
{
  MStatus                               status = MS::kSuccess;

  obMembers.clear();

  MItDependencyGraph                    itGraph( obCluster, MFn::kSet );

  if ( itGraph.isDone() )
  {
    // Throw an exception if no Set found.
    THROWERROR( MStatus( MS::kFailure ), "No Set available for GetClusterMembership" );
  }

  MFnSet                          fnSet( itGraph.thisNode(), &status );

  if ( status == MS::kSuccess )
  {
    // Get membership of set.
    status = fnSet.getMembers( obMembers, true );
  }

  return status;
}

// -----------------------------------------------------
// BEGIN EXCERPT FROM ::GetClusterWeights()

// obCluster: DG node of apiType MFn::kClusterFilter or MFn::kJointCluster.
exportClusters::GetClusterWeights( MObject & obCluster )
{

  // ...

  MFnWeightGeometryFilter             fnCluster( obCluster );

  // Cache Cluster membership as MSelectionList
  // for rejection of invalid weight results below.

  MSelectionList                      obMembers;
  GetClusterMembership( obCluster, obMembers );

  // Loop through the geometries affected by this Cluster.

  unsigned                            nGeometryInCluster;

  nGeometryInCluster =  fnCluster.numOutputConnections();

  for ( size_t ii = 0; ii < nGeometryInCluster; ++ii )
  {
    MDagPath                          skinPath;
    unsigned int                      index;

    index = fnCluster.indexForOutputConnection( ii, &status );
    if ( status != MS::kSuccess )
      continue;

    // Get the dag path for this geometry.
    status = fnCluster.getPathAtIndex(index,skinPath);
    if ( status != MS::kSuccess )
      continue;

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

    // Print out the path name of the skin, vertexCount & influenceCount.
    for ( /* nothing */ ; !gIter.isDone(); gIter.next() )
    {
      MObject comp = gIter.component(&status);
      if ( status != MS::kSuccess )
        continue;

      // Get the weights for this vertex (one per influence object).
      MFloatArray                 wts;

      status = fnCluster.getWeights( skinPath, comp, wts );
      if ( status != MS::kSuccess )
        continue;

      if ( wts.length() > 1 )
      {
        // I've never seen this happen.. 
        THROWERROR( status, "Not expecting more than a single weight value!" );
      }

      // *** NOTE: Here's the problem ***

      // MFnGeometryFilter::getWeights() returns a weight of 1.0 if
      // a component is NOT a member of the Cluster!  Use membership of
      // MSelectionList to reject invalid weights.

      if ( !obMembers.hasItem( skinPath, comp ) )
      {
        // The weighting reported for this component does not represent this Cluster.
        continue;
      }

      // Output the weight data for this vertex
      cout << gIter.index() << ": " << wts[0] << endl;

    }
  }

  // ...

}

Wednesday, June 13, 2001