Rigging a Sprite Sheet in 3dsmax

A user recently asked on CGTalk:

i want to use max to create something like this :
http://www.youtube.com/watch?v=AizepmgmkOY

basically i want to have a controller like this one :
http://www.youtube.com/watch?v=EHNmcsUdUtc

but instead of it controlling morph targets , i want it to control a texture on a plane object
so it will cycle or load different images for set values in the controller position.

This article will demostrate a method of hooking up a sprite sheet to a two-dimensional joystick controller.

This will be our sprite sheet for the example:

It may not be much to look at, but for testing purposes it will be the easiest way of determining if we’re getting the right image or not.

You can download the initial and final scene files here:
Download Sprite Sheet Rigging Scene Files (3dsmax 2009)

As a starting point, we have a teapot and a joystick controller. Notice that both the joystick frame and the joystick controller itself have their pivot set to their bottom left corner. This will make it easier to extract the normalized value from the controller. The joystick controller is also parented to the frame.
As you might expect, the joystick has a limit controller applied to it’s X and Y axes to keep it within the frame.

The teapot has a material applied with our sprite sheet loaded as a texture.

First we must scale our UV space. We do this so we get a UV space in the range of 0 to 1 for each sprite. This has the advantage of decoupling the object’s UV mapping from the sprite sheet, allowing us to think in normal terms when mapping our object.
So, if we have 7 sprites on the X axis and 3 sprites on the Y axis, our UV space, centered at [0,0], will range from -3 to 3 on the X and -1 to 1 on the Y.

To scale our current UV space we simply divide the U and V tiling parameters by the number of sprites in each axis.

U tiling: 1.0 / 7 = 0.142857
V tiling: 1.0 / 3 = 0.333333

Now we must write code that will snap the position of the joystick controller to the correct values. We will add float script controllers to the U offset and V offset parameters of our texture.
This is most easily done from track view.
Select the tracks in track view and from the controller menu choose ‘Assign…‘. Select ‘Float Script‘ as the controller type.

First we must create variables for the relevant joystick position controller, and a constant value for the number of sprites in this axis.
Create a variable named xCtrl and use ‘Attach Controller‘ to connect it to the Float Limit controller of the joystick’s X position.
Then create a variable named NumSpritesX and use ‘Assign Constant…‘ to assign it a value of 7.

This is the complete code for the U offset controller:

local normalizedX = xCtrl.value / XCtrl.upper_limit
local xIndex = (normalizedX * NumSpritesX - 0.001) as integer + 1
NumSpritesX / 2. + 0.5 - xIndex

The first line normalizes the position of the joystick by dividing it by the upper limit of the limit controller. because the pivots are aligned as mentioned before, and the joystick is parented to the frame, we get a normalized value in the range of 0.0 to 1.0.
We then use this value to determine the index of the sprite we need to retrieve.
We do this by multiplying the normalized position by the number of sprites on the X axis (in this case, 7) and casting to an integer. This cast is what provides the ‘snap’ behavior. Otherwise we would get a smooth movement across the UV space, which we are trying to avoid.
We subtract -0.001 from the value before casting to integer so that a normalized position of 1.0 (when the controller is farthest to the right) will not loop back to the first sprite. As the result we get is 0-based, we add 1 to convert it to 1-based.
The final line converts the index of the sprite to its valid U offset value. Because our U space is centered at [0,0] and ranges from -3 to 3, we must subtract the index from half of the total number of sprites, and add 0.5 so we end up on the correct boundary.

Do exactly the same for the V offset parameter.

Now everything should be hooked up. You can move the joystick around and the correct sprite should appear on the teapot.

If we want to change the number of sprites in the sprite sheet, all we need to do is:

  • Change the U and V tiling parameters on the bitmap texture.
  • Change the NumSpritesX and NumSpritesY variables in the script controllers of the U and V offset parameters.

Everything else will adjust automatically. The frame can also be resized to whatever we want, as long as the pivot alignment is maintained and the limits are updated.

In a proper production environment, or just to take it a step further, we could also put a custom attribute on the joystick controller with spinners for inputting the dimensions of the sprite sheet, making the rig more animator friendly. The U and V tiling paremeters as well as the variables in the script controllers would then be linked to these custom attribute parameters.