/* Author: Walter Behrnes Script Name: wbScatterOnNormal.mel Script Version: 1.0 Maya Version: 8.5+ Description: This script is used to scatter objects oriented to the surface normal Use: source "...PathToScript.../wbScatterOnNormal.mel"; tbpMakeWindow(); Documentation: It is important to understand that the scatter Object should be oriented standing up and facing in the positive X direction. The reason for this is so that the bend deformer applies the bend in the correct direction. Select obect to duplicate and press "Get Object". Insert a name to group all copies under in the "Group Name" text field. Once the Object to Duplicate is loaded into the tool, and a group name given, make a face selection on the object that you want to populate on and then run the script. "Update count" is used in case you want to use the tool over multiple sessions. In the case that you do work on the file over multiple sessions you will want to press this button in order to insure unique naming. */ //------------------------------------------------------------------------------ //--------------------------- DECLARE GLOBAL VARS ------------------------------ //------------------------------------------------------------------------------ global string $tbpObjectToDuplicate, $tbpGroupName, $tbpNumberOfDuplicates, $tbpMaximumRotateX, $tbpMaximumRotateY, $tbpMaximumRotateZ; global string $tbpMinimumScale, $tbpActivateDeformations, $tbpMaximumDeform, $tbpMinimumDeform, $tbpMaximumScale; global int $renameCount = 1; //------------------------------------------------------------------------------ //----------------------------GET SELECTED OBJECTS------------------------------ //------------------------------------------------------------------------------ global proc tbpGetUsersObject(string $tbpOTD) { global string $tbpObjectToDuplicate, $tbpGroupName, $tbpNumberOfDuplicates, $tbpMaximumRotateX, $tbpMaximumRotateY, $tbpMaximumRotateZ; global string $tbpMinimumScale, $tbpActivateDeformations, $tbpMaximumDeform,$tbpMinimumDeform, $tbpMaximumScale; string $tempUserSelect[] = `ls -sl`; string $temporaryList; string $returnList = ""; for($temporaryList in $tempUserSelect) { if($returnList != "") $returnList = $returnList+":"+$temporaryList; else $returnList = $temporaryList; } textFieldButtonGrp -edit -text $returnList $tbpOTD; } //------------------------------------------------------------------------------ //---------------------------- CREATE WINDOW ------------------------------ //------------------------------------------------------------------------------ global proc tbpMakeWindow() { //RECOGNIZE GLOBAL VARIABLES global string $tbpObjectToDuplicate, $tbpGroupName, $tbpNumberOfDuplicates, $tbpMaximumRotateX, $tbpMaximumRotateY, $tbpMaximumRototateZ; global string $tbpMinimumScale, $tbpActivateDeformations, $tbpMaximumDeform,$tbpMinimumDeform, $tbpMaximumScale; //DELETE OLD WINDOW if(`window -exists wbScatterOnNormal`) { deleteUI wbScatterOnNormal; } //START MAKING WINDOW string $wbScatterOnNormal = `window -widthHeight 500 500 -menuBar true -title "wbScatterOnNormal" wbScatterOnNormal`; columnLayout -adjustableColumn true C1; separator -height 25 -style "none"; textFieldButtonGrp -label "Object to Duplicate" -text "--Select Object--" -buttonLabel "Get Object" -buttonCommand ("tbpGetUsersObject(\"DuplicatorObject\");") DuplicatorObject; $tbpNumberOfDuplicates = `intSliderGrp -label "Number of Copies" -field true -minValue 1 -maxValue 1000 -fieldMinValue 1 -fieldMaxValue 50000 -value 30 `; $tbpGroupName = `textFieldGrp -label "Group Name" -text "--Enter Name For Group--"`; setParent ..; columnLayout -adjustableColumn true C2; separator -height 5 -style "single"; $tbpMaximumRotateX = `floatSliderGrp -label "Rotate X" -field true -minValue 0 -maxValue 360 -fieldMinValue 0 -fieldMaxValue 360 -value 35`; $tbpMaximumRotateY = `floatSliderGrp -label "Rotate Y" -field true -minValue 0 -maxValue 360 -fieldMinValue 0 -fieldMaxValue 360 -value 360`; $tbpMaximumRotateZ = `floatSliderGrp -label "Rotate Z" -field true -minValue 0 -maxValue 360 -fieldMinValue 0 -fieldMaxValue 360 -value 35`; $tbpMaximumScale = `floatSliderGrp -label "max Scale" -field true -minValue .25 -maxValue 2 -fieldMinValue .1 -fieldMaxValue 5 -value 1.125`; $tbpMinimumScale = `floatSliderGrp -label "min Scale" -field true -minValue .1 -maxValue 2 -fieldMinValue .1 -fieldMaxValue 5 -value .5`; setParent ..; columnLayout -adjustableColumn true C3; separator -height 2 -style "single"; $tbpActivateDeformations = `checkBox -label "Apply Deformer" -align "right" -value false -width 100`; $tbpMinimumDeform = `floatSliderGrp -label "min Deformation" -field true -minValue 0 -maxValue 1 -fieldMinValue 0 -fieldMaxValue 10 -value .1`; $tbpMaximumDeform = `floatSliderGrp -label "max Deformation" -field true -minValue 0 -maxValue 1 -fieldMinValue 0 -fieldMaxValue 10 -value .5`; checkBox -label "Orient Objects To Normal" -v 1 tbpOrientToNormal; button -label "Update Count" -c "tbpGlobalCountUpdate()"; button -label "Select faces to copy to and Create" -command ("tbpGetValues(\""+ $tbpObjectToDuplicate +"\",\""+$tbpGroupName+"\",\""+$tbpNumberOfDuplicates+"\",\""+$tbpMaximumRotateX+"\",\""+$tbpMaximumRotateY+"\",\""+$tbpMaximumRotateZ+"\",\""+$tbpMinimumScale+"\",\""+$tbpMaximumScale+"\",\""+$tbpActivateDeformations+"\",\""+$tbpMinimumDeform+"\",\""+$tbpMaximumDeform+"\");"); setParent ..; showWindow $wbScatterOnNormal; } //------------------------------------------------------------------------------ //----------------------------GET VALUES---------------------------------------- //------------------------------------------------------------------------------ global proc tbpGetValues(string $tbpOTD,string $tbpGN,string $tbpNOD,string $tbpRX,string $tbpRY,string $tbpRZ,string $tbpSMin,string $tbpSMax,string $tbpAD,string $tbpMnD,string $tbpMD ) { //DECLARE USAGE OF GLOBAL VARS global string $tbpObjectToDuplicate, $tbpGroupName, $tbpNumberOfDuplicates, $tbpMaximumRotateX, $tbpMaximumRotateY, $tbpMaximumRotateZ; global string $tbpMinimumScale, $tbpActivateDeformations, $tbpMaximumDeform,$tbpMinimumDeform, $tbpMaximumScale; //DECLARE LOCAL VARS string $copyObjs,$grounName; int $particleCount,$addDeformer; float $rX,$rY,$rZ,$sMax,$sMin,$mD; //GET VALUES FROM WINDOW $copyObjs = `textFieldButtonGrp -query -text DuplicatorObject`; $particleCount = `intSliderGrp -query -value $tbpNOD`; $groupName = `textFieldGrp -query -text $tbpGN`; $rX = `floatSliderGrp -query -value $tbpRX`; $rY = `floatSliderGrp -query -value $tbpRY`; $rZ = `floatSliderGrp -query -value $tbpRZ`; $sMin = `floatSliderGrp -query -value $tbpSMin`; $sMax = `floatSliderGrp -query -value $tbpSMax`; $mD = `floatSliderGrp -query -value $tbpMD`; $mnD =`floatSliderGrp -query -value $tbpMnD`; $addDeformer = `checkBox -query -value $tbpAD`; //CALL MAIN WINDOW if($copyObjs != "--Select Object--" && $groupName != "--Enter Name For Group--") eval("tbpStartDuplicator(\""+$copyObjs+"\","+$particleCount+",\""+$groupName+"\","+$rX+","+$rY+","+$rZ+","+$sMin+","+$sMax+","+$mD+","+$mnD+","+$addDeformer+");"); else if($groupName == "--Enter Name For Group--") print("\n\nPLEASE ENTER A GROUP NAME AND TRY AGAIN!!!\n"); if($copyObjs == "--Select Object--") print("PLEASE ENTER OBJECTS TO DUPLICATE AND TRY AGAIN!!!\n\n"); error("ERRORS FOUND, PLEASE REFER TO SCRIPT EDITOR FOR FOUND ISSUES"); } global proc tbpGlobalCountUpdate() { //global int $objectNameCount; global int $renameCount; //GET TOP LEVEL OBJECTS IN OUTLINER,COUNT,SET SIZE OF OBJECTNAMECOUNT string $tempCountObjs[] = `ls -as`; //GET COUNT OF ALL OBJECTS, COUNT, SET SIZE OF GLOBALCOUNT string $tempCountAllObjs[] = `listRelatives -ad $tempCountObjs`; int $tempCount = size($tempCountAllObjs); $renameCount = $tempCount; print ("\nSETTING \"globalCount\" to: "+$tempCount); } //------------------------------------------------------------------------------ //----------------------------PROCEDURES---------------------------------------- //------------------------------------------------------------------------------ //ADD DEFORMER PROCEDURE //DEFORMS GEOMETRY, THEN REMOVES DEFORMER proc createDeformer (string $objName, float $maxDeform, float $minDeform) { //GET BOUNDING BOX INFO float $bbox[] = `xform -q -bb $objName`; //GET HEIGHT float $bbH = abs($bbox[4] - $bbox[1]); //GET MIDDLE $bbH = -($bbH/2); //APPLY NONLINEAR TO GROUP nonLinear -type bend -lowBound 0 -highBound 5 -curvature 0 $objName; //RENAME rename (`ls -sl`) "TEMPBEND"; //MOVE TO BASE move -r 0 $bbH 0 ; //BEND setAttr "bend1.curvature" (rand($minDeform,$maxDeform)); //DROP SELECTION select -d; //DELETE DEFORMER delete -ch $objName; } //MAKE SCATTER BASE GEOMETRY proc string makeNewObjectFromSelection() { //GRAB NAME SELCTIONS TRANSFORM string $scatterBaseNodes[]; $scatterBaseNodes = `selectedNodes`; string $scatterObjName[] = `listTransforms $scatterBaseNodes[0]`; //GET LIST OF SELECTED COMPONENTS string $tempSelectedFaces[] = `ls -sl`; //PUT LIST INTO A STRING string $selectionList1 = ""; for ($faces in $tempSelectedFaces) { $selectionList1 += $faces+" "; } //SELECT SELECTIONS TRANSFORM OBJECT select -r $scatterObjName; //DUPLICATE OBJECT duplicate -rr; //STORE NEW OBJS NAME string $newSelectedObj[] = `ls -sl`; //SWAP NAMES OF SELECTED FACES TO MATCH NEW TRANSFORM OBJECT string $newList = substituteAllString($selectionList1, $scatterObjName[0], $newSelectedObj[0]); //SELECT FACES ON NEW OBJECT, DELETE NON SELECTED FACES eval select -r $newList; InvertSelection; delete; //RESELECT NEW OBJECT select $newSelectedObj[0]; return $newSelectedObj[0]; } //MAKE PARTICLES proc makeParticlesOnNewObject(string $particleObject, int $particleCount, string $particleSystem, string $particleSystemEmmiter) { //SEED RANDOM NUMBER float $myRandomNumber = rand(4256); seed($myRandomNumber); int $creationState = `checkBox -q -v tbpOrientToNormal`; int $esStartFrame = `playbackOptions -q -ast`; //SELECT PARTICLE OBJECT AND EMMIT PARTICLES FROM IT. select -r $particleObject; emitter -type surface -name $particleSystemEmmiter -r $particleCount -sro 0 -nuv 0 -cye none -cyi 1 -spd 0 -srn 0 -nsp 1 -tsp 0 -mxd 0 -mnd 0 -dx 1 -dy 0 -dz 0 -sp 0 ; particle -n $particleSystem; connectDynamic -em $particleSystemEmmiter $particleSystem; //SET MAXIMUM VALUE OF PARTICLES TO CREATE string $PARTTEMP = $particleSystem+"Shape.maxCount"; setAttr $PARTTEMP $particleCount; //SET PREROLL TO -60 string $PARTTEMP = $particleSystem+"Shape.startFrame"; setAttr $PARTTEMP ($esStartFrame - 1); //SET RATE TO 500 setAttr ($particleSystemEmmiter+".rate") 1000000; if($creationState == 1) setAttr ($particleSystemEmmiter+".speed") 1; //APPLY GOAL TO PARTICLES select -r $particleSystem ; select -tgl $particleObject ; if($creationState == 1) goal -g $particleObject -w 0 -utr 0 $particleSystem; else goal -g $particleObject -w 1 -utr 0 $particleSystem; //APPLY GOALU&V ATTRIBUTES TO PARTICLES select -r $particleObject ; string $esTName = $particleSystem+"Shape"; addAttr -ln goalU -dt doubleArray $esTName; addAttr -ln goalU0 -dt doubleArray $esTName; addAttr -ln goalV -dt doubleArray $esTName; addAttr -ln goalV0 -dt doubleArray $esTName; //RANDOMIZE POSITION OF PARTICLES if ($creationState == 1) dynExpression -s "goalU = rand(0,1); goalV = rand(0,1);" -c $esTName; else dynExpression -s "goalU = rand(0,1);\ngoalV = rand(0,1);" -rbd $esTName; //SET THROUGH A RANDOM NUMBER OF FRAMES SO THAT WE INSURE WE GET A RANDOM SPREAD ON THE PARTICLES if($creationState == 1) { for ($aa = $esStartFrame;$aa <= ($esStartFrame + 23);$aa++) { currentTime $aa; } }else{ int $esMyRandNum = rand(1,60); for ($aa = $esStartFrame;$aa <= ($esStartFrame + $esMyRandNum);$aa++) { currentTime $aa; } } } //RENAME OBJECTS IN GROUP proc tbpRenameObjectsInGroup(string $groupName) { //DECLARE GLOBAL USAGE global int $renameCount; //GET LIST OF OBJECTS IN GROUP string $objectListNames[] = `listRelatives -c -pa $groupName`; string $curRel; for ($curRel in $objectListNames) { $curRelNew = `match "[a-zA-Z0-9]*$" $curRel`; //APPEND COPY NUMBER TO NAME //print ("rename "+$curRel+" ("+$curRelNew+"Copy"+$renameCount+"_REN)\n"); rename $curRel ($curRelNew+"Copy"+$renameCount+"_REN"); //COUNT UP GLOBAL RENAME COUNT $renameCount ++; } } ////////////////////////////////////////////////////////////////////////////////////////// // GET POSITION AND ANGLE // ////////////////////////////////////////////////////////////////////////////////////////// proc float[] getPositionAngle(string $curParticle) { //SET FRAME 1 GET POSITION //print ($curParticle+"\n"); currentTime -edit 1 -update yes; float $getPosition1[] = `getParticleAttr -at position ($curParticle)`; //SET FRAME 2 GET POSITION & VELOCITY currentTime -edit 24 -update yes; float $getPosition2[] = `getParticleAttr -at position ($curParticle)`; float $getVelocity[] = `getParticleAttr -at velocity ($curParticle)`; //RECORD POSITION1 float $posX1 = $getPosition1[0]; float $posY1 = $getPosition1[1]; float $posZ1 = $getPosition1[2]; //RECORD POSITION2 float $posX2 = $getPosition2[0]; float $posY2 = $getPosition2[1]; float $posZ2 = $getPosition2[2]; //RECORD VELOCITY vector $particleVectorX =<<0,$getVelocity[1],$getVelocity[2]>>; vector $particleVectorY =<<$getVelocity[0],0,$getVelocity[2]>>; vector $particleVectorZ =<<$getVelocity[0],$getVelocity[1],0>>; vector $X = <<0,0,1>>; float $angleX = rad_to_deg(angle($X, $particleVectorX)); vector $Y = <<0,0,1>>; float $angleY = rad_to_deg(angle($Y, $particleVectorY)); vector $Z = <<1,0,0>>; float $angleZ = rad_to_deg(angle($Z, $particleVectorZ)); float $values[]; $values[0] = $posX1; $values[1] = $posY1; $values[2] = $posZ1; $values[3] = $posX2; $values[4] = $posY2; $values[5] = $posZ2; $values[6] = $angleX; $values[7] = $angleY; $values[8] = $angleZ; return $values; } //------------------------------------------------------------------------------ //----------------------------CODE START---------------------------------------- //------------------------------------------------------------------------------ global proc tbpStartDuplicator(string $copyObj,int $pCount, string $gName,float $rotX,float $rotY,float $rotZ,float $sMin,float $sMax,float $maxDef,float $minDef, int $addDeformer) { //USER DEFINED VARIABLES string $particleSystem = "TEMPPARTICLES"; string $particleSystemEmmiter = "TEMPPARTICLEEMMITER"; float $ptPos[]; float $randX,$randY,$randZ,$randS; global int $renameCount = 1; int $groupCount = 1; int $creationState = `checkBox -q -v tbpOrientToNormal`; //SET GROUP NAME $gName = $gName+"_GRP"; //CREATE DUPLICATE GEO FOR GROWTH string $TEMPPARTICLEGEO = makeNewObjectFromSelection(); //CREATE PARTICLE SYSTEM makeParticlesOnNewObject($TEMPPARTICLEGEO, $pCount, $particleSystem, $particleSystemEmmiter); //SELECT PARTICLE SYSTEM select -r $particleSystem; //GET NAME OF PARTICLE CLOUD string $ptCloud[] = `ls -sl`; //CREATE A VARIABLE THAT REFERENCES ALL POINTS IN CLOUD string $pCloudString = $ptCloud[0]+".pt[*]"; //MAKE ARRAY OF ALL POINTS string $ptPoints[] = `ls -fl $pCloudString`; //CREATE EMPTY GROUP TO PUT COPIES IN select -d; if(`objExists $gName`) { //SKIP }else{ group -em -n $gName; } select -d; //CREATE ARRAY OF COPY OBJECT string $objectsToDuplicate[] = stringToStringArray($copyObj,":"); int $sizeOfObjectToDup = size($objectsToDuplicate); //COPY OBJECTS TO PARTICLE CLOUD for ($myPoints in $ptPoints) { //SELECT PARTICLE GET POSITION select -r $myPoints; $ptPos = `xform -q -t -os`; float $getValues[]= `getPositionAngle($myPoints)`; //SELECT RANDOM COPY OBJECT int $tempNumber = floor(rand(-1,($sizeOfObjectToDup - 1)))+1; //DUPLICATE OBJECT STORE NAME string $curSel[] = `duplicate -rr -n ($objectsToDuplicate[$tempNumber]+$groupCount) $objectsToDuplicate[$tempNumber]`; //RENAME OBJECTS IN GROUP tbpRenameObjectsInGroup($curSel[0]); //DEFORM DUPLICATED OBJECT if($addDeformer == 1) { createDeformer($curSel[0], $maxDef, $minDef); } //SET RANDOM NUMBERS $randX = `rand (-$rotX) $rotX`; $randY = `rand $rotY`; $randZ = `rand (-$rotZ) $rotZ`; $randS = `rand $sMin $sMax`; for ($curGroup in $curSel) { //Rotate OBJECT 90 ON X, THIS LAYS IT FLAT if($creationState == 1) { //SKIP }else{ setAttr ($curSel[0]+".rotateZ") -90; } //TRANSFORM OBJECT TO PARTICLE POSITION xform -a -t $ptPos[0] $ptPos[1] $ptPos[2] $curSel[0]; if ($creationState == 1) { rotate -r 90 0 0 $curSel[0]; makeIdentity -apply true -t 0 -r 1 -s 0 -n 0 $curSel[0] ; rotate -r 0 0 $randY $curSel[0]; makeIdentity -apply true -t 0 -r 1 -s 0 -n 0 $curSel[0] ; //print $getValues; //print "\n\n"; //ROTATE Y xform -a -t $getValues[0] $getValues[1] $getValues[2] $curSel[0]; if($getValues[3] >= $getValues[0]) { setAttr ($curSel[0]+".rotateY") $getValues[7]; }else{ setAttr ($curSel[0]+".rotateY") (180+(180-$getValues[7])); } //ROTATE X if( $getValues[4] >= $getValues[1]) { if( $getValues[5] < $getValues[2] ) { setAttr ($curSel[0]+".rotateX") (180 + $getValues[6]); }else{ setAttr ($curSel[0]+".rotateX") (360 - $getValues[6]); } }else{ if( $getValues[5] < $getValues[2] ) { setAttr ($curSel[0]+".rotateX") ((180-$getValues[6])); }else{ setAttr ($curSel[0]+".rotateX") (180-(180-$getValues[6])); } } }else{ xform -a -t $ptPos[0] $ptPos[1] $ptPos[2] $curSel[0]; rotate -r -ws $randX $randY $randZ $curSel[0]; } //SCALE OBJECT xform -s $randS $randS $randS $curSel[0]; //PARENT UNDER GROUP parent $curSel[0] $gName; } $groupCount ++; } // PARTICLES /PARTICLE EMMISSION OBJECT delete $particleSystem; delete $particleSystemEmmiter; delete $TEMPPARTICLEGEO; }