Recipe 49: RoboMoves
- Animating OpenGL objects
- Procedural animation technique
- Working with jit.path for smooth motion
When I made the Humanoid recipe, I quickly found myself looking for a way to set it to motion without having to crank on the trackpad. Having the ability to create a complex animation rig isn’t much fun unless you have a way to make it move. After digging around a little bit in the pile of new Jitter objects, I found my answer in the jit.path object. Since the animation is represented by a Jitter matrix, all the usual techniques for generating, managing, and storing a matrix can be employed. Being able to work with animation loops in this way provides a good mix of randomness with repetition and control.
First, let’s look at the setup inside the “robot” subpatch. The structure of this patch should be familiar to you if you’ve looked at the Humanoid recipe. There is a hierarchy of jit.anim.node objects that provides for all of the articulated joints of our robot. If you haven’t taken time to play with the relationship between @anchor,@position, and @rotatexyz, go ahead and drop in some attrui objects to see how that works.
You might notice the jit.gl.node object at the top of this subpatch. This is there to make it so that we don’t have to type in a context name for each of the GL objects in the subpatch. Using OpenGL implicit contexts in Max 6 isn’t just a good way to save typing, but also makes it easier to reuse patches in other places without having to retype objects.
Okay, now let’s look at jit.path. We’re feeding it the output jit.noise, which is outputting a 4-plane float32 matrix. Before it gets sent to jit.path, the jit.submatrix and jit.concat objects are used to copy the first cell to the right side of the matrix. This will make the looping of our animation more seamless. To loop the animation, we use a counter to send “eval” messages.
It’s worth mentioning that the the output of jit.path is just a list of interpolated numbers. In this case we are using them to drive rotation values for jit.anim.node objects, but these interpolated values could really be used for anything. To get nice fluid motion, we’ve set the interpolation mode to “spline” which interprets the input matrix as handles on a bezier curve
In addition to the random loops created by jit.noise, this patch also stores each loop matrix in jit.matrixset. This allows us to recall previous loops. The point of doing this is to add some amount of repetition and memory to an otherwise completely random setup. Using the ideas set forth in this recipe, along with a more advanced way to generate the animation values, one could make a fairly compelling procedural animation system.