### **Rolling Cube Rig**
Rolling a cube is a variant of a rolling (or bouncing) ball, requiring a cube to turn on an edge as it rolls.
![[01.RollCube_TX.gif|*rolling a cube along the X-axis in Maya*]]
*rolling a cube along the X-axis in Maya*
This exercise demonstrates simple rig elements: **hierarchy**, **node specialization**, **breaking hierarchy with animation connections**, and a **focused control** (a single curve). This will also reveal some _**limitations in rigging**_ since we rig for a **specific solution** -- there may be a more sophisticated rig that solves the problems for more situations, but we will stick to this simple rig initially.
_Here are the steps to set up the rig:_
### **Hierarchy & Node Specialization**
Remember, we **build around the origin ( 0 0 0 )** and use **real-world units** to make sure we maintain registration of the rig to the world.
#### **1. Create the geometry.**
**1a. Create > Polygon Primitives > Cube**
![[02.CubeGnomon.png|*polygon cube at the origin displaying manipulator*]]
*polygon cube at the origin displaying manipulator*
This creates geometry at the origin that will break through the ground at Y=0, and later, we will maintain the mass (for squash & stretch) and center of gravity by moving the cube up with the offset level of the hierarchy so that it rests on the ground.
1b. Rename the new cube to "_**Cube_geo**_" or "_**Dice_geo**_" or something like that.
#### **2. Add group levels to isolate rig elements for rotation, offset, (squash & stretch), and position.**
With the cube geometry selected...
**2a. Edit > Group (_Ctrl + G_)**
Use the default settings: Group under _Parent_, Group pivot _Origin_, Preserve Position
**2b.** Rename the first group above the cube: _**rotation_grp**_
_**----
**_If you want to add an **extra** control:
**2c. Edit > Group (C_trl + G_)**
**2d.** This group should be renamed to:
The hierarchy should look like this: _**squashStretch_grp**_
_This tutorial will not set up squash & stretch., though you can easily use SDK to do so
-----_
Then, again...
**2e. Edit > Group (_Ctrl + G_)**
**2e.** And rename the group: _**offset_grp**_
![[03.Outliner.png|*Outliner Hierarchy consists of offset_grp parent of rotation_grp parent of Cube_geo*]]
*Outliner Hierarchy consists of offset_grp parent of rotation_grp parent of Cube_geo*
_**extra:**_ You can also add a _**squash_stretch_grp**_ group, which is below _**offset_grp,**_ so that the cube squashes against the ground, even when it is rolling on edge.
### **Focused Control**
#### **3. Create the MSR (Move Scale Rotate) control as root**
**3a. Create > NURBS Primitives > Circle**
**3b.** Rename the node to "**Cube_MSR**"
With the MSR selected:
**3c. Edit > Delete by Type > History (_Alt + Shift + D_)**
and
**3d. Modify > Freeze Transformations**
(Use the defaults to **Freeze Translate, Rotate, and Scale**.)
**3e.** Parent the top group node (either _**offset_grp**_ or _**squash_stretch_grp**_) to the new **MSR**
This top root will collapse the rig under one node. All the animation keyframes will be placed on this node. The animator does not need to access any of the nodes underneath except indirectly through the rig we will create below.
**3f.** To move the cube up to rest on the ground, move **_rotation_grp._TranslateY** up to **0.5**.
The hierarchy, **Cube_MSR** selected, with the Channel Box looks like this:
![[04.Hierarchy.png|*Outliner hierarchy, Perspective Cube rig controls, Channel Box*]]
*Outliner hierarchy, Perspective Cube rig controls, Channel Box*
### **Breaking Hierarchy: Automate the rig with Set Driven Key**
The goal is to translate the **MSR** along the **X-axis** and have the cube automatically roll in the correct direction, lifting up so that the right lower edge of the cube stays on the ground. We will use **Rotation Z** on the _**rotation_grp**_ and **Translate Y** on the _**offset_grp**_ to coordinate this motion after _**editing the curve tangents**_ in the graph editor.
For **each unit translated in X**, the cube will **roll (rotate) 90 degrees in Z**, hop up a bit in **Y** to accommodate rolling over the edge, and then sit back down on the ground. We can then extrapolate this motion in both directions indefinitely.
We will use **Set Drive Key (SDK)** for this, creating the following connections and keyframes:
| | | |
|---|---|---|
|**_Cube_MSR_.TranslateX**|**_rotation_grp_.RotateZ**|**_offset_grp_.TranslateY**|
|0.0|0.0|0.0|
|0.5|-|0.207|
|1.0|-90|0.0|
To fine-tune this motion, we can **edit the curve tangents** for the TranslateY curve. In order to avoid any unintended compound effects, ensure all the **Rotate axis curves** are **linear**. This keeps the interaction between the **Rotate** and **Translate** simple and allows the animator to add the slow-in and slow-out for the cube's performance.
#### **4. Connect the control to the rotation**
The "mantra" to keep the SDK workflow straight is: **"Driver. Attribute. Driven. Attribute. Key"** If you step through this list with each keyframe, you will not miss setting a value. Remember to change the **driver** attribute first, or the **driven** attribute will snap to the animated value, and you will have to set its value again. And don't forget to set the _**first key**_ for the default value!
To create the first keyframe with **SDK**:
4a. Select the _**Cube_MSR**_.
4b. In the **Animation Menu Set**, select **Key > Set Drive Key > Set...**
4c. In the **Set Driven Key window**, **click on Load Driver** to put the _**Cube_MSR**_ in the _**Driver list**_.
4d. In the **Outliner**, **select** both _**offset_grp**_ and **rotation_grp**.
4e. In the **Set Driven Key window,** **click on Load Driven** to put these nodes in the _**Driven list**_.
4f. From the Driver list, select _**Cube_MSR**_ and then the **Translate X** attribute.
4g. From the Driven list, select _**rotation_grp**_ and then the **Rotate Z** attribute.
4h. Key the first values of **_Cube_MSR_.TX 0** and **_rotation_grp_.RZ 0**
![[05.SDK.png|*Set Driven Key window with Cube_MSR.Translate X selected in Driver list and rotation_grp.Rotate Z selected in Driven list*]]
*Set Driven Key window with Cube_MSR.Translate X selected in Driver list and rotation_grp.Rotate Z selected in Driven list*
#### **5. Create the next SDK keyframe for X-axis movement and cube rotation**
5a. Click on _**Cube_MSR**_ in the SDK window to select the control and move **Translate X** to **1**. You can type the TX value in the Channel Box.
5b. Click on _**rotation_grp**_ in the SDK window and **Rotate in Z clockwise** to **-90**. You can type the RZ value in the Channel Box.
5c. Set Driven Key > **Key**
To test the animation, select _**Cube_MSR**_ and **pull the manipulator** back and forth in the **X-axis**. The cube should rotate between 0 and 1, but the edge will dip below the "ground" -- we will fix this next with the _**offset_grp**_.
#### **6. Connect the control to the offset**
6a. If the _**offset_grp**_ node is not in the **Driven list** of the **Set Driven Key window**, select the node in the **Outliner** and click on **Load Driven**.
6b. Select _**Cube_MSR**_ and move **Translate X** back to **0**.
6b. Make sure _**Cube_MSR**_ is selected in the **Driver list**, then **Translate X**. Select _**offset_grp**_ in the **Driven list** and then select **Translate Y**.
6c. **offset_grp.TranslateY** should be set to **0**. Hit **Key**.
6d. Select **Cube_MSR** in the Driver list. The value of **offset_grp.TranslateY** should remain at **0**. Hit **Key**.
6e. Select Cube_MSR at change the Translate.X value to 0.5, halfway in-between the two keyframes.
In the **Front view**, focus on the cube (**hit the _F key_**) and see that the edge of the cube is dipped below the Y=0 axis at **Cube_MSR.TX=0.5**.
6f. Select _**offset_grp**_ in the Driven list (make sure **Translate Y** is still selected). **Drag the Y (green) manipulator** in the Front view (you can even **zoom in** with _**Alt + Right Mouse Button**_ to see the corner more exactly) so that the corner (edge) of the cube just touches the **Y=0 axis**. In the SDK window, click **Key**.
To test the animation, select _**Cube_MSR**_ and **pull the manipulator** back and forth in the **X-axis**. As cube rotates, the corner/edge of the cube will still dip a bit between 0 and 0.5 and then again between 0.5 and 1. We will adjust this in by **editing the animation curve.**
#### **7. Fine-tune the Animation Curve to fix the Cube Roll.**
7a. Open **Windows > Animation Editors > Graph Editor** to see the animation curves created by the SDK window. You can move the SDK window to the side (or minimize it).
7b. To see the curve we want to adjust, select the **offset_grp** node in the **Outliner** and look in the **Graph Editor**.
_This is what the curve should look like just after creating keyframes with SDK above:_
![[06.CurveEditor.png|*Graph Editor showing the Set Driven Key curve of Cube_MSR.TranslateX versus offset_grp.TranslateY*]]
*Graph Editor showing the Set Driven Key curve of Cube_MSR.TranslateX versus offset_grp.TranslateY*
Make sure you can see the Front view and the Graph Editor at the same time.
First, we must adjust the **_rotation_grp_.RotateZ** curve to have **Linear** tangents. This will make it easier to adjust the **offset_grp.TY** predictably. Only one curve should use ease-in and easy-out, and that should be the **offset_grp.TranslateY** curve.
7c. Select _**rotation_grp**_ and in the **Graph Editor**, **select** the **RotateZ>Cube_MSR.TranslateZ** curve from the hierarchy list on the left.
7d. In the **Graph Editor**, go to **Tangents > Linear** to straighten the curve.
Now, we will focus on the **offset_grp.TranslateY > Cube_MSR.TranslateX** curve.
To edit the animation curve and see the results clearly, we will temporarily set keyframes on the Driver attribute so we do not have to deselect the _**offset_grp**_ when previewing the animation. So, set animation according to the following:
7e. Selelct _**Cube_MSR**_ and move the **Time Slider** to **1**. Make sure **TX=0**, and then in the **Channel Box**, select TranslateX and **right-click** to choose "**key selected**" from the context menu.
7f. Move the **Time Slider** to **60**. Change the value of **TX to 1**. Select **TranslateX**, **right-click,** and **key selected**.
When you drag the **Time Slider** between **1** and **60,** the cube should rotate on its edge but dip a bit in two places on either side of frame **30**, the halfway point, just like when you test the animation after setting the last SDK key. We will use the **Time Slider** to change the values of TX without deselecting the animation curve we want to adjust.
7g. Select _**offset_grp**_ in the **Outliner**.
7h. In the **Graph Editor**, select **Translate Y > Cube_MSR.Translate X** curve. There should be a bell-curve in the graph view. You may have put the mouse pointer over the graph view and type F to frame the curve
7i. **Select the** **keyframes** at **X=0**. You should see the tangents appear to either side.
7j. Go to **Curves > Weighted Tangents** to enable tangent weight. The tangents should get a bit larger.
7k. **Select a tangent** from under the curve, and pull it up to about **X=0.2**, **Y=0.15**, which should be a grid intersection. We will mirror this tangent on the other side once we get a good animation, so the grid is a good reference.
7l. **Pull the Time Slider between 1 and 30** to preview the beginning of the animation -- without having to deselect the **offset_grp** node. As you **scrub back and forth**, the corner/edge of the cube **should stay about the Y=0 axis** in the **Front view**. You can **adjust the tangent** if it does not. **Pull the tangent up and down slightly,** but not much right to left, The SDK curve allows for this subtle behavior of raising the **Cube_MSR** moves in X and also turns on the **rotation_grp** node underneath the selected node. You could leave the Time Slider at other frames where it dips, like 13, and adjust the tangent so that the cube is above the axis. Always scrub the Time Slider after you adjust the tangent to make sure all the other values work.
7m. Now s**elect the keyframe** at **X=1** and then the **inside tangent** under the curve. Move it to about **X=0.8, Y=0.15** to mirror the other tangent. **Scrub the Time Slider** between **30** and **60** to ensure the corner/edge stays on the **Y=0 axis** throughout the animation. You can **move the tangent slightly** to fine-tune the animation.
_The result should be a dome curve like this:_
![[07.CurveEditorTangent.png|*The final offset_grp.TranslateY curve should look like a dome with angled sides*]]
*The final offset_grp.TranslateY curve should look like a dome with angled sides*
We have one last adjustment to make this rig work along the X-axis beyond the 0 < X < 1 range.
#### **8. Make the Rig work along the entire X-axis**
8a. Select both the offset_grp and the rotation_grp nodes in the Outline.
8b. In the Graph Editor, select the **offset_grp.TranslateY>Cube_MSR.TranslateX** curve and **Ctrl + select** the r**otation_grp.RotateZ>Cube_MSR.TranslateX** curve.
8c. Click the middle mouse button in the graph window and **hit the F key** to **frame** the curve. Due to the high rotation value (90) and small translate value (1), you will only see the **RotateZ (blue) curve.**
8d. In Graph Editor > View, make sure that Infinity is checked. This shows values of the curves before and after the end keyframes.
8e. Drag over the RotateZ>Cube_MSR.TranslateX curve (blue) in the graph view to select it.
8f. Go to **Graph Editor > Curves > Pre Infinity > Cycle with Offset,** then **Curves > Post Infinity > Cycle with Offset**. You should see the curve continue off in a straight line. If you didn't make the curve Linear is a previous step (7D), choose **Tangents > Linear** with the curve selected now. Use "Cycle with Offset" on Rotation curves so that the cube continues to roll without snapping back to a previous rotation.
8g. **Select** the **offset_grp.TranslateY>Cube_MSR.TranslateX** curve in the hierarchy list of the **Graph Editor**. It should focus automatically.
8h. Drag over the curve to select it.
8i. Go to **Graph Editor > Curves > Pre Infinity > Cycle** and then **Curves > Post Infinity > Cycle.** You should see the curve repeating itself every whole number before 0 and after 1.
You can close the SDK window, the Graph Editor, and go to the Perspective View.
**Select the Control Circle** for the **Cube_MSR** in the Perspective View and hit the **Translate (W) Tool.**
You should be able to **pull the manipulator back and forth in X _for any distance_,** and the **cube should roll** without dipping below the ground!
**To clean up the rig**, delete the animation curve in **Cube_MSR.TX** by selecting the node, then selecting **Translate X** in the **Channel Box**, and right-click then select "**Break Connections**" from the context menu.
#### **9. Set up rotation along the Translate Z by following similar procedures as above.**
To move the _**Cube_MSR**_ along the **Z-axis**, we roll the _**rotation_grp**_ on the **X-axis.**
| | | |
|---|---|---|
|**_Cube_MSR_.TranslateZ**|**_rotation_grp_.RotateX**|**_offset_grp_.TranslateY**|
|0.0|0.0|0.0|
|0.5|-|0.207|
|1.0|90|0.0|
Create the Set Driven Key keyframes between **_Cube_MSR_.TranslateZ (TZ)** and **_offset_grp._RotateX (RX)** in the same way as we did with **TX** to **RZ** in step 6 above. When setting keys between **TZ** and _**offset_grp.TranslateY, which already has connections to TX**_, **Maya will automatically create** a "**blendWeighted"** node in between the similar **SDK animation** curves to **_offset_grp_.TranslateY** so that there should be no double translates when both TX and TZ are used or animated. Be sure to edit the SDK animation curves in the same way.
#### **10. A Bad Combination**
If you drag the **Cube_MSR** in the _**XZ plane,**_ you will notice that it does not roll correctly in some places. It appears to roll backward at times.
The combination of **Cube_MSR.TX** and **Cube_MSR.TZ** is not ideal, though. This _**simple rig**_ does not blend the two axes well because of **Gimble Lock** caused by **Rotation Order**. For any value of **Cube_MSR.TX** that is not **0** (where **rotation_grp.RZ=0**) or a **multiple of 4** (where r**otation_grp.**RZ is a **multiple of 360** or a full rotation), the value of **RX** when **TZ** is animated does not roll correctly!
If you are going to roll the cube along the **Z axis**, stay **within -1 < X < 1** for the best results!