钉毛囊


// djRivet.mel        
//
// author: David Johnson
// contact: david@djx.com.au
// website: www.djx.com.au
// last rev: 02 Nov 2009
// version: 1.6.0
//
//
//      Use follicles as a way of constraining objects to a poly or nurbs surface.
//
//      Follicles are part of the maya hair system, but can be created independantly.
//      Input a uv-coordinate to the follicle node and it will stick to that point
//      on the surface and orientate itself to the surface normal. Other objects can
//      be parented to or constrained to the follicle node.
//    
//      Advantages: surface can be modified (eg. smoothed)
//                  follicle can be repositioned by changing (maybe animating) uv-coordinate
//
//    Disadvantages: works best with properly layed out, non-overlapping uv's (extra work!)
//
//      USAGE:    place djRivet.mel in your scripts folder
//              source djRivet.mel (or restart maya)
//
//              select object(s) then shift-select a surface
//        (either poly mesh or nurbs surface must be last selected)
//
//              type "djRivet" (without the quotes)
//
//              a follicle will be created at the point on the surface closest to each object
//        and the object(s) will be parent constrained to the follicle(s)
//
//              The objects to constrain can be any type that has a transform node,
//              but the target surface must either be a poly mesh or a nurbs surface.
//
//        If vertices, cv's or lattice-points are part of the selection list,
//        they will be clustered and the cluster will be constrained to the follicle.
//        You will be asked whether this should be done individually or together.
//
//    WARNINGS:
//        Save your scene file as a precaution before you use djRivet.mel
//
//    LIMITATIONS:
//        Fails if objects to be constrained have their translate/rotate channels locked or animated.
//
//    TO DO LIST:
//              Add error handling to clean up on failure
//
//    CREDITS:
//        Michael Bazhutkin, I used your excellent rivet.mel for years - thanks for sharing!
//        Mike Rhone, who said "Better than rivet:Use a follicle."
//        Brecht Debaene, for showing me how to hook up a follicle
//        robthebloke.org, for sharing the knowlege.
//
//    HISTORY:
//        1.0    09 Oct 2006 - working version
//        1.1    11 Oct 2006 - fixed problem with closestPointOnMesh ignoring parent transforms
//        1.2    14 Oct 2006 - fixed duplicate names problem
//                        fixed problem determining object location
//                        object now parent-constrained to follicle
//                        multiple objects can be constrained in a single execution
//      1.3    16 Oct 2006 - fixed problem if shapeNode was not alone under the transform
//                        add check for surface type (currently only poly mesh supported)
//      1.4     9 Oct 2006 - target surface can now be poly mesh or nurbs
//                      - removed transform heirarchy limitation (improved baking method)
//        1.4.1    21 Oct 2006 - fix small error in nurbs uv normalization
//                            fix error with heirarchy handling
//        1.4.2   21 Oct 2006 - prevent failure that occured if target surface had locked transforms
//                              check for locked attributes on objects to be constrained and skip if locked
//        1.5    27 Oct 2006     - cv's and vertices can now be riveted
//        1.5.1    29 Oct 2006 - lattice-points can now be riveted
//                                user is asked whether pnts should be constrained individually or together
//        1.5.2    30 Oct 2006 - clean up point handling code, so original selection list is preserved
//        1.5.3    11 Feb 2007 - new maya8.5 follicle attributes accounted for
//                            script now checks maya version and works correctly in maya 7, 8.0, 8.5
//                            follicles and clusters are grouped under a locked transform called djRivetX
//        1.5.5    28 Aug 2007 - detect maya8.5sp1 correctly
//                              catch errors when transforms are animated and warn user
//        1.6.0    02 Nov 2009    - multiple uv set handling
//
/

// LOCAL PROCEDURES (must come first)
//
// djRivetHideFollicleChannels() hides most of the channelbox channels to make it less confusing to look at

proc djRivetHideFollicleChannels(string $fol, string $fols, float $ver) {

    setAttr -keyable false -channelBox false ($fol + ".tx");
    setAttr -keyable false -channelBox false ($fol + ".ty");
    setAttr -keyable false -channelBox false ($fol + ".tz");
    setAttr -keyable false -channelBox false ($fol + ".rx");
    setAttr -keyable false -channelBox false ($fol + ".ry");
    setAttr -keyable false -channelBox false ($fol + ".rz");
    setAttr -keyable false -channelBox false ($fol + ".sx");
    setAttr -keyable false -channelBox false ($fol + ".sy");
    setAttr -keyable false -channelBox false ($fol + ".sz");

    setAttr -keyable false -channelBox false ($fols + ".rsp");
    setAttr -keyable false -channelBox false ($fols + ".ptl");
    setAttr -keyable false -channelBox false ($fols + ".sim");
    setAttr -keyable false -channelBox false ($fols + ".sdr");
    setAttr -keyable false -channelBox false ($fols + ".fld");
    setAttr -keyable false -channelBox false ($fols + ".ovd");
    setAttr -keyable false -channelBox false ($fols + ".cld");
    setAttr -keyable false -channelBox false ($fols + ".dmp");
    setAttr -keyable false -channelBox false ($fols + ".stf");
    setAttr -keyable false -channelBox false ($fols + ".lfl");
    setAttr -keyable false -channelBox false ($fols + ".cwm");
    setAttr -keyable false -channelBox false ($fols + ".dml");
    setAttr -keyable false -channelBox false ($fols + ".cml");
    setAttr -keyable false -channelBox false ($fols + ".ctf");
    setAttr -keyable false -channelBox false ($fols + ".brd");
    setAttr -keyable false -channelBox false ($fols + ".cbl");
    setAttr -keyable false -channelBox false ($fols + ".cr");
    setAttr -keyable false -channelBox false ($fols + ".cg");
    setAttr -keyable false -channelBox false ($fols + ".cb");
    setAttr -keyable false -channelBox false ($fols + ".sdn");
    setAttr -keyable false -channelBox false ($fols + ".dgr");

    // maya8+
    if($ver >= 8.0) {
        setAttr -keyable false -channelBox false ($fols + ".fsl");
        setAttr -keyable false -channelBox false ($fols + ".sgl");
    }
    
    // maya8.5+
    if($ver >= 8.5) {
        setAttr -keyable false -channelBox false ($fols + ".sct");
        setAttr -keyable false -channelBox false ($fols + ".ad");
        setAttr -keyable false -channelBox false ($fols + ".clumpWidth");
    }

}

//.........................................................................................................
// djRivetUnlockChannels() unlocks the translate, rotate and scale channels

proc djRivetUnlockChannels(string $surf) {

    setAttr -lock off ($surf + ".tx");
    setAttr -lock off ($surf + ".ty");
    setAttr -lock off ($surf + ".tz");
    setAttr -lock off ($surf + ".rx");
    setAttr -lock off ($surf + ".ry");
    setAttr -lock off ($surf + ".rz");
    setAttr -lock off ($surf + ".sx");
    setAttr -lock off ($surf + ".sy");
    setAttr -lock off ($surf + ".sz");
}

//.........................................................................................................
// djRivetIsTransformLocked() checks to see if one of the translate or rotate attributes is locked

proc int djRivetIsTransformLocked(string $dag){
    
    string $locked[] = `listAttr -locked $dag`;
    if(size($locked) == 0) return(0);
    string $xl;
    for ($xl in $locked) {
        switch ($xl) {
            case "translateX":
            case "translateY":
            case "translateZ":
            case "rotateX":
            case "rotateY":
            case "rotateZ":
                return(1);
            default:
                break;
        }
    }
    // if we got to here, there were locked attributes, but not translate or rotate
    return(0);
}

//.........................................................................................................
// djRivetIsTransformAnimated() checks to see if one of the translate or rotate attributes is animated

proc int djRivetIsTransformAnimated(string $node) {

    // get the connections and connected nodes
    string $animated[] = `listConnections -s true -d false $node`;
    if(size($animated) == 0) return(0);

    string $a;
    for($a in $animated) {
        string $t[];
        tokenize $a "_" $t;
        switch ($t[1]) {
            case "translateX":
            case "translateY":
            case "translateZ":
            case "rotateX":
            case "rotateY":
            case "rotateZ":
                return(1);
            default:
                break;
        }
    }
    // if we got to here, there were animated attributes, but not translate or rotate
    return(0);
}

//.........................................................................................................
// djRivetChooseUVSetWindow()

global proc djRivetChooseUVSetWindow() {

    string $uvSets[] = `polyUVSet -q -allUVSets`;
    string $form = `setParent -q`;
    
    formLayout -e -width 300 -height 75 $form;
    
        string $djRivetUVSetNames = `optionMenu -l "Choose a UV Set and click OK " djRivetUVSetNames`;
        for($s in $uvSets) menuItem -l $s;
                    
        string $xBut = `button -l "OK" -c( "layoutDialog -dismiss `optionMenu -q -v djRivetUVSetNames`")`;

    formLayout -e
        -af $djRivetUVSetNames "top" 5
        -af $djRivetUVSetNames "left" 5
        -af $djRivetUVSetNames "right" 5
        -ap $djRivetUVSetNames "bottom" 0 50

        -ac $xBut "top" 5 $djRivetUVSetNames
        -af $xBut "left" 5
        -af $xBut "right" 5
        -af $xBut "bottom" 1
        $form;
}


///
// GLOBAL PROCEDURES
//
// djRivet()

global proc djRivet() {

    // version number
    string $vS[];
    string $verS = `about -v`;
    tokenize $verS $vS;
    float $ver = $vS[0];
    
    int $lockedAttributeCount = 0;    // used to count failures due to locked attributes
    int $rivetCount = 0;            // count the objects actually riveted
    string $rivetList[];            // used to build list of objects to be riveted
    string $djRX;                    // store name of djRivet_follicles group
    
    print("djRivet start\n");

    // skip select flag was introduced in maya 8, used by createNode command, doesnt work in maya 7    
    string $SS = ($ver >= 8) ? " -ss " : " ";
    
    string $sel[] = `ls -sl -fl`;
    int $ns = size($sel);
    if($ns < 2) {
        warning("Invalid selection. First select at least one object, then last select a poly or nurbs surface.");
        return;
    }
    
    // get the shape node of the last object in the list (must be mesh or nurbsSurface, otherwise fail)
    //
    string $surf[] = `ls -dag -s $sel[$ns-1]`;
    string $surfType = `nodeType $surf[0]`;
    if($surfType!="mesh" && $surfType!="nurbsSurface") {
        warning("Invalid selection. First select at least one object then last select a poly or nurbs surface.");
        return;
    }
        
    // Create an empty group called djRivetX, lock and hide its transforms
    // This is where follicles and clusters will be hidden
    //
    if(!(`objExists djRivetX`)) {
        $djRX = eval("createNode transform -n djRivetX" + $SS);

        setAttr -lock true -keyable false ($djRX + ".tx");
        setAttr -lock true -keyable false ($djRX + ".ty");
        setAttr -lock true -keyable false ($djRX + ".tz");
        setAttr -lock true -keyable false ($djRX + ".rx");
        setAttr -lock true -keyable false ($djRX + ".ry");
        setAttr -lock true -keyable false ($djRX + ".rz");
        setAttr -lock true -keyable false ($djRX + ".sx");
        setAttr -lock true -keyable false ($djRX + ".sy");
        setAttr -lock true -keyable false ($djRX + ".sz");
        
        print("Follicle group called " + $djRX +" has been created.\n");

    }
    else {
        $djRX = "djRivetX";
        print("Follicle group called " + $djRX +" has been discovered.\n");
    }

    // check for vertices, cv's and lattice-points in the selected object list
    // Ask whether to cluster and constrain individually or together
    //
    string $pntHandling;
    string $pntList = "";
    int $pnts=0;
    for($i=0;$i<$ns-1;$i++) {
        if(size(`match "\\.vtx" $sel[$i]`) || size(`match "\\.cv" $sel[$i]`) || size(`match "\\.pt" $sel[$i]`)) {
        
            // vertices, cv's or lattice-points
            //
            $pnts++;
            if($pnts == 1) $pntHandling = `confirmDialog -title "djRivet" -message "How should vertices, cv's or lattice points be constrained?" -button "individually" -button "together" -defaultButton "individually" -dismissString "ignore" -cancelButton "ignore"`;

            if($pntHandling == "individually") {

                string $djCluster[] = `cluster -n "djCluster#" $sel[$i]`;
            
                // $djCluster[0] is the cluster, $djCluster[1] is the clusterHandle
                //
                string $cn[] = `parent $djCluster[1] $djRX`;    // parent clusterHandle to $djRX
                $djCluster[1] = $cn[0];                            // just incase name was changed
                setAttr ($djCluster[1] + ".visibility") 0;
                $rivetList[$rivetCount++] = $djCluster[1];        // put cluster name in the rivet list
            }
            else if($pntHandling == "together") {
                $pntList = ($pntList + " " + $sel[$i]);
            }
        }
        else {
            // transform nodes
            //
            $rivetList[$rivetCount++] = $sel[$i];    // put node name in the rivet list
        }
    }
    
    // Cluster the pnts together
    //
    if($pntHandling == "together") {
        string $djCluster[] = eval("cluster -n \"djCluster#\" " + $pntList);
            
        // $djCluster[0] is the cluster, $djCluster[1] is the clusterHandle
        //
        string $cn[] = `parent $djCluster[1] $djRX`;    // parent clusterHandle to $djRX
        $djCluster[1] = $cn[0];                            // just incase name was changed
        setAttr ($djCluster[1] + ".visibility") 0;
        $rivetList[$rivetCount++] = $djCluster[1];        // put cluster name in the rivet list
    }
    
    //
    // POLY MESH target
    //
    if($surfType == "mesh") {

        // closestPointOnMesh ignores polymesh transforms,
        // so we need make a temporary copy and freeze the transforms
        // (make sure transform channels are not locked)
        //
        string $tmpPolyMesh[] = `duplicate -n $sel[$ns-1] $sel[$ns-1]`;
        string $tforms[]=`listTransforms $tmpPolyMesh[0]`;
        if(size($tforms)!=0) parent -w $tmpPolyMesh[0];
        djRivetUnlockChannels($tmpPolyMesh[0]);
        makeIdentity -a true $tmpPolyMesh[0];
        
        string $tmpSurf[] = `ls -dag -s $tmpPolyMesh[0]`;
        
        // uv set handling: If there are multiple uv sets, ask which to use
        //
        string $uvSets[] = `polyUVSet -q -allUVSets $tmpSurf[0]`;
        string $uvSet = $uvSets[0];
        if(size($uvSets) > 1) {        
            select -r $tmpSurf[0];
            $uvSet = `layoutDialog -title "djRivet: Multi UV Set" -ui "djRivetChooseUVSetWindow"`;
                        
            if($uvSet != $uvSets[0] && $uvSet != "dismiss")
                // closestPointOnMesh uses the default uv set so copy the chosen uv set into the default
                polyUVSet -copy -uvSet $uvSet -newUVSet $uvSets[0] $tmpSurf[0];
            else
                // reset $uvSet if window was closed without making a choice
                $uvSet = $uvSets[0];            
        }

        // create closestPointOnMesh node
        // and connect it to the polymesh
        //
        string $cpom = eval("createNode closestPointOnMesh -n cpom1" + $SS);
        connectAttr -f ($tmpSurf[0] + ".outMesh") ($cpom + ".inMesh");

        // create a temporary transform node to store the location of the object
        // and connect it to the closestPointOnMesh node
        //
        string $loc = eval("createNode transform -n loc1" + $SS);
        connectAttr -f ($loc + ".translate") ($cpom + ".inPosition");

        // loop through the objects
        //
        for($i=0;$i<size($rivetList);$i++) {
                
            // make sure the translate and rotate attributes are not locked
            // if they are make a note in the script editor and skip the object
            //
            if(`djRivetIsTransformLocked($rivetList[$i])`) {
                $lockedAttributeCount++;
                warning($rivetList[$i] + " could not be constrained due to translate or rotate attributes being locked.");
                continue;
            }
            if(`djRivetIsTransformAnimated($rivetList[$i])`) {
                $lockedAttributeCount++;
                warning($rivetList[$i] + " could not be constrained due to translate or rotate attributes already animated.");
                continue;
            }
            
            //
            // move the transform node to the worldspace location of the object's rotatePivot
            //
            float $fpos[] = `xform -q -ws -rp $rivetList[$i]`;
            xform -ws -t $fpos[0] $fpos[1] $fpos[2] $loc;

            // get the uv coords from the closestPointOnMesh node
            //
            float $fu = `getAttr ($cpom + ".u")`;
            float $fv = `getAttr ($cpom + ".v")`;

            // create a follicle and parent it to a new transform
            //
            string $fol = eval("createNode transform -n \"follicle#\" -p " + $djRX + $SS);
            string $folN = `match "[0-9]+$" $fol`;
            string $fols = eval("createNode follicle -n follicleShape" + $folN + " -p " + $fol + $SS);

            // hook up the the follicle to the polymesh
            // and position it at the uv coords we got earlier
            // (these uv's can be easily edited later in the channel box)
            //
            connectAttr -f ($surf[0] + ".worldMatrix[0]") ($fols + ".inputWorldMatrix");
            connectAttr -f ($surf[0] + ".worldMesh[0]") ($fols + ".inputMesh");
            connectAttr -f ($fols + ".outRotate") ($fol + ".rotate");
            connectAttr -f ($fols + ".outTranslate") ($fol + ".translate");

            setAttr -type "string" ($fols + ".mapSetName") $uvSet;
            setAttr ($fols + ".parameterU") $fu;
            setAttr ($fols + ".parameterV") $fv;

            // tidy up channel box
            //
            djRivetHideFollicleChannels($fol, $fols, $ver);
            
            // parent constrain the object to the follicle
            //
            parentConstraint -mo -weight 1 $fol $rivetList[$i];
        }

        // clean up intermediate nodes
        //
        delete $cpom $loc $tmpPolyMesh[0];
    }
    //
    // NURBS target
    //
    else if($surfType == "nurbsSurface") {

        // closestPointOnSurface ignores surface transforms,
        // so we need make a temporary copy and freeze the transforms
        // (make sure transform channels are not locked)
        //
        string $tmpNurb[] = `duplicate -n $sel[$ns-1] $sel[$ns-1]`;
        string $tforms[]=`listTransforms $tmpNurb[0]`;
        if(size($tforms)!=0) parent -w $tmpNurb[0];
        djRivetUnlockChannels($tmpNurb[0]);
        makeIdentity -a true $tmpNurb[0];
        
        string $tmpSurf[] = `ls -dag -s $tmpNurb[0]`;

        // follicles use normalized uv's when attaching to nurbs
        // so we need to know the uv min max values
        //
        float $uRange[] = `getAttr ($tmpSurf[0] + ".minMaxRangeU")`;
        float $vRange[] = `getAttr ($tmpSurf[0] + ".minMaxRangeV")`;
        
        // create closestPointOnSurface node
        // and connect it to the nurbs surface
        //
        string $cpos = eval("createNode closestPointOnSurface -n cpos1" + $SS);
        connectAttr -f ($tmpSurf[0] + ".local") ($cpos + ".inputSurface");

        // create a temporary transform node to store the location of the object
        // and connect it to the closestPointOnSurface node
        //
        string $loc = eval("createNode transform -n loc1" + $SS);
        connectAttr -f ($loc + ".translate") ($cpos + ".inPosition");

        // loop through the objects
        //
        for($i=0;$i<size($rivetList);$i++) {
        
            // make sure the translate and rotate attributes are not locked
            // if they are make a note in the script editor and skip the object
            //
            if(`djRivetIsTransformLocked($rivetList[$i])`) {
                $lockedAttributeCount++;
                warning($rivetList[$i] + " could not be constrained due to translate or rotate attributes being locked.");
                continue;
            }
            if(`djRivetIsTransformAnimated($rivetList[$i])`) {
                $lockedAttributeCount++;
                warning($rivetList[$i] + " could not be constrained due to translate or rotate attributes already animated.");
                continue;
            }

            // move the transform node to the worldspace location of the object's rotatePivot
            //
            float $fpos[] = `xform -q -ws -rp $rivetList[$i]`;
            xform -ws -t $fpos[0] $fpos[1] $fpos[2] $loc;

            // get the uv coords from the closestPointOnSurface node
            //
            float $fuX = `getAttr ($cpos + ".u")`;
            float $fvX = `getAttr ($cpos + ".v")`;
            
            // follicles use normalized uv's when attaching to nurbs
            // so we need to convert the cpos sampled uv values
            //
            float $fu = abs(($fuX - $uRange[0])/($uRange[1] - $uRange[0]));
            float $fv = abs(($fvX - $vRange[0])/($vRange[1] - $vRange[0]));

            // create a follicle and parent it to a new transform
            //
            string $fol = eval("createNode transform -n \"follicle#\" -p " + $djRX + $SS);
            string $folN = `match "[0-9]+$" $fol`;
            string $fols = eval("createNode follicle -n follicleShape" + $folN + " -p " + $fol + $SS);

            // hook up the the follicle to the nurbs surface
            // and position it at the uv coords we got earlier
            // (these uv's can be easily edited later in the channel box)
            //
            connectAttr -f ($surf[0] + ".worldMatrix[0]") ($fols + ".inputWorldMatrix");
            connectAttr -f ($surf[0] + ".local") ($fols + ".inputSurface");
            connectAttr -f ($fols + ".outRotate") ($fol + ".rotate");
            connectAttr -f ($fols + ".outTranslate") ($fol + ".translate");

            setAttr ($fols + ".parameterU") $fu;
            setAttr ($fols + ".parameterV") $fv;

            // tidy up channel box
            //
            djRivetHideFollicleChannels($fol, $fols, $ver);
            
            // parent constrain the object to the follicle
            //
            parentConstraint -mo -weight 1 $fol $rivetList[$i];
        }

        // clean up intermediate nodes
        //
        delete $cpos $loc $tmpNurb[0];
    }
    else {
        warning("Invalid selection. First select at least one object then last select a poly or nurbs surface.");
        return;
    }
    
    // restore original selection
    //
    select -r $sel;
    
    // final status report
    if($lockedAttributeCount == 1) {
        print("\n");
        warning($lockedAttributeCount + " object was not constrained. See script editor for details.");
    }
    else if($lockedAttributeCount > 1) {
        print("\n");
        warning($lockedAttributeCount + " objects were not constrained. See script editor for details.");
    }
    else {
        print("djRivet done\n");
    }
}

/





djRivet;

转载于:https://www.cnblogs.com/y522122186/p/9418606.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值