Thursday, August 26, 2010

Bake Custom Geo at 360 degrees for 3 seconds...

...and you get fully working custom facial geo with no wrap deformers to slow things down. As you might have guessed, the custom facial geo baker is complete. So now you can...

The short of it:

  1. Import your new beard/gotee whatever
  2. Position it where you want it in relation to a ZEROED out Morphy face
  3. Select your custom mesh, then his face mesh
  4. Source and run script
  5. Go grab some candy. Preferably dark chocolate.
  6. Come back and animate.
The long of it:
For those of you interested, here's how I go about tackling things like that. First I figure out what I want the script to do. Here's my original "plan" notes:

  • Process to be scripted
    • Select $customGeo followed by deformingMesh
    • Create wrapDeformer 
    • Get blendshape channels into array
    • For loop
      • for each blendshape channel on the deforming mesh (limit by facial region?)
        • Get input connector value and put in $driverArray
        • Break the connection on the blendshapeChannel
        • turn channel value to 1
        • duplicate $customGeo to freeze it
          • Add new geo name to $bakedCustomGeo string array
        • position new geo
        • reconnect the connecter value with data from $driverArray
    • Put all new blendshape geo in new group
    • Name group
    • Connect all new geo back into original geo as blendshape node ($customGeoBaseName_bsNode)
Of course that's not going to be everything as lots of stuff rears it's head and must be put down like a many headed beast trying to devour your time. Next thing I do is look through scripts I have or can find online that might have similar functions I can hack (see my previous hacking other people's scripts post). I had used a great script written Asi Sudai called extractBlendshapes. It will take a mesh with a blendshape that you want to get the blendshapes from if, say for example, you deleted the original target meshes. It even puts them in a handy visual columns/rows format in worldspace. I made judicous use of large chunks of his code for the duplication and extraction function. I just modified it to duplicate the wrap deformed customGeo instead of the main mesh then did all the rest of the stuff I needed to do to get things working.

Also, thanks to my buddy David Bokser who helped me out with a syntax issue I was getting stuck on last night.

Here's the script (sorry, I don't have the best coding practices as I'm still a novice at it):
TITLE: jbMorpheusFacialCustomGeoBaker
AUTHOR:Josh Burton
DATE: August 26, 2010

Script for baking out custom facial geo for the Morpheus Rig.

If your computer explodes, I didn't do it.

1. First select the custom geo to bake
2. Then select the head (to wrap it to)
3. Run script

08.26.10 - BIRTH!

Acknowledgements -
1. Blendshape extraction, size, existance checking from extractBlendShapes - Asi Sudai
2. David Bokser for helping me fix some of my syntax issues

//sub Procs

// Debuging printing proc - Acknowledgement 1
proc extractBlendShape.debug(string $msg)
if (1==1)
print ("\n***Debug: " + $msg +"\n");
}// End
// Get object bounding size - Acknowledgement 1
proc extractBlendShape.getBounding(string $node)
float $bounding[]=`xform -q -bb $node`;
float $xSize=(`abs $bounding[0]` +`abs $bounding[3]`);
print $xSize;
}// End
// check the object have blendShapes - Acknowledgement 1
proc string extractBlendShape.getBlendShape(string $node)

string $shapes[] = `listRelatives -s $node`;
for ($shape in $shapes){
string $tempArray[]=`listConnections -s 1 -d 0 -type "blendShape" ($shape + ".inMesh")`;
if ($tempArray[0] != "") return $tempArray[0];
return "none";
}// End

//Main Proc
global proc jbMorpheusFacialCustomGeoBaker() {

//Declaring our intial variables
string $blendShapeNamesBaked[];
string $blendshapeConnections[];
string $currentConnections[];
string $selected[] = `ls -sl`;

//Josh, do an error check to make sure the selection order is correct
$customGeo = $selected[0];
$deformerGeo = $selected[1];

//create and store name of Wrap deformer
string $wrapDeformer[] = `deformer -type wrap $customGeo`;
select -r $customGeo;
select -tgl $deformerGeo;
select -cl;

//reorders deformation order for proper baking of skinned mesh
reorderDeformers "tweak1" "face_skinCluster" $deformerGeo;

// Check if object have blendShape node. - Acknowledgement 1
string $blendShapeNode = `extractBlendShape.getBlendShape $deformerGeo`;
if ($blendShapeNode == "none") { print ("\n"+ $deformerGeo + " don't have blendShape"); return; }
// Get all BlendShapes shapes - Acknowledgement 1
extractBlendShape.debug $blendShapeNode;
string $blendShapeNamesShort[] = `listAttr -m ($blendShapeNode + ".weight")`;

int $n = 0;

//Creates a new name for the geo to be baked
for ($name in $blendShapeNamesShort) {
$blendShapeNamesBaked[$n] = $customGeo + "_" + $blendShapeNamesShort[$n];

// Start extracting
// Get object size, to better spread the blendShapes - Acknowledgement 1
float $bounding[]=`xform -q -bb $customGeo`;
float $boundingSizeX=(`abs $bounding[0]` +`abs $bounding[3]`);
float $boundingSizeY=(`abs $bounding[1]` +`abs $bounding[4]`);
extractBlendShape.debug ("Bounding size = " + $boundingSizeX);
// Start extracting each shape - Acknowledgement 1, changed to export the custom geo instead of the deforming Geo
int $t=1;
string $bakedCustomGeo[];
for ($i=0; $i<`size($blendShapeNamesShort)`; $i++) { int $row = `floor($i/5)`; if ($t>5) $t=1;
extractBlendShape.debug ("doing blendShape - " + $blendShapeNamesShort[$i]);
//queries the connection that goes into the blendshape node and stores it
string $currentBlendShapeChannel = $blendShapeNode + "." + $blendShapeNamesShort[$i];
$currentConnections = `listConnections -d off -p on -s on $currentBlendShapeChannel`;
$blendshapeConnections[$i] = $currentConnections[0];
//breaks connection on blendshape node
disconnectAttr $blendshapeConnections[$i] ($blendShapeNode + "." + $blendShapeNamesShort[$i] ) ;
//back to Asi's code
setAttr ($blendShapeNode + "." + $blendShapeNamesShort[$i] ) 1;
string $bakedCustomGeo[]=`duplicate -name $blendShapeNamesBaked[$i] $customGeo`;
xform -r -t (($boundingSizeX*($t+1.2))*1.1) (($boundingSizeY*$row)*-1) 0 $bakedCustomGeo[0];
setAttr ($blendShapeNode + "." + $blendShapeNamesShort[$i] ) 0;
// Restores connection
connectAttr $blendshapeConnections[$i] $currentBlendShapeChannel;
//Restores deformation order of the Deformer Geo
reorderDeformers "face_skinCluster" "tweak1" $deformerGeo;
reorderDeformers "face_skinCluster" "face_bsNode" $deformerGeo;

//Delete wrap and connect baked custom geo as blendshapes to original custom geo
delete $wrapDeformer[0];
$customGeoBlendShapeNode = $customGeo+"_bsNode";
blendShape -n $customGeoBlendShapeNode $blendShapeNamesBaked $customGeo ;

//groups our new baked geo for easy cleanup later on
$bakedCustomGeoGroupName = $customGeo+"_bsGeo_grp";
group -n $bakedCustomGeoGroupName $blendShapeNamesBaked;
setAttr ($bakedCustomGeoGroupName +".v") 0;
parent $bakedCustomGeoGroupName customFacialGeo_bsGeo_grp;

//Connects our custom geo blendshape channels to the original deforming mesh channels
int $b=0;
for ($bshape in $blendShapeNamesBaked) {
connectAttr ($blendShapeNode + "." + $blendShapeNamesShort[$b]) ($customGeoBlendShapeNode +"."+ $blendShapeNamesBaked[$b]);

//Skin the custom geo
$customGeoSkinName = $customGeo+"_skinCluster";
skinCluster -n $customGeoSkinName -tsb qssFaceSkinJoints $customGeo;

//copy the skin weights from the deformer geo to the custom geo
copySkinWeights -ds $customGeoSkinName -ss "face_skinCluster" -noMirror -surfaceAssociation closestPoint -influenceAssociation name;

//renames our original custom geo properly
$customGeoProperName = $customGeo+"_customGeo";
rename $customGeo $customGeoProperName;

//Report complete
print ($customGeoProperName + " exported properly. I'd move the joysticks around to make sure.") ;


What else?
  • Been doing some polishing on some of the blendshapes for the rig and deformation
  • Pushed Nose widener more at a beta tester's request
  • Bug fix - eyebrow mover rotation is now properly mirrored
  • Moved out the jaw_anim control so it wouldn't get stuck behind beards
  • Moved the hair over to using skinning rather than wrap deformers
Now, pardon me but I have some pig tails that were sent in to look at. Keep em comin!

No comments:

All the stuff on this site is 2000 - by Josh Burton...unless otherwise noted. All rights reserved.