# Tank Rig Tutorial

Hello everyone, this tutorial will guide you through the process of creating a full tank rig system in 3ds max, well... maybe not fully but certainly with a lot of tools to make a realistic tank animation, actually, when you've learned this, you'll be able to make a car rig too with a little modifications. This is a medium-level tutorial, so you need some knowledge with the max's rigging tools (bones, IKs, constraints, and so).

You can check the tank's behaviour in this video: video_tank.mov (right click, save target as)

What you're gonna learn:

## Ground Projection System

With this system our rig will be able to detect a ground and adapt itself over the ground's surface; we will only need to animate a point through a spline path. The system could work without that spline, but the fact is that the next features of this rig need this usage. There are more complex systems that work pretty fine only with transform keyframes, but they're history dependant and consume more cpu resources than this one, maybe later on we'll be checking those methods.

## Auto Spinning Wheels

This system makes the animator's life easier; well... it's what a rig is supposed to do. Having a path where the tank will be going to travel, we're going to define the wheel behaviour in respect to this distance. Here we're going to use some scripting and some high school math, but don't be afraid! If you haven't tried this stuff yet, now you're going to learn, it's not hard, trust me, in fact, the entire math that we're going to use will be multiply and divide.

## Auto Slide Caterpillar

The caterpillar band will be composed of several pieces sliding through a spline which will be projected to the ground too, this is more realistic than other systems like using a path deform modifier over a whole caterpillar band, that's because each caterpillar's piece has its own behaviour instead of begin rubber-deformed like the path-deform method. Here we're going to use script controllers too, very similar to the wheels system, and some iterative macro operations. This last one will be very useful for a lot of tasks for other kind of projects, in a few words it means to do a lot of repetitive tasks in a few lines of code.

## Frame Position and Orientation

With this we're going to calculate the position of the tank's frame using the position of the wheels (this sounds easy!), and its orientation using the rotation of the wheels axles.

## Cannon Targeting System

Finally, we'll be making the cannon's rig. This one is a piece of cake; we'll be playing around with some look-at constraints.

Now let's begin....

We're going to use this file: tank_rig_start.rar. (right click, save target as) this is a 3ds max 9 version file.

Extract it in your pc and open the tank_rig_start.max file. Here we have a basic tank model: the frame, turret, cannon, a wheel (we'll clone the others), a caterpillar piece, and the ground. This last one was made starting with a plane with a lot of segments and some noise and wave modifiers applied to it. Also, we have some red spline objects and two points, they have an important function, we are going to use them as animation controls, the animator will only animate these objects (Just for manual adjustments), and the rig will do the magic!, so, they must be visible and accessible enough to help the animators recognize and select them as soon as they want to interact with the rig system. I choose red as its colour, but you may choose any colour you like, preferably a very light and saturated colour. We have a spline too, which is going to define our tank's path, when we finish our rig this spline could be modified as you like, moving, removing or adding vertices.

## The Ground Projection System

How are we going to project our tank to the ground?, there are several methods, some more complex than other, but the one that I'm going to explain right now is one of the most intuitive. The main Idea is to project our wheels' position using a mesh projection; we can do that using the "Conform" tool. If we have a mesh with one vertex for each wheel, we can project the mesh using this conform, and constraint the wheels' position to these projected vertices. We'll be using the conform Geometric/deformable space warp.

First, we are going to clone the wheels, this is for helping us to define where the mesh's vertices are going to be. Then we'll work only with one wheel.

Select the frame and the Wheel (the big one) and hide unselected. Copy the wheel in the same place (ctrl+V) select copy in the dialog Box and press OK, then without unselect this copy, place it to the opposite side of the frame shifting its x-position from negative to positive value (this is to make sure its position is exactly opposite). Then, Select both wheels and drag-copy them to the lower side of the screen, calculate a short distance from the first wheels, having in mind we're going to have 5 wheels each side along the frame. In the Clone Options Dialog select 4 in the Number of copies spinner.

Now let's create a 4 length seg by 1 width seg plane. Before drawing it into the viewport, configure the snap tool to snap to pivots. Right click over the Snaps Toggle button, in the Grid and Snap Settings Dialog check Pivot. Now, Hide the frame and from the top view create the plane snapping from the top-left wheel to the bottom-right wheel. Name this plane as ProjectedPlane.

Set zero as the plane's z-position, the plane should now be in the bottom of the wheels. Also add a shell modifier to it with zero in the Inner and Outer Amount. Without this modifier the projection isn't going to work, because the conform space warp doesn't conform open meshes.

After this, we're going to work over the first wheel, so delete the rest of them. It seems like a waste of time make the copies and then deleting them. But, they were useful to define from now the wheels' position and enabled us to create the projected mesh without having any future troubles with its vertices position.

Create a point helper with a size of 0.3 and the display form that you like, I choose a box.

Snap it to the first plane's vertex (the vertex where the first wheel is going to be constrained), as we did before snapping to pivots we can do the same snapping to vertices, Name this helper as "Helper_Attached_01", this point will help us to constraint the wheels to the plane's vertices. It'll be attached to the plane's vertex using an attachment constraint, this controller attach nodes to mesh faces, but we can use it as a vertex attachment constraint just defining the point's position over the face.

Rotate the wheel's pivot (with Affect Pivot Only, Hierarchy Panel) 90 degrees over its local y-axis. This is to make sure that our wheel's rotation will work fine setting its spinning over the x-axis which is the first one in the Axis order.
Then, Link the Wheel to the Helper_Attached_01 (Helper_Attached_01 as parent).

Select the Helper_Attached_01 and Add an Attachment constraint to it, select the plane as a target. The point now is in other position; we have to configure its attachment constraint. In the motion panel under the Attachment Properties Rollout set the next parameters: Face=7, A=1, B=0. The face is where the point we'll be attached and A and B are the barycentric coordinates, useful to place the point just over its respective vertex. Make sure the "Align to Surface" property is checked.

If the wheel has a wrong orientation you have to rotate the helper to fix it, just make sure the wheel has the orientation that it had before.

If the Face, A and B values doesn't work for you, you could change them until you get the right point's position.

Finally we're going to create the conform space warp and project the plane. Create panel -> Space warps -> Geometric/Deformable -> Conform. Draw it from the top view with any size you like, it must be pointing downward. Unhide by name the Ground. In the modify panel choose the Ground as Warp to Object and set zero the Standoff Distance (This parameter defines an offset position from the Mesh)

Bind the projected plane to this space warp with the Bind to Space warp tool. And this is it for now! Our first part of the rig is finished, now we have a modifier over the Projected Plane projecting it over the ground's surface. If we move our projected plane we can see how it adapts itself in real time.

## Auto Spinning Wheels

First of all, we need to create our tank's route, so we can use the distance along this path to define the wheel's spinning. We cannot use only the tank's current position, because the wheel's spinning depends on the distance travelled by the tank. For example, if our tank goes from the point A to the point C its wheel's rotation in the point C will be different if it goes from A to B and then to C, not to matter that it's finally in the same place, that's because the distance is different. So, if we create a spline as its path, we may know exactly the distance travelled by the tank along this path.

Unhide by name the "Path" and the "Control_Main" objects, we're going to use this last one as the point that is going to travel along the path. Select the Helper_Attached_01 and link it to the ProjectedPlane, then link the ProjectedPlane to the Control_Main, the hierarchy now goes as shown in the picture below.

Align the ProjectedPlane to the Control_Main, make sure to check all position and orientation axis and that both objects are in pivot point align. The plane now looks weird, but we'll fix that in the next step.

With this hierarchy we make sure the wheel and the projectedPlane will follow the Control_Main's rout and its orientation

Select the Control_Main and add it a Path_constraint, select the Path spline as target. We need to configure some settings in the motion panel. The point needs to "Follow" the path and its axis must to be "z" and flipped. With these settings the projectedPlane has a right shape, because it is now parallel to the ground.

## The Spinning Expresion

We'll need a mathematical expression in the wheel's x-rotation controller. In this expression we need to find the x-rotation value regards the distance travelled by the tank. I could give you the expression and you could use it without knowing how it was made, but I wouldn't be a good teacher if I make it so easy!

Seriously speaking, its better that you start understanding how to make expressions for future rigs challenges. So, here we go, a small and very easy mathematical lesson:

How can we find the wheel's x-rotation? Think about the distance that a circumference needs to travel to make a full turn. This distance is equal to its perimeter (2*pi*radius).

To find the numbers of turns along a distance, we could take this distance and divide it by the distance travelled by one turn (as mentioned before, one turn is equal to the perimeter). For example, if we have a distance of three times the wheel's perimeter, dividing the first value over the perimeter will give us a number of 3 turns.

And what do we do next with the turn's number? We could multiply it by its equivalent in degrees, 360º or 2*pi in radians, and we got our expression!

This expression goes as follows:

Actually, we may cancel the (2*pi) values by themselves. 2*pi / 2*pi is equal one (1), so we can remove these numbers, they're irrelevant now.

And what about the distance? How can we find it? We could do it using the percent along path of the path constraint, and the path's length. One value by the other will give us what we wanted: Distance= (Percent/100)*SplineLength, we divide Percent by 100 because here we need a percent that goes from 0 to 1. When the percent is 0% the distance is 0, when the percent is 100% the distance is equal the Spline's Length. 50% will give us a half of the spline's length, and so...

Finally the expression goes as follows: (Percent/100)*SplineLength / Radius

Now, we're going to put this expression in the wheel's x-rotation controller, we'll be using the script controller.

Select the wheel, in the Motion Panel open the Assign Controller rollout, select the Rotation: Euler XYZ Controller and click in the assign controller button, select Rotation List. With a list of rotations we may have 2 controller layers, one for the script and the other one for manual adjustments. Open the rotation List, in the Available controller assign an Euler XYZ controller, this controller is for manual adjustment, so we need to set it to active by double clicking it in the Rotation List rollout, or by clicking the "Set Active Button". When a controller is active this one will be the one that we'll be modifying by the rotation gizmo (manual adjustment).

Go back to the first Euler XYZ controller in the Assign Controller Rollout, open it, and in the x-rotation controller assign a float script controller

In the Expression Text Box write: SplineLength=curveLength Path, this line enables us to get the path's length using the curvelength maxscript function (it doesn't work well if the path spline is scaled). In the next line write the expression, (Percent/100)*SplineLength / Radius.

Then, we have to create the variables, and assign them their respective values.

In the Create Variable Group you have to write the names of the variables exactly as they're written in the Expression text box. Start writing the Path, then click on the Create Button, do the same with the Percent and radius.

We do not need to create the SplineLength variable because it going to get its value inside the script.

If we evaluate the expression now, we're going to get nothing, because we need to assign the variables to their respective values.

- Select Path in the Variables List and click in the Assign Node button, select the "Path" spline object in the "Track view Pick" DialogBox.

- Select Percent in the Variables List and click in the Assign Track button, select the control_Main's path constraint percent controller.

- Select radius in the Variables List and click in the Assign Constant button, write 0.473 (you can find it using the tape helper object measuring the wheel's diameter and then dividing by two).

You could assign the wheel's radius parameter to the radius variable if you need to change the wheels radius in the future.

If you evaluate now, we get our auto spinning system! You can check it out by moving the control_main object.

## Auto Slide Caterpillar

Right lets get part 2 of this 3 part tank tutorial under wya. Before we start creating the caterpillar we have to finish our wheel's set-up and then we'll clone it four times.

First we'll set up our Wheel's Control Object ("Control_Wheel_01"), as mentioned before in the first page, these control objects will be useful for the Animator's adjustments and custom animation.

Basically we're going to instance the transform controllers. Like instanced Objects, a change to the instance for any one controller will change all the others.
To do that, first unhide by name the "Control_Wheel_ 01", align it to the wheel (position and orientation) and make an offset in its position and orientation with the "Affect Object only" button pressed in the Hierarchy panel (take a look at the picture, both pivots must be in the same place).

Link the Control_Wheel to the "Helper_Attached_ 01". Since the transform controllers are respect to the Parent's transformation, we need to make sure that both objects have the same parent.Next, Select the Wheel_01 and open the Track view (you can also open the Mini Curve Editor clicking the button in the Left-Bottom of the Screen). Navigate until you find the Wheel's transform controller, click it and then with the right button, select "Copy". Then, navigate until you find the Control_Wheel's transform controller, click it and right click it, this time select "Paste" and check "Instance" in the Paste DialogBox.

Now both objects, Wheel and Control_Wheel are transform-controller Instanced, you can check it out by moving the Control_Wheel.

## Cloning the Wheels

Double-click the Helper_Attached_01 (it's easier if you do it in wireframe mode), it will select all the objects under its hierarchy, including itself. Clone them by pressing ctrl+v, select copy in both options (object and controller). If your cloned wheel has an orientation offset, you can fix it by selecting by name the Helper_Attached_02 and rotating it.

Then, select by name the Helper_Attached_02 if you haven't, go to the motion panel in the Attachment Parameters rollout and decrease the Face number until you get the right position for the second wheel, this number could be 2 units less than the first wheel (if this rollout doesn't appear you need to activate the position button in the PRS Parameters rollout). Do the same process three more times for the remaining wheels. For the last wheel you need to change the A and B values to fix its position (A=0, B=1) and set the face value to 1.

## Creating the Caterpillar

As mentioned in the first page, the caterpillar is based in several pieces sliding around a spline. So now, we'll create the spline.

Select the projectedPlane, in the Modify panel turn off it's conform binding modifier by clicking the bulb and set its world position and rotation values to zero. This is temporary; it's to do the next steps more easily having the tank aligned to the viewport.

To create the small wheels, double click the Helper_Attached_01 to select it with the wheel and the control object, clone them pressing ctrl+v, select copy in both options. We need to clone the wheel with the helper because we need a parent with the same orientation (the controllers are in respect to the parent's transform), select the Helper_Attached_06, in the motion panel select its Position list controller and replace it by a Position XYZ controller, doing this we're deleting the attachment constraint.

Fix its orientation by rotating it -90 degrees over its z-axis, and place it in the back-top side of the tank (see picture), Unhide the Frame and link the helper to it. Then select the wheel and decrease its radius value, like 0.373, you have to decrease it in the script controller too.
To create the front small wheel, double click the Helper_Attached_06, clone the objects, select by name the Helper_Attached_07 and place it at the front of the tank.

From the left view start creating the spline adding vertices at the bottom of the wheels, one vertex per each wheel, continuing above the small wheels (see picture below). Finally make sure that all vertices are bezier type with tangents as large as shown in the picture (select vertices -> right click -> left-top quad -> bezier), these tangents will generate a smooth interpolation in the spline while being deformed over the ground's surface. From the top view move the line to the middle of the wheels. Name this spline as "CaterpillarSpline".

From the left view start creating the spline adding vertices at the bottom of the wheels, one vertex per each wheel, continuing above the small wheels (see picture below). Finally make sure that all vertices are bezier type with tangents as large as shown in the picture (select vertices -> right click -> left-top quad -> bezier), these tangents will generate a smooth interpolation in the spline while being deformed over the ground's surface. From the top view move the line to the middle of the wheels. Name this spline as "CaterpillarSpline".

Next, we need to create one point helper for each spline's vertex. Use the Vertex snap tool for this operation and set a size of 0.2 for them. We're gonna use these helpers to deform the spline's vertices. Name them Helper_CaterpillarPoint_1, Helper_CaterpillarPoint_2 .... starting by the Helper in the first wheel. You could use the rename Objects tool in the tools menu.

There are some methods to deform a spline using nodes, like the Spline IK Control modifier. But I didn't use it in this rig because in some tank's orientations the vertices didn't behave well, also, it has problems when you clone it. So, finally I decided to use the skin modifier. This modifier will affect the spline's vertices as it does with mesh vertices, it's not expensive for the pc (the spline has a very few vertices) and it doesn't have problems like the Spline IK Control does.

Add the skin modifier to the spline, and then, add all the Helper_CaterpillarPoints as bones. Modify the weight for each vertex and its tangents points in respect to their respective Helper, until you get the desired result.

Now, link the bottom helper_CaterpillarPoints to their respective Helper_Attached points, doing this the spline will be attached to the ProjectedPlane too. Link the rest of the CaterpillarPoints to the Frame, and link the Frame to the ProjectedPlane (Do not forget do this).

To make the helpers follow the wheel's position, we'll need a position constraint. Select the wheel_01 caterpillar helper add a position constraint to it selecting the wheel as the target. We cannot use the "Keep Initial offset" option because it defines positions not relative to the tank, therefore in some tank's orientations this helper will have a wrong position. To place it where it was before assign a Position XYZ controller in the available controller of the position list and make it active in the position list Rollout, you can delete the first Position XYZ controller, it's useless now. Then place the helper where it was before (you can do it aligning it to the Helper_Attached object).

Do the same process with the rest of the wheels. The upper caterpillar helpers need to be constrained to the small wheels .

## Caterpillar Pieces

The pieces will slide using a path constraint over the spline that we have created, then we'll add a script controller in its percent along path controller to define its sliding in respect to the distance travelled by the tank.

Unhide by name the Caterpillar_Piece_01, link to the Frame and add a path constraint to it using the CaterpillarSpline as target. In the motion panel in the path parameters rollout set the parameters as shown in the picture. The Allow Upside Down option will enable the piece to have the right orientation through the spline without any flipping.

Then rotate the piece -90 degrees over its local x-axis and then -90 degrees over its local z-axis.

Now, we'll add the script to the percent controller. In the motion panel -> Assign controller rollout (you can also do it in the track view) assign a float list controller in the percent controller, in the list's available controller assign a Bezier float controller, and in the First controller (Linear Float) assign a Float Script. We created a list of controllers to define an extra value with the second controller, so, in this way, we can define an offset to each caterpillar's piece having the same script controller for all of them.

The script is almost the same than the wheel's spinning. But in this time we're not using a radius, instead, we'll be using the Caterpillar length. Start writing the first line of the previous script:

SplineLength=curvelength Path

Then add the next line after the first one:

CatLength=curvelength Caterpillar

In the last line replace radius by CatLength and place a minus at the beginning of this line:

-(Percent/100)*SplineLength/CatLength

And don't forget to create the variables and assigning their respective nodes or tracks. In the Caterpillar variable we need to assign the CaterpillarSpline as node.

In this case we're finding the number of the piece's turns along the caterpillar dividing the distance by the caterpillarLength (the perimeter).
This is what the controller handles, a value from 0 to 1, 1 as 100%, in this case as 1 turn along the spline.

## Cloning the Pieces

To clone the pieces we need to do the same process 50 times!.

Fortunately, there are methods to do it very quickly, an iterative macro operation. As I said in the first page, it means to make a lot of repetitive tasks in a few lines of code.

Go to Maxscript Menu -> New Script. In the Text Field paste these lines of code:

for i=1 to 49 do
(
newPiece=copy \$Caterpillar_Piece_01
newPiece.position.controller[2].percent.controller[2].value=(i/50 as float)*100
newPiece.position.controller[2].percent.controller[1].controller=
\$Caterpillar_Piece_01.position.controller[2].percent.controller[1].controller
)

How it works:

for i=1 to 49 do

First, we need to define the iteration range using the sentence "for", using the variable "i" we start defining the first number of the iteration, in this case we start from 1, and then defining the last number of the iteration, in this case 49, we'll be executing the same process 49 times. Inside the Iteration the current loop number is stored in the variable "i", we can use this number to set a percent offset in the current piece copy.

Between parenthesys we describe the process that we need to repeat 49 times.

newPiece=copy \$Caterpillar_Piece_01

In this line of code we're creating the copy of the piece and storing it in the "newPiece" variable, we need to use the "\$" character before the object's name to be able to use this object inside maxscript. If the object's name has any space on it, in maxscript we need to replace this space by the "_" character.

newPiece.position.controller[2].percent.controller[2].value=(i/50 as float)*100

In this line we're defining the percent offset. With the dot character (.) I'm accessing into a property, first accessing the newPiece's position property, then the second controller of the position, then its percent, then the second controller of this percent, and finally the value of this controller. I use the variable "i" (current loop) to find the right offset, if we divide this number by the total number of copies we get a value ranged from 0 to 1, multiplying it by 100 we get the percent respective to the current copy. i use "as float" to make sure the division will bring me a decimal number.

newPiece.position.controller[2].percent.controller[1].controller=
\$Caterpillar_Piece_01.position.controller[2].percent.controller[1].controller

This is only one line actually, it was too long. Here, we're copying-instance the first percent controller, the script controller. If we'll need to make any configuration to this controller in the future, we'll need to make it only once. And also there's only one script controller executing only one time giving a value shared for all the pieces.

After you place the code in the Text Field of the maxscript editor go to File->Evaluate All. Now we got 50 pieces!
This is just a very very tiny explanation of iterative macro operations; you could check the Maxscript reference for a lot of information about this. Also, you could use the Macro recorder to find the maxscript code for an operation in max; you can activate it in the Maxscript menu -> Macro recorder. It enables a pink Text Field in the Maxscript Listener (Maxscript Menu->Maxscript Listener). If you made an operation in max the script will appear in this text Field, unfortunately not all the max's operations appears there.

Join us next week when we wrap up this tank rig with creating a fullt movable turret and cannon.

## Frame Position and Orientation

Before we create the frame position and orientation system, we need to copy the wheels and caterpillar for the left side of the tank. But, there's a problem that we need to deal with. After clone the caterpillar, the original caterpillarSpline will have the skin with the cloned helpers as bones and not the original ones. Fortunately there's a trick to avoid this, just turn off the caterpillarSpline skin modifier.

Hide the Frame, the turret and cannon objects. Select all the wheels, helpers, pieces, and control objects of the right side. You can do it in the top view drawing a selection rectangle over all the objects (see picture below), unselect the ProjectedPlane after this. Press ctrl+v, and check copy in both options.

Now select by name the caterpillarSpline and turn on its skin modifier, do it also with the caterpillarSpline01.

Select by name the Helper_Attached_14, in the motion panel change its A and B values to set its new position (probably you only need to set A=0), do the same process with the 13, 12, 11, and 10 Helper_Attached objects. The front wheel will be different, change its Face number too (Face=2), set A=1 and B=0, and rotate it 180 degrees over its local z-axis.

To mirror the position of the Helper_Attached_09 and Helper_Attached_08 (the new Wheel_Small helpers) change their x-position value from negative to positive value.

Now, select all the Control_Wheel objects and change its object position with the "Affect Object Only" button activated in the hierarchy panel, put them in the opposite side of the wheels.

## Creating Axles

With these axles we can control the frame's orientation. After creating them, the frame will have their orientation average. We'll be using bones with IK solvers.

Hide all but the wheels and the projectedPlane. From the top view create a bone from each of the left wheels to each of the right wheels using the snap tool with pivot activated, set width and height to 0.3 in the create panel and don't delete the end bones. Name the big bones as Axle_Main_01, Axle_Main_02....and the End bones as Axle_End_01, 02, 03...etc. Add an IK solver to each pair of bones, you can decrease the IK goal size in the motion panel, link the main axle's bones to their respective wheels and do the same with the IK solvers (see picture).

Now, the Axles have an orientation in respect to the wheels, but they also need an extra orientation in respect the overall system, we'll be using the IK Solver swivel angle for this. That'll be useful, for example, in ground inclines where the frame needs to rotate forwards or backwards.

Create a point helper; this helper will be the target of the IK solvers swivel angle, so we need to place it at the centre of the tank. Select this helper name it Helper_AxlesSwivelTarget and align it to the middle axle, in the Align DialogBox check "centre" in the "Target Object" group and make sure all position axis are checked. Then, link it to the middle axle.

Select the first IK goal, in the motion panel set the Helper_AxlesSwivelTarget as target using the pick button in the IK solver plane group, do the same with the other IK goals but the middle one. This middle bone won't have swivel target, for this reason, we cannot leave it linked to the wheel, if we do, it will spin with the wheel.

Select the middle Axle_Main bone and link it to the ProjectedPlane. Then add a position constraint to it with the Wheel as target, this is to replace the job that the link was doing before without the spinning issue, select the middle IK goal and set the Swivel Angel=180, with this value this axle will have the same orientation of the other ones.

We have now a little problem to solve, the front axles; the Axle_Main_04 and Axle_Main_05 have a difference of 180 degrees in respect the other axles. Therefore, the orientation constraint won't work as we desire for these bones. What we can do is to create helpers for these axles having a 180 degrees rotation offset. Create and Name them as Helper_Axle_04 and Helper_Axle_05, align them to their respective axle checking all position and orientation axis and the "Centre" option in the "Target Object" group. Link them to their respective axle and rotate them 180 degrees over their local x-axis.

Create another helper with a different size and shape, align it to the AxlesSwivelTarget and name it Helper_Frame. Add a position constraint to it and add as target all the wheels (motion panel). Then add an orientation constraint and add as target the Axle_Main_01, Axle_Main_02, Axle_Main_03, Helper_Axle_04 and the Helper_Axle_05. Unhide the Frame and link it to this new helper.

Our Frame orientation and position system is done!, you can check it out by moving the wheels over their z-axis.

## Frame, Turret and Cannon Control Object Set-Up

Just like we did before with the wheels' control objects, we're going to do the same with the Frame, turret and cannon objects.

Unhide all, Select the Control_Frame and align it to the frame, check the entire position and rotation axis and the pivot option in the "Target Object" group. With "Affect Object Only" button in the hierarchy panel, create an orientation and position offset until you find a good place and orientation for this object (see picture below). Since this control object will have the same transform controller of the frame, is good to align its pivot to the frame to ensure we'll have the same position and orientation after copy-instance the controllers.

Do the same with the rest of the control objects with their respective tank objects.

Create the hierarchy of the tank's parts; link the turret to the frame, the cannon_base to the Turret and the cannon_extension to the cannon_base.

As we did with the wheel's control object, we need to link the control objects to their respective objects' parent.

In the track view copy-instance the transform controllers for each object and its control object, you can do it easier in the mini curve editor.

Now we can get the projectedPlane where it was before, select it, align it to the Control_Main (position and orientation) and activate its Conform Binding Modifier.

## Cannon Targeting System

The cannon base will have a look at constraint, also the turret but only over its z-axis. For both objects we need to create a point helper that finally contains the look at controller, the objects will inherit their rotation.

Create two points helper, name them Helper_LookAt_Turret and Helper_LookAt_Cannon. Select the Helper_lookAt_Turret and align it to the turret, link it to the Turret's Parent (the frame) and assign it a lookAt constraint with the Control_Target object as target. Then select the Helper_lookAt_Cannon, align it to the cannon base, link it to the cannon base parent (the Turret) and assign it a lookAt constraint with the Control_target object as target.

You may like to do not have the lookAt viewline disturbing in the viewport, so you can hide it in the motion panel, setting zero the "viewline length" value in the look_at constraint rollout.

There are some methods to get the rotation of an object that has a lookAt constraint, like using wiring with an ExposeTM Helper, which exposes an object's transform values, even if it has any constraint assigned. But, I prefer to use script controllers, because I didn't need to create any extra object to make it work.

Select the Turret, in the motion panel -> Assign Controller rollout, select the Rotation: XYZ Euler Controller and assign a Rotation List controller to it. As mentioned before, this controller will enable us to have two controller layers, the first with the script controller and the other one to make manual adjustments.

In the Available controller assign an Euler XYZ Controller, go back to the first Euler XYZ, and in the Z Rotation controller assign a script controller.

In the expression, first we need to find the local rotation values of the helper, that's because the controllers need values in local mode (local values in max are respect to the parents). We can do that using the transform values of this helper and its parent.

The way that a 3d software inherits the transform values from an object to its children is to multiply the parent's transform matrix by its children local transform matrix. Having in mind this, we may find the child's local TM by doing the inverse process. In math the inverse process of multiply two matrices isn't divide them, it's a special process called "Inverse", max has a maxScript function for this.

So, the expression goes as follows: helper's transform * inverse parent's transform

From this resulting transform we need to extract the rotation value: (helper's transform * inverse parent's transform).rotation

Then we need to convert this rotation from Quaternion values to Euler angles values in order to be able to get its Z rotation value. To don't make the code line too long, i assign this rotation to a variable and continue in the next line.

So, it goes as follows:

rot=(helper's transform * inverse parent's transform).rotation
(rot as eulerangles).z

For the helper we're going to create a variable called helper_lookAt assign the Helper_lookAt_Turret as node. We can get the parent node as an object's property. The expression finally goes as below.

rot=(helper_lookAt.transform * inverse helper_lookAt.parent.transform).rotation

degtorad is a need because the controller handles rotation values in radians.

The Cannon_base will need all the rotation values from its helper_lookAt. We cannot assign the lookAt constraint directly to the cannon, because we won't be able to make manual adjustment to it. We could assign an extra Euler XYZ controller in the rotation list for manual adjustments, but it will have unexpected behaviours when we rotate it (this problem happens in rotation controllers only, in position controllers it doesn't happen, and in the turret case, it doesn't happen either because we're using only one axis there).

But there's a way to make it possible, we're going to link the cannon to the helper. Select the cannon_base and the Control_cannon_base objects and link them to the Helper_lookAt_cannon, then select the cannon_base, align it to the Helper_lookAt_cannon (orientation), now it has a wrong orientation, so rotate it 90 degrees over its local y-axis.

Doing this the cannon will inherit the helper's orientation, and also we'll be able to make manual adjustments.

You can move the Control_Target to check this out!

Ok, and finally this is it!, out tank rig is done!. You can animate the Control_Main object throw the path spline and also modify this spline as you like.

## Final Notes

To adapt your tanks final model to this rig, you only need to align and link the model's parts to the tank's objects. And if you want a rig more comfortable you can create layers in the max layer manager, one for helpers, other for Control objects etc. Also you could block some position and/or rotation axis in some objects (Hierarchy panel -> Link Info Button), for example in the turret's x and y rotation axis, to avoid movements that aren't possible in the tank. The rig objects like the Frame or the turret are geometric objects, but if you like they could be bones, finally both are nodes. Finally like any other rig you have to be careful with scales.

I hope you enjoyed this tutorial, more stuff will come soon!

Enter content...