// // Skin Exporter v1.0 // // Author: Kiaran Ritchie (c) 2007 // // Description: This tool will export the weighting data // for any number of meshes. You can then import the weights // from the .wt file back onto any number of selected meshes. // // Features: // -Handles missing influences/target meshes gracefully. // -Allows retargeting of weight data to mesh/influences with different names. // -Exports all weights to human readable format. // -Script creates new skincluster on target meshes during import, if skincluster does not already exist. // -If influences from file are not found in current skincluster, they will be automatically added OR ... // -If influences cannot be found, user is prompted to retarget to a different influence or simply skip it. // // Entry point: krSkinExporter(); // /////////////////////////////////// // Main GUI. /////////////////////////////////// global proc krSkinExporter() { if (`window -q -ex krSkinExporterWindow`) deleteUI krSkinExporterWindow; //Main Window window -title "Kiaran's Skin Exporter" -w 300 -h 120 krSkinExporterWindow; columnLayout -adj true -cw 300; rowColumnLayout -nc 2 -cw 1 180 -cw 2 100; text "Select one or more polygon meshes:"; text " "; textField -tx "c:\\weights.wt" krSkinExporter_textField; button -label "Export Skin Data " -c ("krSkinExporter_export"); text " "; button -label "Import Skin Data" -c ("krSkinExporter_import"); setParent..; separator -h 10; button -label "Close" -c ("deleteUI krSkinExporterWindow");; //Show Main Window Command showWindow krSkinExporterWindow; } /////////////////////////////////// // Entry point for export functionality. /////////////////////////////////// global proc krSkinExporter_export() { print "HERE1"; //Get filename string $fileName = `textField -q -tx krSkinExporter_textField`; string $extension = `fileExtension($fileName)`; //Make sure filename has txt extension if ($extension != "wt") error "Skin Exporter: File must end in '.wt'. Action aborted."; //Get user's selection string $sel[] = `ls -sl`; string $cleanList[]; //Filter-out only selected polygon mesh objects that are ALSO skinned. int $i=0; for ($obj in $sel) { print "HERE2"; string $shape[] = `listRelatives -pa -s $obj`; if ($shape[0] == "") //skip objects with no shape. continue; string $skinCluster = `findRelatedSkinCluster($obj)`; print $skinCluster; print $shape[0]; if (!`objectType -isType "mesh" $shape[0]`) print "isMesh!"; print "hello"; if ((`objectType -isType "mesh" $shape[0]`) && ($skinCluster != "")) { print "Is mesh and skinned"; //Add to cleaned list. $cleanList[$i] = $obj; $i++; } print "HERE BOTTOM"; } //Check to make sure at least one skinned mesh was selected. int $numMeshes = `size $cleanList`; if ($numMeshes == 0) error "Skin Exporter: Please selected one or more skinned mesh objects. Action aborted."; //Open the file int $fileId=`fopen $fileName w`; fprint $fileId ("// Kiarans Weight Exporter Data File\n"); fprint $fileId ("// Version 1.0\n"); fprint $fileId ("// " + $numMeshes + " mesh(s) recorded in this file.\n"); //Setup progress bar global string $gMainProgressBar; int $numMeshs = `size $cleanList`; progressWindow -title "Skin Exporter:" -progress $numMeshs -status "Starting: 0%" -isInterruptable false; //Write-out skin data for ($obj in $cleanList) { //Update progress window progressWindow -edit -step 1 -status ("Exporting: "+$obj); //Export data to file. krSkinExporter_writeSkinData($obj,$fileId); } //End the progress bar. progressWindow -endProgress; //Close the file fclose $fileId; //Output sucess to user. print "Skin Exporter: Finished!"; } /////////////////////////////////// // Called from export function for each mesh. /////////////////////////////////// global proc krSkinExporter_writeSkinData(string $meshName, int $fileId ) { //Print name of mesh fprint $fileId ("nameofMesh: " + $meshName + "\n"); //Get list of influences string $skinCluster = `findRelatedSkinCluster($meshName)`; string $influences[] = `skinCluster -q -influence $skinCluster`; //Find num of verts int $numVerts[] = `polyEvaluate -vertex $meshName`; string $weightsPerVertex; for ($inf in $influences) { //Store the weights per-vertex $weightsPerVertex = ""; //Setup progress bar global string $gMainProgressBar; progressBar -edit -beginProgress -isInterruptable true -status "Writing Weight Values ..." -maxValue $numVerts[0] $gMainProgressBar; //Go through each vertex, get weight value. int $i; for ($i=0;$i<$numVerts[0];$i++) { int $jointIndex = `krSkinExporter_getJointIndex $inf $skinCluster`; float $weightValue = `getAttr ($skinCluster+".wl["+$i+"].w["+$jointIndex+"]")`; // old method `skinPercent -transform $inf -query $skinCluster ($meshName + ".vtx["+$i+"]")`; //skinPercent -t jointName -q -v skinClusterName object.vtx[xxx]; //`getAttr ($skinCluster+".wl["+$i+"].w["+$jointIndex+"]")`; //if ($weightValue == 0) //continue; $weightsPerVertex += ($i + " "); $weightsPerVertex += ($weightValue + " "); progressBar -edit -step 1 $gMainProgressBar; } //Print name of the influence fprint $fileId ("influence: " + $inf + "\n"); //Print per-vertex weights fprint $fileId ($weightsPerVertex + "\n"); progressBar -edit -endProgress $gMainProgressBar; } } /////////////////////////////////// // Entry point for import function /////////////////////////////////// global proc krSkinExporter_import() { //Get user's selection string $sel[] = `ls -sl`; //Generate list of meshes and skinned meshes from selection. string $cleanList[]; string $skinnedList[]; int $i; int $j; for ($obj in $sel) { //Get shape node. string $shape[] = `listRelatives -s $obj`; //Skip objects with no shape. if ($shape[0] == "") continue; //Add to list of mesh objects if mesh if (`objectType -isType "mesh" $shape[0]`) { $cleanList[$i] = $obj; $i++; } //Add to list of skinned mesh objects if attached to skinCluster string $skinCluster = `findRelatedSkinCluster($obj)`; if ($skinCluster != "") { $skinnedList[$j] = $obj; $j++; } } //Check that user selected at least one mesh object. if (!`size $cleanList`) error "Skin Importer: Please selected one or more mesh objects. Action aborted."; //Prompt user to find the weight file. string $fileName = `fileDialog -dm "*.wt"`; if ($fileName == "") error "Skin Importer: User cancelled. Action aborted."; //Make sure filename has .wt extension string $extension = `fileExtension($fileName)`; if ($extension != "wt") error "Skin Importer: File must in '.wt' format. Action aborted."; //Get confirmation from user to overwrite any existing skinning data. int $overwriteSkin; if (`size $skinnedList`) { string $confirm = `confirmDialog -title "Warning: Skinning Found!" -message "Some mesh(s) are already skinned. Overwrite any existing skin weights?" -button "Go Ahead" -button "No, leave existing skinning." -defaultButton "Go Ahead" -cancelButton "No, leave existing skinning." -dismissString "No, leave existing skinning."`; if ($confirm == "Go Ahead") $overwriteSkin = 1; } //Open the weight file $fileId=`fopen $fileName "r"`; //Check the file for correct syntax. int $isFileOk = `krSkinExporter_checkFileSyntax($fileId)`; if (!$isFileOk) error "Skin Importer: Script detected syntax error in weight file. Action aborted."; //Get list of meshes from file. string $meshsInFile[] = `krSkinExporter_getElements $fileId "nameofMesh: "`; //Setup progress bar global string $gMainProgressBar; int $numMeshs = `size $cleanList`; progressWindow -title "Skin Importer:" -progress $numMeshs -status "Starting: 0%" -isInterruptable false; //Loop through each selected mesh for ($mesh in $cleanList) { //Update progress window progressWindow -edit -step 1 -status ("Importing: "+$mesh); //If mesh not found in file, ask for retarget or skip int $targetMeshFound=0; for ($each in $meshsInFile) if ($mesh == $each) $targetMeshFound = 1; if (!$targetMeshFound) { warning ( $mesh +" mesh not found in file!\n"); continue; //skip for now, add retargeting here! } //If mesh is already skinned, remove skin or skip (depending on feeback from confirmDialog) int $isSkinned=0; for ($each in $skinnedList) if ($mesh == $each) $isSkinned = 1; if ($isSkinned && !$overwriteSkin) { warning ( $mesh +" mesh skipped at user's request.\n"); continue; } //If already skinned, remove existing skincluster. string $skinCluster[]; if ($isSkinned) { skinCluster -e -ub $mesh; $isSkinned = 0; } //Get list of the influences string $infList[] = `krSkinExporter_getInfluencesPerMesh $fileId $mesh`; //Skip if no influences found in data file. if (!`size $infList`) { warning ("Skin Importer: no influences recorded in file for mesh: " + $mesh + "\n"); continue; } int $numInf = `size $infList`; //Setup progress bar global string $gMainProgressBar; progressBar -edit -beginProgress -isInterruptable true -status "Reading Weight Values ..." -maxValue $numInf $gMainProgressBar; //Loop through each influence for ($inf in $infList) { progressBar -edit -step 1 $gMainProgressBar; //Check if influence exists in scene and is a joint. if (!((`objExists $inf`) && (`objectType -isType "joint" $inf`))) { warning ("Skin Importer: influence from file not found in scene: " + $inf); continue; //add prompt here for retargeting influence! } //Ensure that influence is attached to the skincluster if (!$isSkinned)//If mesh not aready skinned, do so now. { $skinCluster = `skinCluster -tsb $inf $mesh`; $isSkinned = 1; } else { //If influence not in existing skincluster, add it automatically //Also find the joint index while we are seaching. int $infAlreadyInSkin; string $curInfls[] = `skinCluster -q -inf $skinCluster[0]`; for ($curInf in $curInfls) if ($curInf == $inf) $infAlreadyInSkin = 1; if (!$infAlreadyInSkin) skinCluster -e -wt 0 -ai $inf $skinCluster[0]; } //Get weights for the influence from file. string $weights = `krSkinExporter_getWeightsPerInf $fileId $mesh $inf`; int $len = `size $weights`; $weights = `substring $weights 1 ($len-2)`; //Set weights per-vertex for this influence string $buffer[]; int $numTokens = `tokenize $weights " " $buffer`; int $vertexIndex; float $weightValue; int $jointIndex = `krSkinExporter_getJointIndex $inf $skinCluster[0]`; int $k; for ($k=0;$k<$numTokens;$k+=2) { $vertexIndex = $buffer[$k]; $weightValue = $buffer[$k+1]; setAttr ($skinCluster[0]+".wl["+$vertexIndex+"].w["+$jointIndex+"]") $weightValue; } } progressBar -edit -endProgress $gMainProgressBar; } //End the progress bar. progressWindow -endProgress; //Reset selection select -r $sel; //Close the file fclose $fileId; //Output sucess to user. print "Skin Importer: Finished!"; } /////////////////////////////////// // Given fileID for a .wt file, name of a mesh and name of an influence, // returns weight values for that influence on that mesh. /////////////////////////////////// global proc string krSkinExporter_getWeightsPerInf(int $fileId, string $meshName, string $infName) { //Maintain list of influences belonging to mesh string $weights; //Rewind file and iterate through each line //to look for target mesh. frewind $fileId; int $atNextMesh; while ((!`feof $fileId` ) && (!$atNextMesh)) { string $nextLine = `fgetline $fileId`; int $size = `size $nextLine`; if ($size == 0) continue; $nextLine = `substring $nextLine 1 ($size - 1)`; string $match = `match $meshName $nextLine`; if ($match == $meshName) { int $i; while ((!`feof $fileId` ) && (!$atNextMesh)) { $nextLine = `fgetline $fileId`; int $size = `size $nextLine`; if ($size == 0) continue; $nextLine = `substring $nextLine 1 ($size - 1)`; $match = `match "^influence: " $nextLine`; $match2 = `match "^nameofMesh: " $nextLine`; if ($match == "influence: ") { string $buffer[]; int $numTokens = `tokenize $nextLine " " $buffer`; if ($infName == $buffer[1]) //found the target influence $weights = `fgetline $fileId`; } if ($match2 == "nameofMesh: ") $atNextMesh = 1; } } } return $weights; } /////////////////////////////////// // Given fileID for a .wt file, returns list of elements found in the file // Rely's on this syntax in file: "elementLabel element" // For example, given: // nameofMesh pSphere1 // nameofMesh pSphere2 // Returns {pSphere1, pSphere2} /////////////////////////////////// global proc string[] krSkinExporter_getElements(int $fileId, string $elementLabel) { //Maintain list of elements in file string $list[]; //Rewind file and iterate through each line //to look for element names. frewind $fileId; int $i; while (!`feof $fileId` ) { string $nextLine = `fgetline $fileId`; int $size = `size $nextLine`; if ($size == 0) continue; $nextLine = `substring $nextLine 1 ($size - 1)`; string $match = `match ("^" + $elementLabel) $nextLine`; if ($match == $elementLabel) { string $buffer[]; int $numTokens = `tokenize $nextLine " " $buffer`; $list[$i] = $buffer[1]; $i++; } } return $list; } /////////////////////////////////// // Given fileID for a .wt file and name of a mesh, returns list of influences for that mesh. /////////////////////////////////// global proc string[] krSkinExporter_getInfluencesPerMesh(int $fileId, string $meshName) { //Maintain list of influences belonging to mesh string $infList[]; //Rewind file and iterate through each line //to look for target mesh. frewind $fileId; int $atNextMesh; while ((!`feof $fileId` ) && (!$atNextMesh)) { string $nextLine = `fgetline $fileId`; int $size = `size $nextLine`; if ($size == 0) continue; $nextLine = `substring $nextLine 1 ($size - 1)`; string $match = `match $meshName $nextLine`; if ($match == $meshName) { int $i; while ((!`feof $fileId` ) && (!$atNextMesh)) { $nextLine = `fgetline $fileId`; int $size = `size $nextLine`; if ($size == 0) continue; $nextLine = `substring $nextLine 1 ($size - 1)`; $match = `match "^influence: " $nextLine`; $match2 = `match "^nameofMesh: " $nextLine`; if ($match == "influence: ") { string $buffer[]; int $numTokens = `tokenize $nextLine " " $buffer`; $infList[$i] = $buffer[1]; $i++; } if ($match2 == "nameofMesh: ") $atNextMesh = 1; } } } return $infList; } /////////////////////////////////// // Given fileID for a .wt file, returns true if syntax is correct. /////////////////////////////////// global proc int krSkinExporter_checkFileSyntax(int $fileId) { int $syntaxStatus = 1; int $numMeshsInFile; int $i; frewind $fileId; while ((!`feof $fileId` ) && ($i<3)) { string $nextLine = `fgetline $fileId`; int $size = `size $nextLine`; $nextLine = `substring $nextLine 1 ($size - 1)`; //Check file header for correct syntax if (($i==0) && ($nextLine != "// Kiarans Weight Exporter Data File")) $sytaxStatus = 0; if (($i==1) && ($nextLine != "// Version 1.0")) $sytaxStatus = 0; //Find number of meshs from file header if ($i==2) { string $buffer[]; int $numTokens = `tokenize $nextLine " " $buffer`; $numMeshsInFile = $buffer[1]; } $i++; } //Compare number of meshs from header to number actually found in the file. string $meshList[] = `krSkinExporter_getElements $fileId "nameofMesh: "`; int $size = `size $meshList`; if ($numMeshsInFile != $size) $syntaxStatus = 0; return $syntaxStatus; } /////////////////////////////////// // Given name of a joint and a skincluster, returns index of joint. /////////////////////////////////// global proc int krSkinExporter_getJointIndex(string $jointName, string $skinCluster) { int $jointIndex; int $found; while (!$found) { string $connections[] = `listConnections -type "joint" ($skinCluster + ".matrix["+$jointIndex+"]")`; if ($connections[0] == $jointName) $found = 1; else $jointIndex++; } return $jointIndex; }