Download createTreadsOnCurve.mel.

//*******************************************************************************************************************
// File name: createTreadsOnCurve.mel;
// Author:  Tony Kaap    05 May 2006
//
// Copyright belongs the author.  Permission to use and modify is freely given.
// This is for educational use.  Commercial use is freely allowed, but at your own risk.
//
//
// createTreadsOnCurve
// This script easily and flexibly attaches evenly-spaced copies of input geometry to an input
// curve, and animates them flowing along the curve.  Its primary purpose is to create tracks
// for tracked vehicles like tanks, tractors, and off-road crawlers.
//
// This is the actual work function, but the helper functions at the bottom allow you to call
// the function with one fewer parameter to remember.
//
// $aim == 1     -create aim constraints
// $aim == 0    -do not create aim constraints
proc createTreadsOnCurveDoIt( string $curve, string $srcObj, int $ct, int $time, int $aim )
{
    float $start, $end;
    float $step;

    // create the control wheel object
    string $control[]  = `polyPipe -r 3 -h 1 -t 0.5 -sa 20 -sh 1 -sc 1 -ax 1 0 0 -ch 0 -n "controlWheel"`;
    setKeyframe  -t 1 -v 0.0 ($control[0] + ".rx");
    setKeyframe  -t $time -v 360.0 ($control[0] + ".rx");

    setAttr ($control[0] + ".doubleSided") 0;
    setAttr ($control[0] + ".visibleInRefractions") 0;
    setAttr ($control[0] + ".visibleInReflections") 0;
    setAttr ($control[0] + ".smoothShading") 0;
    setAttr ($control[0] + ".primaryVisibility") 0;
    setAttr ($control[0] + ".motionBlur") 0;
    setAttr ($control[0] + ".receiveShadows") 0;
    setAttr ($control[0] + ".castsShadows") 0;

    // This sets the initial animation curve on the control object to "cycle with offsets"
    string $cSrc;
    if (`connectionInfo -isDestination ($control[0] + ".rx")`){
        $cSrc = `connectionInfo -sourceFromDestination ($control[0] + ".rx")`;
        $cSrc = match("[^\.]*", $cSrc + "\n");
        selectKey -add -k $cSrc;
        setInfinity -pri cycleRelative -poi cycleRelative;
    }

    // Create an empty group to drop all of the locators into.
    // This keeps the Outliner clean and usable
    string $locatorGroup = `group -empty -n ($control[0] + "Group")`;

    // Lock the channels of the locator group so that they don't get moved accidentally.
    setAttr -lock true ($locatorGroup + ".tx");
    setAttr -lock true ($locatorGroup + ".ty");
    setAttr -lock true ($locatorGroup + ".tz");

    setAttr -lock true ($locatorGroup + ".rx");
    setAttr -lock true ($locatorGroup + ".ry");
    setAttr -lock true ($locatorGroup + ".rz");

    setAttr -lock true ($locatorGroup + ".sx");
    setAttr -lock true ($locatorGroup + ".sy");
    setAttr -lock true ($locatorGroup + ".sz");

    // Setup work for driving the tread segment animation through complete rotations of the control wheel.
    $start = 0;
    $end = 360.0;
    $step = 360.0 / $ct;
    print ("Number of pieces: " + $ct + "\nRotational distance per piece: " + $step + " degrees\n");


    int $i;
    string $locators[];      // The newly-created locator
    string $locatorList[];    // A list of all of the locators created (used later for aim-constraining)
    string $objs[];            // The newly-created copy of the source segment geometry
    for ($i = 0; $i < $ct; $i++)
    {
        // Create and select a new locator.
        $locators = `spaceLocator`;
        select $locators[0];
        $locatorList[size($locatorList)] = $locators[0]; // Add this locator to the list of locators
        select -add $curve;
        // Attach the new locator to the curve by using a motion path.  Selection order is important.
        string $path = `pathAnimation -fractionMode true -follow true -followAxis z -upAxis x
            -worldUpType "objectrotation" -worldUpVector 1 0 0 -worldUpObject $curve -inverseUp true
            -inverseFront false -bank false -startTimeU $start -endTimeU  $end $curve $locators[0]`;

        // Create a new transform to parent to the locator.
        string $newGeometryGroup = `group -empty -n ("geomGroup")`;
        // Since there is a node named "geomGroup" for each locator, we need to add the "|" character to specify
        // that we want to operate on the only one at the root level of the scene heirarchy.
        $newGeometryGroup = ("|" + $newGeometryGroup);
        // Create a new copy of the source geometry.
        $objs = `duplicate $srcObj`;
        // Parent the geometry underneath the transform.
        parent -r $objs[0] $newGeometryGroup;
        // Parent the transform underneath the current locator.
        // This allows us to aim constraint the transform while permitting easy replacement of the geometry.
        parent -r $newGeometryGroup $locators[0];

        // This removes the initial animation from the "attach to motion path" command, then sets driven keys
        // from the control object
        string $source;
        if (`connectionInfo -isDestination ($path + ".uValue")`){
            $source = `connectionInfo -sourceFromDestination ($path + ".uValue")`;
            $source = match("[^\.]*", $source + "\n"); // grab just the object name.
            delete $source; // delete the time-driven animation curve;
            // Set up keys driven by the "control wheel" to drive the segments along the motion path.
            setDrivenKeyframe -currentDriver ($control[0] + ".rotateX") -dv $start  -v 0 ($path + ".uValue");
            setDrivenKeyframe -currentDriver ($control[0] + ".rotateX") -dv $end  -v 1 ($path + ".uValue");
        }else{
            // Execution should never reach this point in the code.
            print ($path + " is not a destination of a connection\n");
        }
        // This sets up the $source variable to point to the new driven key animation curve
        if (`connectionInfo -isDestination ($path + ".uValue")`){
            $source = `connectionInfo -sourceFromDestination ($path + ".uValue")`;
            $source = match("[^\.]*", $source + "\n"); // grab just the object name.

            // This sets the driven key animation curve to cycle properly
            selectKey -clear;
            selectKey -add -k $source;
            setInfinity -pri cycle -poi cycle;
        }

        // increment the counters so the next locator is offset properly along the motion path
        $start += $step;
        $end += $step;

        // put the new locator in the locatorGroup
        parent $locators[0] $locatorGroup;

    }
    // If enabled by the $aim flag, iterate through the list of locators created, and create an aim constraint for
    // the geomGroup underneath each one.  This construction allows for replacement of the geometry without having
    // to re-create the aim constriants for each node.
    if( 1 == $aim )
    {
        for($i = 0; $i< $ct; $i++)
        {
            int $prev = ($i>0 ? $i-1:$ct-1); // set the index for the previous locator in the tread.
            string $curLoc, $curLocGeomGrp, $prevLoc;
            $curLoc = $locatorList[$i];
            $prevLoc = $locatorList[$prev];
            // construct the path through the right locator to the right 'geomGroup' node;
            $curLocGeomGrp = ($locatorGroup+"|" + $curLoc + "|geomGroup");

            // create the aim constraint
            aimConstraint -offset 0 0 0 -weight 1 -aimVector 0 0 1 -upVector -1 0 0 -worldUpType "objectrotation"
                -worldUpVector 1 0 0 -worldUpObject $curve $prevLoc $curLocGeomGrp;
        }
    }

    // Clear any animation curves and keyframes from the selection.
    selectKey -clear;
    // End the tool with the controlWheel selected.
    select $control[0];

    // Create an arc length measure tool, and place it at the end of the curve.
    string $name = `arcLengthDimension ($curve+ ".u[1]")` ;
    // Read the length of the entire curve.
    float $arcLength = `getAttr ($name + ".arcLength")`;
    // Divide that length into segment sizes.
    float $arcLengthPiece = $arcLength / $ct;
    // Output the results to the Script Editor.
    print ("Curve length: " + $arcLength + " - Length per piece: " + $arcLengthPiece + "\n");
    // Remove the arc length measure tool.
    delete $name;
}

// Description:
//  This script quickly and easily duplicates and rigs geometry to move around a looped
// NURBS curve in the manner of a tracked vehicle like a tank.
//
// $curve - string - name of the input curve
// $srcObj - string - name of the input geometry
// $ct - int - number of segments you want the treads to have
// $time - int - number of frames it takes to have one segment of the treads make a full cycle of the curve.
//
// Command Format:  createTreadsOnCurve curve object count cycleDuration;
// Example:         createTreadsOnCurve curve1 pPyramid1 100 400;
//
global proc createTreadsOnCurve( string $curve, string $srcObj, int $ct, int $time)
{
    createTreadsOnCurveDoIt( $curve, $srcObj, $ct, $time, 1);
}

// Helper function to create treads that only use the curve's normal direction
// This will result in the geometry on the curve pointing in the same direction as the locators
global proc createTreadsOnCurveNoAim( string $curve, string $srcObj, int $ct, int $time)
{
    createTreadsOnCurveDoIt( $curve, $srcObj, $ct, $time, 0);
}
//*******************************************************************************************************************








 
tony@kaap.us | WebSite by KaapFamily.net  |  Valid CSS  |  Valid HTML