So far if you’ve been following the series, we covered an approaching to thinking about your projects as systems instead of linear experiences and then we covered how to dive deeper in and start examining and thinking deeply about the signals in your project. For the final part of this series, I’m going to show you a few practical examples of how you can achieve this inside your TouchDesigner project and at the end there’s a few nice little project files you can take away as examples. Time to dive in!
Example 1: Simple Sample
In the most basic example, let’s take a look at the simplest thing you’d want to attach to a timeline or Animation COMP. Let’s take an example of the following:
- 20 frames at value of 0
- Linear ramp up to value of 1 for 30 frames
- Hold value of 1 for 30 frames
- Ease-in ramp down to -1 for 100 frames
This example has a number of elements to it that cover A LOT of animation needs including ramping up and down values with different curves, holding values, and more importantly doing this all to specific frame numbers.
Now your first thought might be to bust open the ol’ Animation COMP and keyframe this bad boy. Wrong! Let’s build this natively with some CHOPs and I bet you’ll be impressed how easy it is and how flexible it will become.
Hold of 0
First step is making 20 frames of value of 0. Easy. We’ll make a Constant CHOP for that. Most people think of Constant CHOP for only single-sample values, but it’s great for creating these kinds of holds. The trick is to turn off the Single Sample parameter on the Channel page of the parameters. Once we do this we’ll change the units for the Start and End parameters to be Samples instead of Seconds, and then we’ll set them to 0 and 19 (so that we have 20 samples).
This will give us the first thing we need, which is a 20 frame hold at value of 0.
Linear Ramp to 1
To make our linear ramp we can use our good friend (maybe new friend for you!) of Pattern CHOP. This CHOP lets us create waves of different types and set quite a lot of their attributes quickly. So we’ll make a Pattern CHOP, switch the Type parameter to Ramp, set the Length parameter to 30, then we’ll set the Extend Left and Extend Right on the Channel page to Hold. This is just a safety so that at no point does our 0-1 ramp segment ever loop when we join it with other CHOPs later.
Hold 1 for 30 frames
We already made one hold, so this is a rinse and repeat! Except the only differences this time are that after we setup our channel length to be 0 to 29 (30 frames including 0!), we will go back to 0 page of the parameters and change the value of the first channel to 1.
Ease-in to -1
So far so good! Feels easy, right? What about an ease-in ramp to -1? Yikes, sounds hard. But, it’s not too bad if you know where to look. Firstly it’s important to know that what we’re about to do is apply some easing algorithms, because frankly I find them generally easier to work with than trying to do everything with a bunch of native operators. So for this example, we wanted to just a regular ease-in ramp. I went on DuckDuckGo and looked up “easing curve math python” and found this in the top hits which I leave for your reference since it’s a great site with easy to grab math. I scroll down and find the function named CubicEaseIn() and look at the math for it which is just p * p * p. Without going too deep on easing (I suggest you read work by Robert Penner on that), in this case p is our value at a certain time. We don’t need to worry about time too much, because of how we’re going to do this in TouchDesigner.
I’m going to start by taking another Pattern CHOP, doing the same things we did previously to make a linear ramp, except that I’ll set the Length parameter to 100. The trick is to now pass the output of that to an Expression CHOP where we can enter that math formula above on the Expr page of the parameters. You’ll see me.inputVal is already entered when we click on the Expression 0 parameter. That’s a useful starting place because we know that a Cubic ease in function is just p * p * p, where p is our value, so we can just do me.inputVal * me.inputVal * me.inputVal. It sounds simple, because it is, don’t over-complicate it in your head! You’ll see once you enter that expression you’ll have a pretty ease-in curve. Final thing we have to do to this curve is use a Math CHOP to scale it from 0 to 1 to a the new range of 1 to -1.
Now that we have all the pieces of amazingly artistic keyframe animation channel together, we need to slam them back to back and make a single channel out of them. We can do this easily with a Join CHOP. I click on my first operator, then shift + click on each of the next ones, and then I drag the first output to the join which will automatically connect all of them in the correct order. Voila!
We’re almost done! We have our ready to go channel, we just need to figure out a way to “play it back” because we can’t really work with this multi-sample channel easily. This is where one of my favourite operators comes in: Lookup CHOP. Lookup CHOP allows you to scan through multi-sample data using an index channel. So in this case, we’ll plug our animation into the second input of the Lookup CHOP, then we’ll connect a Timer CHOP to the first input. We’ll set the Timer CHOP Length parameter to 180 samples, since that’s all of our section lengths added together. Then we’ll turn on Cycle, turn off Cycle Limit, go to the Outputs page and turn off Done and Ready. Finally we can plug it into out Lookup CHOP first input, hit Start on the Timer CHOP and see the magic happen.
If you don’t want the animation to loop, just turn off the Cycle parameter on the Timer CHOP and you can pulse the start button to play it through.
Ok so let’s quickly recap this example. We figured out what our animation is step-by-step, used the appropriate CHOPs to recreate each part of the animation, join them together as a single channel, then scrub through it with a Timer CHOP and Lookup CHOP. While it may feel like that took a while, in reality it’s pretty quick to bang through these. The amazing part of these is that not only are they quick and easy, but they’re really flexible. Let’s say you needed to:
- Change the easing math: you could just go to that site, grab some new math like Quadratic Ease Out which is just -(p * (p – 2)) so we’d just enter -(me.inputVal * (me.inputVal – 2)) and have a whole new curve.
- Update the timings of the sections: This is super easy, no need to fuss around with keyframe handles or anything, you can just run through each of the operators and change their Length parameters with ease
- Programmatically change things: This is where this shines, let’s say you want to insert some randomness into the mix or randomly change some curves. Whereas this would be a total pain in the butt to do if it was keyframed or in an Animation COMP, this is super easy to just randomize some of the simple parameters that define the parts of data. No fuss, no mess.
On top of that, this is simply not connected to any “timeline” or similar. You have Timer CHOPs that you can control together or separately. Things can run in parallel or completely independently. If you need to jump through states you just reset different Timer CHOPs without need to worry about “where in the timeline you are.” There are so many powerful benefits to working this way, I can’t even begin to mention them all (and think I mentioned a bunch on the 2 previous posts).
Taking it further & Download
So we did a simple example. Cool. But what about more complex animations? You might be surprised but this dinky little example covers 90% of all animation types of data you’ll need to create in TouchDesigner. Need more channels to control other things? Make a separate operator chain with it’s own Join CHOP and Lookup CHOP. Need more complex curves? You can learn more about easing (because it is very documented online) and then start using some more interesting math that you find online to create some really cool curves. There are very few things I haven’t been able to re-animate in TouchDesigner using the few steps I mentioned above. So while it’s a simple example, it covers the fundamentals you can use to incrementally build more and more complex animation signals natively in TouchDesigner. You can download the example I built below:
Example 2: Crazy custom animators gone wild
I’d be remiss if I didn’t mention the other 10% of times where I couldn’t/didn’t want to re-create the animation signals in TouchDesigner. There are 2 instances where I skip this party. One is when there is a separate animation team doing A LOT of iteration on their side. For example, I was working with some animators that were match moving some objects in After Effects and kept changing things and giving me updated keyframes. There was so much data each revision it would have just been a plain old waste of time for me to constantly have to update my data. In that case, I made an importing tool that takes After Effects keyframe data and creates an Animation COMP out of it (you can get it if you’re a Learn Elburz.io TouchDesigner HQ member).
The other few times that I’ve skipped making these signals in TouchDesigner is in those few instances where the animations really really REALLY wanted totally minute levels of control over the animation. They didn’t just want the quadratic ease in, but they would spend a few hours nudging the little handles back and forth until it was justtttttttttttttttttttt right in After Effects. At this point it was not worth my time to recreate it then have to re-edit it with minute details if they decide they want to change something. In these cases, where the designers might be incredibly picky/involved, I did the same as above and used my own After Effects keyframe tool to import the data.
Alternatively if you don’t have that tool, you can look up “how to export After Effects keyframes as text file” and build an importer with some Python scripts. To get those keyframes, you need to highlight all the keyframes, hit Ctrl + C, open a text editor, then hit Ctrl + V. This will dump the keyframe data into the text file that you can parse further.
Or even further alternatives, you can just get the animators to render lots of layers with alpha that you can playback based on certain conditions.
I hope this small series of posts have been helpful in showing you the optimal way of working in TouchDesigner. I know a lot of folks come to TouchDesigner from a background that uses a lot of animation keyframed data locked to a timeline and that just leads you down a world of misery. Thinking about your projects as systems, then drilling down on the signals, then building out those signals similar to the way we built the example here will give you unlimited flexibility in your projects.