// rf_.mel - MEL Script
// --------------------------------------------------------------------------
//
// DESCRIPTION:
// Takes a geometry with blendshape node applied and extracts all the
// targets from the base mesh. Use this in case you get a file with no targets
// included. Or if you work on facial blendshapes and get rid of targets and
// want to add soem later you can extract them again and build more out
// of those.
//
// REQUIRES:
// Selection of the blendshape node . Either channel box or Hypergraph.
// The function takes a simple arg of how far from the main geometry you
// want the targets to sit. So if i am working real life units i would :
// rf_bakeBlendShapeTargets(40) - as 40cm in +X from the main mesh.
//
// USAGE:
// source "rf_bakeBlendShapeTargets.mel" rf_bakeBlandShpaeTargets(arg - distance);
//
// AUTHORS:
// Rick Fronek - TD at Perspective Studios
// http://specialfx3d.blogspot.com
// www.perspectivestudios.com
//
// Copyright ©2006 Rick Fronek - All Rights Reserved.
//
// VERSIONS:
// 1.00 - March 25, 2008 - Initial Release.
//
// --------------------------------------------------------------------------
global proc rf_unlockTransAttrs()
{
string $sel[] = `ls -sl`;
string $lockedAttrs[] = `listAttr -locked $sel[0]`;
for($b in $lockedAttrs)
{
setAttr -lock 0 ($sel[0] + "." + $b);
}
} // End of proc
//---------------------------------------------------------------------------------------------------
global proc string rf_getNameOfBaseGeo()
{
string $headName = "";
string $selection[] = `ls -sl`;
if(size($selection) == 0) error("No BS node seleted, please select BS node.");
// Get the shape of the selection and compare it with the selection
if(`nodeType $selection[0]` != "blendShape") error("Please select the BS node.");
// otherwise do this...
$headName = $selection[1];
return $headName;
} // End of function
//---------------------------------------------------------------------------------------------------
// A function that takes a selected blend shape node and returns its name
// which is then passed to another function for futher work.
// You must select the BS node. Easy way to do it is to select the mesh
// the blendshape is applied to and click on it in the channel box
// That's important for this function to run properly.
global proc string[] rf_findBS()
{
string $blendShape[];
string $bsArray[]; // Needed to store the bs node and return a single node
string $allObjects[] = `ls -type "blendShape"`;
//error check
if(size($allObjects) == 0) error("Please select mesh with BS applied.");
for($n in $allObjects)
{
$bsArray[size($bsArray)] = $n;
$blendShape = $bsArray;
}
// return the shapes
return $blendShape;
}
//---------------------------------------------------------------------------------------------------
// This is the CORE function that goes through all the weights on the blendshape
// node returned from function named rf_findBS().
// The goal is to reset the BS node to 0 ,take the weight num 0 and turn it to 1
// then duplicate/bake the base mesh move it aside , reset the bs node and take
// another weight and do the same to it. Until all the weights are baked and you
// end up with extracting all the BS weights = targets.
global proc rf_bakeBlendShapeTargets(int $iDistance)
{
string $blendShapeNode[] = `rf_findBS`;
string $BSmeshNode = `rf_getNameOfBaseGeo`;
// Take a single blendShape node from the array that gets the blenshapes
string $bsNode = $blendShapeNode[0];
// To get the multi attributes use the listAttr -multi flag to get the names and index
// string $wts[]=`listAttr -m controller_morph_Head.w`;
// This is my way of getting the values only in a float array and iterate through them
float $targets[] = `getAttr ($bsNode + ".weight")`;
for($x=0;$x
{
setAttr($bsNode + ".weight" + "[" + $x + "]") 0; // set the BS to 0 first to make sure its reseted
setAttr($bsNode + ".weight" + "[" + $x + "]") 1;
select -r $BSmeshNode;
duplicate -rr;
rf_unlockTransAttrs();
move -x $iDistance;
select -r $bsNode;
setAttr($bsNode + ".weight" + "[" + $x + "]") 0;
}
}