Accessing Blend Shape Data [MEL]



 

 

 

A blend shape deformer, tweaks a geometry object, in this case "originalGeometry" and will output the deformed geometry "deformedGeometry". It takes a number of variations of the input surface, in this case "faceShape1" and "faceShape2" which are associated with a weighting value. The results of the deformation are added to the resulting surface shape.

This implies that maya applies an offset, from the blend shapes multiplied by it's weight to the original geometry. When querying the target shapes however, you will receieve the actual vertex positions of the geometry.

 

 

 

 

WARNING - PLEASE READ

There is a big problem with the code provided her for extracting Blend Shapes. If a blend target is deleted, then the target object will not be returned when queried. This is a known problem by alias and is listed in their technical knowledge base here

I will aim to fix this code as soon as possible, however it looks as though there is no reliable way of handling multiple targets associated with a given blend shape.

Thanks to James Whitworth for pointing this out.

 

 

 

Enabling/Disabling BlendShapes

 

One initial issue that you must consider if you wish to export blend shapes is that if you attempt to query the original mesh shape which has blend shapes applied, you will end up accesing the deformed version rather than the base version.

 

To counter this problem, it is worth disabling all Blend Shape deformers before you attempt to access the base shape.

 

All blend shape deformers in maya have an envelope (en) attribute. This attribute can be set to 0 to disable the actual effect. Therefore, before we export, we can disable all of the blend shape deformers, and then re-enable them after exporting the data.

 

 

 

 

 

 

 

 


#include<maya/MFnBlendShapeDeformer.h>
#include<maya/MItDependencyNodes.h>
#include<maya/MPlug.h>

void DisableBlendShapes()
{
 

MItDependencyNodes it(MFn::kBlendShape);
while( !it.isDone() )
{

 

MFnBlendShapeDeformer fn(it.item());

// get the envelope attribute plug
MPlug plug = fn.findPlug("en");

// set to 0 to disable FFD effect
plug.setValue(0.0f);

it.next();

}

}

void EnableBlendShapes()
{
 

MItDependencyNodes it(MFn::kBlendShape);
while( !it.isDone() )
{

 

MFnBlendShapeDeformer fn(it.item());

// get the envelope attribute plug
MPlug plug = fn.findPlug("en");

// set to 1 to enable FFD effect
plug.setValue(1.0f);

it.next();

}

}


 

 

Finding all Blend Shapes
in a scene

If we wish to find all of the blend shape deformers within a Maya scene, then we need to search for all of the MFn::kBlendShape nodes.

We can attach a MFnBlendShapeDeformer function set to the node to query its values.

Any Blend shape deformer may act upon more than one undeformed base object. Each base object will then have a set of blend targets and a set of weights for each target.

 

 

 

 

 

 

 

 

 


#include<maya/MFnBlendShapeDeformer.h>
#include<maya/MItDependencyNodes.h>

// create an iterator to go through all blend shapes
MItDependencyNodes it(MFn::kBlendShape);

while(!it.isDone())
{
 

// attach the function set to the object
MFnBlendShapeDeformer
fn(it.item());

MObjectArray base_objects;

// print blend shape name
cout
<<"BlendShape "<<fn.name().asChar()<<endl;

// get a list of objects that this blend shape deforms
fn.getBaseObjects(base_objects);

cout << "NumBaseObjects "
<<
base_objects.length()
<<
endl;


// loop through each blendshaped object

for(int i=0; i<base_objects.length(); ++i) {

  // get the base shape
MObject Base = base_objects[i];

// output all of the target shapes & weights
OutputWeights(fn,Base);

}

// get next blend shapes
it.next();

}



 

Determining the Weights

Lets assume we had a situation where the base geometry object was an undeformed polygonal head.

That head may then be associated with a set of blend targets for various facial expresions. These blend targets are basically deformed versions of the surfaces.

Lets assume that we had a single weighting value for a given blend target. If the weight value was 0 then the Target would have no effect on the base shape. A value of 1 would make the final object identical to the target shape.

So we can assume that each weight is associated with a single target? err, no. Maya does allow for a second use of blend shapes. You could for example have 10 blend targets, and a single weighting value that varied from 0 to 10. The single weight is therefore responsible for cycling through the targets.

Therefore, we should first determine how many weights we have, and then how many targets we have per weight.

 


#include<maya/MFnMesh.h>

void OutputWeights(MFnBlendShapeDeformer& fn,MObject& Base)
{
 

// output info about the base shape
MFnDependencyNode fnDep(Base);

// write base name
cout << "\tBase " << fnDep.name().asChar() << endl;

// attach the function set to the object
unsigned int
nWeights = fn.numWeights();

cout << "\t\tNumWeights " << nWeights << endl;

// only want non-history items
for(unsigned int i=0;i!=nWeights;++i) {

 

MObjectArray targets;

// get an array of target shapes
fn.getTargets(Base,i,targets);

cout <<"\t\tnumTargets " << targets.length();
cout << endl;

// output each target shape
for
(unsigned int j=0;j<targets.length();++j) {

 

OutputTarget(targets[j]);

}

}

}


 

 

Outputting the Targets

The most generic way of outputting the geometry targets, is to use the MItGeometry iterator.

This allows you to walk though the vertices/control points of any surface/curve/lattice or mesh, without requiring specialised routines for each surface type.

 

 

 

 

 

 

 

 

 


#include<maya/MItGeometry.h>

void OutputTarget(MObject& target)
{
 

// attach the function set to the object
MItGeometry
it(target);

// write number of points
cout
<< "\t\tNumPoints " << it.count() << endl;

// iterate through all geometry points
while(!it.isDone()) {

 

MPoint P = it.position();

// print point

cout << "\t\t\t"
<< P.x <<
" "
<< P.y <<
" "
<< P.z <<
"\n";

it.next();

}

}






 

 

What Next?

Transformation Data

Animation Data

Animation Curves

Lattices

Smooth Skinning

Rigid Skinning

index

Rob Bateman [2004]

[HOME] [MEL] [API]