/* Title: fitMorph.mel Author: Erick Miller Email: erickmiller@yahoo.com Date: April 2002 Version: 2.2 Compatibility: Maya v3 & v4 + Install Instructions: 1. Copy the mel script (fitMorph.mel) to your local user/scripts folder: (win2000 example path to mel scripts folder): C:\Documents and Settings\*USERNAME*\My Documents\maya\#.#\scripts 2. Copy the icon file (fitIcon.bmp) to your user/prefs/icons folder: (win2000 example path to icons folder): C:\Documents and Settings\*USERNAME*\My Documents\maya\#.#\prefs\icons 3. Then type: source fitMorph.mel; into the Maya command line. 4. Then, MAKE SURE YOUR SHELF IS VISIBLE, and type: installFitMorph; into the Maya command line. You should now have a new shelf button, click it, and you will get the script's Ui... The buttons all have roll-over annotations, and should be pretty self explanatory, once you press them. Selection order is always the target object last. Description: Several cool functions to fit selected objects or components into the shape of other selected objects. Options include snapping to objects, fitting to bounding box, and wrapping one shape to another object shape, as sort of a "lite" 3d morphing capability. It uses a tricky way of calculating the closest point on the target surface, which requires no plugins or complex data sturctures, or slow vector / magnitude math calculations :-D Updates: ___ v1.1 * Added a couple usability fixes/updates, selection order is now consistent. * Selection order doesn’t get modified by executing functions anymore, i.e. script restores original selection if it ever needs to change it in the code. ___ v1.5 *Added Entire New feature set, with a whole new set of snapping and flattening functions, which can be good to use before you actually perform the "shrink wrap" in order to remove any unwanted surface curvature: 1) Scale to Zero @ Center of Selection Pivot: This feature will let you quickly flatten out a selected set of vertices, or objects, along the selected axis. This is useful if you want to have a "snap to grid" behavior, in order to flatten out the vertices (or anything selected) along the same plane, and you want them to be flattened according to the selection's relative axis and location, as opposed to flattened across, onto the grid. 2) Bounding Box Snap: This feature will snap the selected vertices (or anything selected) on an object to it's own bounding box edge. This is also very useful for flattening vertices onto a single plane, but without having to be forced to snap them to the grid, it still snaps them to the "world's" axis. The script will snap them to the bounding box edge of the object that contains them, options are the min or max of each axis. ___ v2.0 *Added Entire New feature set, "Interactive Fit". This tab layout of the UI will allow you to interactively decide whether or not you want to snap the components to the surface, one at a time. Define an interactive session by first selecting the verts and the target surface last, and then the UI allows you to pick walk through your component selection, whether it is polygon, nurbs, or subdiv, you can pick walk through the vertices, and snap them one by one, deciding for each one if that particular vert should or shouldn’t be snapped onto the target surface. ___ v2.1 *Two small history based bug fixes that caused history to get deleted on the component snap function are fixed in this update. ___ v2.2 *Fixed a couple error checking routines and added an option to clear the globals for the "Interactive Fit" session. ___ v2.5 *Added 2 New Features: (Polygon Vertex Only) 1. Move Along Averaged Vertex Normal. This moves selection of poly vertices outward, in the direction of the averaged normal. The vert is moved in the outward direction that it's average normal is pointing, and the amount it is moved is determined by a slider bar that has 3 levels of precision for highly accurate vertex translations. 2. Relax Vertices. This siply uses the polyAverageVertex command to "smooth" the vertex locations. The amount (iterations) is determined once again, by a slider bar. Input: selection order, gui based input. Return: interactive output */ global proc fitMorph() { // // Delete ui or prefs if they exist for this win... // if(`window -ex fit`){deleteUI fit;} if(`windowPref -ex fit`){ windowPref -r fit; } string $fitWin = `window -title "M a y a F I T M O R P H ! v2.5" -s 0 fit`; // tabLayout; setParent $fitWin; // columnLayout -adjustableColumn true "Standard Fit"; frameLayout -label "Object Fit Options..." -collapsable true -labelAlign "top" -borderStyle "in"; columnLayout; button -label "Snap Object to Object" -w 210 -ann "Based on selection order: Snaps the first object onto the second object's pivot point." -c "snapObjToObj"; button -label "Fit Obj to Bounding Box" -w 210 -ann "Based on selection order: Fits the first object's bounding box to the second object's bounding box." -c "fitBboxForUi"; button -label "\"Shrink Wrap\" Obj to Obj " -w 210 -ann "Based on selection order: Trys to fit a duplicate of the first object into the shape of the second object." -c "objectFit"; setParent ..; setParent ..; frameLayout -label "Component Fit Options..." -collapsable true -labelAlign "top" -borderStyle "in"; columnLayout; button -label "Snap Components to Object" -w 210 -ann "Based on selection order: Snaps the first selected group of cvs or vertices onto the last selected object's pivot point." -c "componentFit pointSnap"; button -label "Fit Verts to Bounding Box" -w 210 -ann "Based on selection order: Fits the first selected group of cvs or vertices bounding box to match the last selected object's bounding box." -c "componentFit fitBbox"; button -label "\"Shrink Wrap\" Verts to Object " -w 210 -ann "Based on selection order: Actually MOVES the first selected group of cvs or vertices onto the closest point on the last selected object's surface." -c "componentFit surfaceSnap"; setParent ..; setParent ..; frameLayout -label "Move Along Normal:" -collapsable true -labelAlign "top" -borderStyle "in"; columnLayout; rowColumnLayout -numberOfColumns 1 -columnAlign 1 "right" -columnWidth 1 210; text "(Polygon Vertices Only):" ; separator -style "none"; separator -hr true; separator -style "none"; floatSliderGrp -w 210 -cw 1 40 -cw 2 170 -adj 1 -field true -min -.5 -max .5 -pre 3 -s 3 -v .105 moveVertNormalSlider; button -label "Move Along Averaged Vertex Normal." -w 210 -ann "Polygon Vertex Only: Actually MOVES the selected group of POLYGON ONLY vertices outward, in the direction of the vertex normal. Similar to \"flood pull\" in Artisan, only works on selections." -c ("moveVertAlongNormal `floatSliderGrp -q -v moveVertNormalSlider`"); separator -style "none"; separator -style "none"; separator -hr true; separator -style "none"; floatSliderGrp -w 210 -cw 1 40 -cw 2 170 -adj 1 -field true -min 0 -max 50 -pre 0 -s 0 -v 1 relaxVertsSlider; button -w 210 -ann "Polygon Vertex Only: Uses polyAverageVertex to average vertex locations, causing a smoother, rounded selection of vertices. Good for getting rid of those \"tangled\" vertices. Similar to \"flood smooth\" in Artisan, only works on selections." -c ("polyAverageVertex -ch off -i `floatSliderGrp -q -v relaxVertsSlider`") -label "Relax (Average) Vertices."; separator -style "none"; separator -hr true; separator -style "none"; setParent ..; setParent ..; setParent ..; frameLayout -label "Flatten Vertices:" -collapsable true -labelAlign "top" -borderStyle "in"; columnLayout; text "Zero Scale Selected Verts.:" ; rowColumnLayout -numberOfColumns 3 -columnWidth 1 70 -columnWidth 2 70 -columnWidth 3 70; //210 button -label " X " -ann "Scale currently selected Components to Zero along thier selected axis and pivot." -c "zeroScaleToSelectedPivot X"; button -label " Y " -ann "Scale currently selected Components to Zero along thier selected axis and pivot." -c "zeroScaleToSelectedPivot Y"; button -label " Z " -ann "Scale currently selected Components to Zero along thier selected axis and pivot." -c "zeroScaleToSelectedPivot Z"; setParent ..; text "Internal Bounding Box Snap:" ; rowColumnLayout -numberOfColumns 2 -columnWidth 1 105 -columnWidth 2 105; //210 button -label "X Min" -ann "Snaps component selection to the bounding box of the it's containing object." -c "vertexSnapToBboxEdge xmin"; button -label "X Max" -ann "Snaps component selection to the bounding box of the it's containing object." -c "vertexSnapToBboxEdge xmax"; button -label "Y Min" -ann "Snaps component selection to the bounding box of the it's containing object." -c "vertexSnapToBboxEdge ymin"; button -label "Y Max" -ann "Snaps component selection to the bounding box of the it's containing object." -c "vertexSnapToBboxEdge ymax"; button -label "Z Min" -ann "Snaps component selection to the bounding box of the it's containing object." -c "vertexSnapToBboxEdge zmin"; button -label "Z Max" -ann "Snaps component selection to the bounding box of the it's containing object." -c "vertexSnapToBboxEdge zmax"; setParent ..; setParent ..; setParent ..; // tabLayout; setParent $fitWin; // columnLayout -adjustableColumn true "Interactive Fit..."; frameLayout -label "One By One Component Fit:" -collapsable true -labelAlign "top" -borderStyle "in"; columnLayout; text "Select Verts. & Target Obj. Last:"; button -label "Define Interactive Session." -w 210 -h 40 -ann "Select a group of cvs or components, and a target surface/object, and click here to begin an \"Interactive Session\"." -c "DefineInteractiveFitSessionGlobals"; button -label "Clear Session Globals." -w 210 -h 20 -ann "NOT UNDO-ABLE. This will clear the list of verts. stored in your current \"Interactive Session\" globals from memory." -c "clearInteractiveFitSessionGlobals"; text "PickWalk Through Selections:"; rowColumnLayout -numberOfColumns 2 -columnWidth 1 105 -columnWidth 2 105; //210 button -en 0 -h 90 -label "<< back <<" -ann "Previous Vert in your \"Interactive Session\" Vert Selection list." -c "selectBackBefore" selectBackBefore_Button; button -en 0 -h 90 -label ">> forward >>" -ann "Next Vert in your \"Interactive Session\" Vert Selection list." -c "selectForwardNext" selectForwardNext_Button; setParent ..; text "FIT IT TO TARGET:"; button -en 0 -label "F I T current vert" -w 210 -h 70 -ann "Click here to Snap Current Active Vert in your \"Interactive Session\" to the current active target surface." -c "select -r $g_fitMorphSelectionArray[ $g_fitMorphCurrentSel ] $g_fitMorphTargetSurface; componentFit surfaceSnap; select -tgl $g_fitMorphTargetSurface;" interactiveFitCommand_Button; setParent ..; setParent ..; showWindow $fitWin; } /* : : : : */ global proc moveVertAlongNormal(float $amountToMoveFromSlider) { string $sel[] = `ls -sl -fl`; for ($vert in $sel) { select -r $vert; if (`nodeType $vert` != "mesh"){ warning "Works only on polygon vertices, skipping this selection."; continue; } float $arrayOfVectors[9] = `polyNormalPerVertex -q -xyz`; // // average the 3 vertex normals into one direction: float $vN[3]; $vN[0]=(($arrayOfVectors[0]+$arrayOfVectors[3]+$arrayOfVectors[6])/3); $vN[1]=(($arrayOfVectors[1]+$arrayOfVectors[4]+$arrayOfVectors[7])/3); $vN[2]=(($arrayOfVectors[2]+$arrayOfVectors[5]+$arrayOfVectors[8])/3); // // unitize the normal to one before using the multiplier: vector $unitizedNormal = `unit << $vN[0], $vN[1], $vN[2] >>`; move -r ($amountToMoveFromSlider * $unitizedNormal.x) ($amountToMoveFromSlider * $unitizedNormal.y) ($amountToMoveFromSlider * $unitizedNormal.z) $vert; } // // restore original vert selection select $sel; } /* : : : INTERACTIVE FIT Globals and functions: : */ global string $g_fitMorphTargetSurface; global string $g_fitMorphSelectionArray[]; global int $g_fitMorphCurrentSel; global int $g_fitMorphNumSel; global proc DefineInteractiveFitSessionGlobals() { global string $g_fitMorphTargetSurface; global string $g_fitMorphSelectionArray[]; global int $g_fitMorphCurrentSel; global int $g_fitMorphNumSel; string $selected[] = `ls -sl -fl`; if ( size($selected) < 2) { error "To define an interactive session, you must first select a group of vertices, and last, select a target surface object, then, hit \"Define Interactive Session.\"."; } int $i; for ($i=0; $i< size($selected)-1; $i++) { if ( `nodeType $selected[$i]` != "mesh" && `nodeType $selected[$i]` != "nurbsSurface" && `nodeType $selected[$i]` != "subdiv" && `nodeType $selected[$i]` != "nurbsCurve" && `nodeType $selected[$i]` != "tweak" // added to account for node history... ){ warning "This function works on the components of deformable objects only. Nurbs, Curves, Polygons or Subdivs."; error "To define an interactive session, you must first select a group of vertices, and last, select a target surface object, then, hit \"Define Interactive Session.\"."; } } string $targetObj = $selected[ size ($selected) -1 ]; select -r $targetObj; string $selBuf[] = `ls -sl -tr`; select -r $selected; if ($selBuf[0] == ""){ error "The last object selected must be at least an object level transform node."; } else { // clear for re-initialization $g_fitMorphTargetSurface = ""; clear ( $g_fitMorphSelectionArray ); $g_fitMorphCurrentSel = $g_fitMorphNumSel = 0 ; $g_fitMorphTargetSurface = $selected[ size ($selected) -1 ]; for ($i=0; $i< size($selected)-1; $i++) { $g_fitMorphSelectionArray[$i] = $selected[$i]; } $g_fitMorphNumSel = `size $g_fitMorphSelectionArray`; $g_fitMorphCurrentSel = -1; button -e -en 1 selectBackBefore_Button; button -e -en 1 selectForwardNext_Button; button -e -en 1 interactiveFitCommand_Button; selectForwardNext(); } } global proc clearInteractiveFitSessionGlobals() { global string $g_fitMorphTargetSurface; global string $g_fitMorphSelectionArray[]; global int $g_fitMorphCurrentSel; global int $g_fitMorphNumSel; $g_fitMorphTargetSurface = ""; clear ( $g_fitMorphSelectionArray ); $g_fitMorphCurrentSel = 0; $g_fitMorphNumSel = 0; button -e -en 0 selectBackBefore_Button; button -e -en 0 selectForwardNext_Button; button -e -en 0 interactiveFitCommand_Button; print "\nGlobal Variables Deleted From Memory."; } global proc selectForwardNext() { global string $g_fitMorphTargetSurface; global string $g_fitMorphSelectionArray[]; global int $g_fitMorphCurrentSel; global int $g_fitMorphNumSel; if (`size $g_fitMorphSelectionArray` && $g_fitMorphCurrentSel + 1 >= $g_fitMorphNumSel) { select -r $g_fitMorphSelectionArray[ `size $g_fitMorphSelectionArray`-1 ]; } else if ($g_fitMorphCurrentSel + 1 >= $g_fitMorphNumSel){ return; } else { select -r $g_fitMorphSelectionArray[ ++ $g_fitMorphCurrentSel ]; } } global proc selectBackBefore() { global string $g_fitMorphTargetSurface; global string $g_fitMorphSelectionArray[]; global int $g_fitMorphCurrentSel; global int $g_fitMorphNumSel; if (`size $g_fitMorphSelectionArray` && $g_fitMorphCurrentSel - 1 <= -1) { select -r $g_fitMorphSelectionArray[ 0 ]; } else if ($g_fitMorphCurrentSel - 1 <= -1) { return; } else { select -r $g_fitMorphSelectionArray[ -- $g_fitMorphCurrentSel ]; } } // //end interactive functions^ /* : : : : */ global proc componentFit( string $mode ) { // modes of operation: // "fitBbox" // "surfaceSnap" // "pointSnap" // string $selected[] = `ls -sl -fl`; if ( size($selected) < 2){ error "First select the object's components to operate on, and then an object to fit those components into"; } string $componentString; int $i; for ($i=0; $i< size($selected)-1; $i++){ if ( `nodeType $selected[$i]` == "mesh" || `nodeType $selected[$i]` == "nurbsSurface" || `nodeType $selected[$i]` == "subdiv" || `nodeType $selected[$i]` == "nurbsCurve" || `nodeType $selected[$i]` == "tweak" // added to account for node history... hmmm ){ $componentString = $selected[$i] +" "+$componentString; } else { error "This function works on the components of deformable objects only. Nurbs, Curves, Polygons or Subdivs."; } } string $targetObj = $selected[ size ($selected) -1 ]; select -r $targetObj; string $selBuf[] = `ls -sl -tr`; select -r $selected; if ($selBuf[0] == ""){ error "The last object selected must be at least an object level transform node."; } switch ( $mode ){ case "fitBbox": { boundingBoxFitter $componentString $targetObj; select -r $selected; break; } case "pointSnap": { snapComponentsToObj $componentString $targetObj; select -r $selected; break; } case "surfaceSnap": { string $shapeTypBuf[] = `listRelatives -s $targetObj`; if ( $shapeTypBuf[0] == "" || (`nodeType $shapeTypBuf[0]` != "mesh" && `nodeType $shapeTypBuf[0]` != "nurbsSurface" && `nodeType $shapeTypBuf[0]` != "subdiv" && `nodeType $shapeTypBuf[0]` != "nurbsCurve") ){ error "This function works on deformable objects only. Nurbs, Curves, Polygons or Subdivs."; } waitCursor -state on; string $pWin,$progressControl; string $version = `about -v`; string $release = `substring $version 1 1`; if ( float( $release ) > 3 ) // only version 4... { $pWin = `window -s 0 -tb 0 pb`; columnLayout; $progressControl = `progressBar -maxValue 500 -width 300`; setParent..; showWindow $pWin; } eval ("select -r "+$componentString); for ($each in `ls -sl -fl`) { snapToClosestPointOnSurface $each $targetObj; if (`window -ex $pWin` ) { progressBar -edit -step 1 $progressControl; } } select -cl; if ( `window -ex $pWin` ) { deleteUI $pWin; } waitCursor -state off; select -r $selected; break; } default: { error "Wrong arguments. Use either \"fitBbox\" \"surfaceSnap\" or \"pointSnap\". "; select -r $selected; break; } } } /* : : : : */ global proc string[] objectFit() { string $selected[] = `ls -sl`; if ( size($selected) != 2){ error "Select two peices of geometry, first select the object to operate on, and then an object to fit the first object into"; } select -r $selected[1]; string $shapeTypBuf2[] = `listRelatives(eval("ls -tr -o -sl"))`; select -r $selected[0]; string $shapeTypBuf[] = `listRelatives(eval("ls -tr -o -sl"))`; string $duplicatedObj[]; if ( `nodeType $shapeTypBuf[0]` == "mesh" || `nodeType $shapeTypBuf2[0]` == "mesh" || `nodeType $shapeTypBuf[0]` == "nurbsSurface" || `nodeType $shapeTypBuf2[0]` == "nurbsSurface" || `nodeType $shapeTypBuf[0]` == "subdiv" || `nodeType $shapeTypBuf2[0]` == "subdiv" || `nodeType $shapeTypBuf[0]` == "nurbsCurve" || `nodeType $shapeTypBuf2[0]` == "nurbsCurve" ){ $duplicatedObj = `duplicate -rr`; } else { select -r $selected; error "This function works on deformable objects only. Nurbs, Curves, Polygons or Subdivs."; } quickBoundingBoxFit( {$duplicatedObj[0],$selected[1]} ); select -r $duplicatedObj[0]; if ( `nodeType $shapeTypBuf[0]` == "mesh") //polys { select -r ( $duplicatedObj[0] + ".vtx[*]" ); } else if ( `nodeType $shapeTypBuf[0]` == "nurbsSurface") //nurbs { select -r ( $duplicatedObj[0] + ".cv[*][*]" ); } else if ( `nodeType $shapeTypBuf[0]` == "subdiv") //subdivision surface { select -r ( $duplicatedObj[0] + ".smp[*][*]" ); } else if ( `nodeType $shapeTypBuf[0]` == "nurbsCurve") //nurbs curve { select -r ( $duplicatedObj[0] + ".ep[*]" ); } waitCursor -state on; string $pWin,$progressControl; string $version = `about -v`; string $release = `substring $version 1 1`; if ( float( $release ) > 3 ) // only version 4...no progressbar in version 3 { $pWin = `window -s 0 -tb 0 pb`; columnLayout; $progressControl = `progressBar -maxValue 500 -width 300`; setParent..; showWindow $pWin; } for ($each in `ls -sl -fl`) { snapToClosestPointOnSurface $each $selected[1]; if (`window -ex $pWin` ) { progressBar -edit -step 1 $progressControl; } } if (`window -ex $pWin` ) { deleteUI $pWin; } waitCursor -state off; select -r $duplicatedObj[0]; return ({ $duplicatedObj[0], $selected[1] }); } /* : : : : */ global proc quickBoundingBoxFit( string $objects[] ) { select -r $objects[0]; string $quickBboxMatch[] = `lattice -divisions 2 2 2 -objectCentered true -ldv 2 2 2`; makeIdentity -apply true -t 1 -r 1 -s 1; boundingBoxFitter $quickBboxMatch[1] $objects[1]; select -r $objects[0]; delete -ch; select -r $objects[0] $objects[1]; xform -cp; snapObjToObj(); } /* : : : : */ global proc snapObjToObj() { // // why not xform ? because i said so ;) // string $sel[] = `ls -sl`; if (size ($sel) != 2) { error "Select 2 geometry objects, the object to move, and the target object last."; } select -r $sel[1] $sel[0]; string $pConstraints[] = `pointConstraint -weight 1`; delete $pConstraints[0]; select -r $sel[0] $sel[1]; } /* : : : : */ global proc snapComponentsToObj(string $components, string $object) { eval ("select -r "+$components); string $cluster[] = `newCluster " -envelope 1"`; float $location[6] = `xform -r -q -ws -piv`; undo; string $null = `group -em`; xform -os -piv 0 0 0; xform -ws -t $location[0] $location[1] $location[2]; makeIdentity -apply true -t 1 -r 1 -s 1; select -r $null $object; snapObjToObj(); clear ( $location ); $location = `xform -ws -q -t $null`; eval ("select -r "+$components); xform -r -ws -t $location[0] $location[1] $location[2]; delete $null; eval ("select -r "+$components); eval ("select -add "+ $object); } /* : : : : */ global proc fitBboxForUi() { string $sel[] = `ls -sl`; if (size ($sel) != 2) { error "Select 2 geometry objects, the object to manipulate, and the target object last."; } boundingBoxFitter $sel[0] $sel[1]; select -r $sel[0] $sel[1]; } /* : : : : */ global proc boundingBoxFitter( string $object, string $target ) { // bbox buffer array float $bbox[6]; // object's original bbox eval ("select -r "+$object); $bbox = `xform -q -ws -bb`; float $sizeX = $bbox[3] - $bbox[0]; float $sizeY = $bbox[4] - $bbox[1]; float $sizeZ = $bbox[5] - $bbox[2]; // the target bbox select -r $target; $bbox = `xform -q -ws -bb`; float $targetX = $bbox[3] - $bbox[0]; float $targetY = $bbox[4] - $bbox[1]; float $targetZ = $bbox[5] - $bbox[2]; // conform bboxes within an // incremented tolerance range // not a perfect fit, but fast. // float $incrmnt = .1; // conform bounding box x while ( (abs($sizeX - $targetX) >= .15 ) && (abs($targetX - $sizeX) >= .15 )){ eval ("select -r "+$object); if ($targetX < $sizeX) scale -r (1-$incrmnt) 1 1 ; if ($targetX > $sizeX) scale -r (1+$incrmnt) 1 1 ; eval ("select -r "+$object); $bbox = `xform -q -ws -bb`; $sizeX = $bbox[3] - $bbox[0]; select -r $target; $bbox = `xform -q -ws -bb`; $targetX = $bbox[3] - $bbox[0]; } // conform bounding box y while ( (abs($sizeY - $targetY) >= .15 ) && (abs($targetY - $sizeY) >= .15 )){ eval ("select -r "+$object); if ($targetY < $sizeY) scale -r 1 (1-$incrmnt) 1 ; if ($targetY > $sizeY) scale -r 1 (1+$incrmnt) 1 ; eval ("select -r "+$object); $bbox = `xform -q -ws -bb`; $sizeY = $bbox[4] - $bbox[1]; select -r $target; $bbox = `xform -q -ws -bb`; $targetY = $bbox[4] - $bbox[1]; } // conform bounding box z while ( (abs($sizeZ - $targetZ) >= .15 ) && (abs($targetZ - $sizeZ) >= .15 )){ eval ("select -r "+$object); if ($targetZ < $sizeZ) scale -r 1 1 (1-$incrmnt) ; if ($targetZ > $sizeZ) scale -r 1 1 (1+$incrmnt) ; eval ("select -r "+$object); $bbox = `xform -q -ws -bb`; $sizeZ = $bbox[5] - $bbox[2]; select -r $target; $bbox = `xform -q -ws -bb`; $targetZ = $bbox[5] - $bbox[2]; } } /* : : : : */ global proc float[] snapToClosestPointOnSurface( string $vertex, string $surface) { // Tricky hack to calculate closest point on surface // by using Maya's fast native intgrated constraint system; // this saves us from having to loop through all vertices // and compare the magnitude of the difference between // two vector positions for n squared vertex locations, // geometry constraint algorithm already does this for us: // float $location[3] = `xform -ws -q -t $vertex`; string $null = `group -em`; xform -os -piv 0 0 0; xform -ws -t $location[0] $location[1] $location[2]; select -r $surface $null; string $geoConst[] = `geometryConstraint -weight 1`; clear ( $location ); $location = `xform -ws -q -t $geoConst[0]`; select -r $vertex; xform -ws -t $location[0] $location[1] $location[2]; delete $null; return ( $location ); } /* : : : : */ global proc vertexSnapToBboxEdge( string $opt ) { string $selectedVerts[], $selectedObj[] ; $selectedVerts = `ls -sl`; $selectedObj = `selectedNodes -do`; string $buffer[]; tokenize $selectedObj[0] "|" $buffer; $bbox = `xform -q -os -bb $buffer[0]`; switch ( $opt ) { case "xmin": { move -x $bbox[0]; break; } case "xmax": { move -x $bbox[3]; break; } case "ymin": { move -y $bbox[1]; break; } case "ymax": { move -y $bbox[4]; break; } case "zmin": { move -z $bbox[2]; break; } case "zmax": { move -z $bbox[5]; break; } } } /* : : : : */ global proc zeroScaleToSelectedPivot( string $opt ) { string $selected[] = `ls -sl`; if (! `size $selected` ){ error "You must select some geometry, or some vertices of geometry to run this function."; } newCluster " -envelope 1"; float $pivots[6] = `xform -r -q -ws -piv`; undo; select -r $selected; switch ( $opt ) { case "X": { scale -r -p $pivots[0] $pivots[1] $pivots[2] 0 1 1 ; break; } case "Y": { scale -r -p $pivots[0] $pivots[1] $pivots[2] 1 0 1 ; break; } case "Z": { scale -r -p $pivots[0] $pivots[1] $pivots[2] 1 1 0 ; break; } } } /* : : : : */ global proc installFitMorph() { global string $gShelfTopLevel; if (`tabLayout -exists $gShelfTopLevel`) { shelfButton -parent ($gShelfTopLevel + "|" + `tabLayout -q -st $gShelfTopLevel`) -command "fitMorph" -image1 "fitIcon.bmp" -annotation "M a y a F i t! Fit source geometry into the shape of target geometry."; } else{ error "You need a shelf for this Install to complete! Show your shelf, man!"; } } // // Sorry to pollute the global function space :-) // but lots of people cant type correctly! // This might help thier wretched soles stay calm // and not email me as much with strange questions... // global proc InstallFitMorph(){ installFitMorph(); } global proc installfitMorph(){ installFitMorph(); } global proc installfitmorph(){ installFitMorph(); } global proc installFit(){ installFitMorph(); } global proc installfit(){ installFitMorph(); } global proc InstallFit(){ installFitMorph(); } global proc fit(){ fitMorph(); }