Category Archives: components

TouchDesigner | Previs for Moving Lights

I got an interesting question a few weeks ago about how to use tracking data to control moving lights. If you work with Touch long enough, at some point you’ll almost always end up wanting to drive some object in the real world with information derived from calculations in Touch. Where / how can you get started with that process?! It’s often temping to straight away jump into just driving the physical object. After all you know what you’re trying to do, and you might have a sense of how to get there – so what’s the harm?

That’s not a bad instinct, but I almost always like to start with some form of previs. You won’t always have access to all the equipment you want to use, and more importantly it’s often better to make sure you understand the problem you’re trying to solve before you start driving motors. The additional bonus here is that solid previs will create some opportunities for testing, and planning that you might not other wise have.

This post is going to look at:

  • Planning / mapping out some simple previs for using tracking data on some moving lights
  • Using the Object CHOP to calculate bearings for rotation information
  • Some simple use of custom parameters and bindings
  • Pattern matching for renaming
  • Using the CHOP export method Channel Name is Path:Parameter
Top level look at our setup

As a disclaimer, this is not a great approach for LOTS of lights – but is a great way to get started and make sure you understand what you’re trying to accomplish.

Workspace Setup

I like a workspace where it’s easy to see multiple perspectives at the same time. In this case I’d like to see the the network editor (your typical Touch workspace), the geometry viewer, and a rendered view. We can split our workspace with the icon that looks like a little down arrow in the upper right corner of the pane bar:

Split the network with the drop down menu in the upper right

In this case I’m going to split the workspace left/right, and then once top/bottom. In the pane on the top right I’m going to change the Pane Type to geometry.

Change the pane type to geometry

On the Bottom I’m going to change the pane type to Panel. If we’re working with container COMPs this can be very handy as it lets us see the panel for the container. If you’ve created an interface, that means you can also interact with your controls from here, without having to open a floating window.

A clean project set up like this looks like:

Our blank network

Our last step here is going to be adding a Container COMP to our network. We also need to rename it, and make sure our two new windows on the right correctly reference our net container. Our network bar is path based, so we just need to make sure both of them have the address: /project1/container_previs

Container COMP with our correct addresses

Custom Parameters

I want to control the elements of my previs container with a set of custom parameters. This will help me reduce the places I have to look for making changes, and helps save me the step of building a UI to control this visualization. I already happen to know what pieces I want to add here:

  • Transform controls for a tracked object
  • Transform Controls for 3 lights
  • Color Controls for 3 lights
  • Dimmer Controls for 3 lights
  • All of these should live on a page called “Settings”

In the end, our custom parameters should look like this:

Our Custom Parameters

I’m not going to go into huge detail here about how to set up the custom parameters here, but you can learn more about using custom parameters:

There is, however, one quick thing to point out. The addition of bindings in the Spring update comes along with a handy way to take quick advantage of them. We can use the drag and drop trick to add a set of custom parameters from another operator, and we can also auto assign all of our bindings in the process. Let’s take a look at that process.

Inside of /project1/conatiner_previs I’m going to add a light COMP. I’m going to first open the custom parameters dialog, and then add a page to my previs container called Settings. Next I’m going to grab the parameter Translate from my light comp, and drag it right onto the Parameter column in the customize dialogue. Here’s where the magic happens. Next I’ll select Bind New Par as Master from the drop-down, and ta-da – now your bindings are already set up for you:

Auto-assign our bindings by dragging and dropping

Scene Set-up

To set up this scene I’m going to use a few simple tricks. First I’m going to use a camera and a few pieces of geometry to get started. For something like the stage, I like a single top level Geo, with separate pieces nested inside. The benefit here is that if we scale or transform our top level Geo those changes will propagate to our nested elements:

Inside out stage

You’ll notice a separate wire-frame version of the stage inside of our stage – this is to give us some nice grid lines. geo2 is also transformed ever so slightly above geo as well, so we’ve got some nice clean rendering. Looking at the phong material for the primary stage, it’s got a slight gray emit color – so we can see it even when there’s no light on it’s surface.

We’ll also use a little trick with our camera. I’ve set my camera to look at a null COMP in our scene. This gives us some better handles for adjusting where our camera is looking without needing to manually set the rotation and transformation values. This is often a very helpful and easy way to get better camera controls by thinking spatially, rather than as transformation values.

Finally, I’m going to add another geo and change it to be a sphere. In this case I want some object to represent a moving object on my stage. I’m going to bind this object to my parent’s custom parameters that I already set-up for transformation. This means I can change the position of this geo either from the parent’s custom ops, or from the parameters on the geo.

Light Set-up

Depending on the order you’ve done this, you may have already created lights to set-up your custom parameters. If you haven’t done that yet, now’s a good time to add some lights to your scene. I’m going to use three for now. I’m also going to use a table to hold the transformation information for our lights. I’m using a table here because I’m thinking of a situation where my lights aren’t going to move – theatrical lights are usually transformationaly stable, and instead just rotate. If you’re lights are going to move in xyz position, this isn’t the most optimal set-up. Next I’m going to convert my table of positions to CHOP data. In my Dat to CHOP I want to make sure that I’m using a channel per column, and that my fist row and first column are marked as names.

Convert from DAT to CHOP

Next I’m going to use an object CHOP to find the position data for my target (that sphere we set-up in our scene). I’m going to plug my datto1 into that a second object CHOP, and my first object CHOP into the second input. Next I’ll make sure that I’m computing bearing, and on the channel page I want to change the output range to be start/end. I want to change that to samples instead of seconds, and then make sure that I start at sample 0 and end at sample 2.

Object CHOP -bearing calculations

So what’s this all about? What we’re doing with this second object CHOP is calculating the rotational values that will tell us the how to look at our target with each of our lights. We can then use this to set the rotation of our lights so they follow our target object. We could also do this with a chain of Math CHOPs… but having done it both ways, they’re almost computationally identical, and this you can do with fewer operators. So now we know the rotation values we need to set our on lights to make sure they’re looking at our target.

Now, we could certainly write some complex references for these values, but we can also learn a handy trick that I don’t see used too many places. Here we’re going to look at another CHOP export configuration. Before we get there, we need to flatten out our CHOP data. To do this we can use a shuffle CHOP set to split all samples:

Flatten out our CHOP data

This is swell, but if we don’t want to go through the process of exporting these one by one to our lights, what can we do? Well, it’s handy to know that there’s another way to use CHOP exports. There happens to be an export method called Channel Name is Path:Parameter. What that means is that if we change the name of our channel to be formatted so it’s the path to the operator followed by a colon and ending with the target parameter the exports will happen for us without any extra work.

Let’s take a quick detour to see how that works in isolation first. Let’s first add a constant CHOP, connected to a null CHOP. Finally let’s add another geo COMP to see how this works.

First steps to understanding another export method

Next let’s name some channels in our constant. I want to add the following:

  • geo1:tx
  • geo1:ty
  • geo1:tz

Next on my null CHOP I’m going to go the common page and change the export method to Channel Name is Path:Parameter. Finally, I’m going to turn on the export flag for the null CHOP, and ta-da. You’ve not exported values for tx, ty, and tz to your geo.

Exporting CHOPs with Path and Parameter

Okay, now if we go back to our flattened rotation info, we can imagine that if we just change the names of our channels we won’t have to do lots of dragging and dropping to get our exports sorted.

Let’s add a rename CHOP, and we can use some fancy pattern matching to do the renaming for us. In the From parameter we want r*[0-2]. What on earth does that mean? Well, any channel that starts with r, then has any character next, and then has a value of 0, 1, then 2. This happens sequentially, so we do all the r0s first, then the r1s and so on. That matters because our shuffled data is all rx values, then ry, and finally rz. We have to make a pattern matching schema that works works with that pattern.

Okay, so in our To parameter we want to use the pattern light[1-3]:r[xyz]. This means we’ll change our name space to be something like light1:rx. Again, this happens sequentially, so we’ll do all the 1s, then 2s, then 3s. What we end up with changes our original names like this:

Next we should be able to connect our null CHOP, set it to export as Channel Name is Path:Parameter, and we should be off to the races with all of our exports set up.

Our Container

By the end of all of this we should have a handy little container that’s set-up so we can change the position of a target geometry, and have our lights automatically follow it around our stage. If you’ve gotten stuck along the way, check the bottom of the page for a link to a repo where you can download just a tox of the finished Container, or a whole toe file with our workspace setup.

Our little follow spots

Other Considerations

What we haven’t talked about is getting your measurements and scaling right, or how to convert our rotational values into pan and tilt measurements, or how to convert that for controlling something with a protocol like DMX. Those are big concerns in their own right, but with a solid visualization you will at least have something to compare the real world against so you can start pulling apart those challenges.

Happy programming!


If you want to download this and look through the set-up you can find it on GitHub here.

TouchDesigner | Save External

a simple save external tox and text helper
clone or download from github

TouchDesigner Version

  • 099 2018.26750

OS Support

  • Windows 10
  • macOS

Summary

Working with git and TouchDesigner isn’t always an easy process, but it’s often an essential part of the process of tracking your work and collaborating with others. It also encourages you to begin thinking about how to make your projects and components more modular, portable, and reuseable. Those aren’t always easy practices to embrace, but they make a big difference in the amount of time you invest in future projects. It’s often hard to plan for the gig in six months when you’re worried about the gig on Friday – and we all have those sprints or last minute changes.

It’s also worth remember that no framework will ever be perfect – all of these things change and evolve over time, and that’s the very idea behind externalizing pieces of your project’s code-base. An assembly of concise individually maintainable tools is often more maintainable than rube golbergian contraption – and while it’s certainly less cool, it does make it easier to make deadlines.

So, what does all this have to do with saving external tox files? TOX files are the modules of TouchDesigner – they’re component operators that can be saved as individual files and dropped into any network. These custom operators are made out of other operators. In 099 they can be set to be private if you have a pro license – keeping prying eyes away from your work (if you’re worried about that).

That makes these components excellent candidates for externalization, but it takes a little extra work to keep them saved and sycned. In a perfect world we would use the same saving mechanism that’s employed to save our TOE file to also save any external file, or better yet, to ask us if we want to externalize a file. That, in fact, is the aim of this TOX.

Supported File Types

  • .tox
  • .py
  • .glsl
  • .json

In addition to externalizing tox files, it’s often helpful to also externalize any files that can be dffed in git – that is any files you can compare meaningfully. When it comes to your version control tool, this means that you can track the changes you or a team member have made from one commit to another. Being able to see what changed over time can help you determine why one version works and another does not. Practically speaking, this usually comes in the form of python files, glsl, or json files. This little tool supports the above file types, and goes a little further.

“What’s further mean?” You ask – and I’m so glad you did. Furhter means that if you change this file outside of touch – say in a text editor like Sublime or Visual Studio Code, this TOX module will watch to see if that file has changed, and if it has pulse reload the operator that’s referencing that file. Better still, if it’s an extension, the parent() operator will have its extensions reinitialized. There’s a little set-up and convention required there, but well worth it if you happen to use extension on a regular basis.

Parameters

base save and pars

Extension Flag

The Extension Flag is the tag you will add to any text DAT that you’re using as an extension. This ensures that we can easily identify which text DATs are being used as externally edited extensions, and reload both the contents of the DAT, as well reinitialize the extensions for the parent() operator. You can use any descriptor here that you like – I happen to think that something like EXT works well.

Log to Texport

If you want to track when and where your external files are being saved, or if you’re worried that something might be going wrong, you can turn on the Logtotextport parmeter to see the results of each save operation logged for easy view and tracking.

Default Color

The default color is set as a read-only parameter used to reset the network worksheet background color. This is used in conjunction with the following two parameters to provide visual indicators for when a save or load operation has happened.

BG Color

This is the color that the network background will flash when you externalize a TOX – it’s the visual indicator that your tox has been sucessfully saved.

Save Color

This is the color that the network background will flash save a text based file in an external editor – it’s the visual indicator that your file has been reloaded.

EXT Color

This is the color used to set the node color of your newly externalized tox – this can help ensure that at a glance you can tell which operators have been externalized.

Version

The version number for this tool.

Operation

reinitextensions.pulse()

If you want to use this in conjunction with extensions, you’ll need to follow a few conventions:

  • The text DAT that references an extension needs to be inside of the COMP uses it as an extension. For example – let’s say you have a text DAT that holds an extension called Project, this needs to live inside of the COMP that is using it as an extension.
  • The file you’re editing needs to end in .py. This might seem obvious, but it’s important that the file you’re editing is a python file. There are a number of checks that happen to make sure that we don’t just reinit COMPs willy nilly, and this is one of those safety measures.
  • The text DAT holding the extension needs to be tagged EXT – or whatever Extension Flag you’ve set in the parameters for the TOX. This makes sure that we don’t just reinit the extensions of our parent every-time any .py file is saved, but only if the that file belongs is being read by a textDAT that’s marked as being an extension.

ctrl+s

The way you’ll use this tox is just as if you were working as you might normally. Only, when you hit ctrl + s, if you’re inside of a COMP that hasn’t been saved externally, you’ll be asked if you want to externalize that module. If you select yes you’ll next be asked where you want to save that module. This module will then create a folder that has the same name as your component, and save the tox inside of that folder (the tox will also have the same name as the component). Better yet, this module will auto-populate the path to the external tox with the location you’ve selected. When you press ctrl + s again it will warn you that you’re about to over-write your tox. If you confirm that you want to replace your tox, it will save the updated version right where your previous tox was located.

Using a text editor

If you’re using a text editor for supported externalized files, than work as you normally might. When you save your file in your text editor Touch will automatically reload the file in Touch. If your text DAT is tagged EXT it will also reinit the extensions of the text DAT’s parent().

Suggested Workflow

Externalization Only

  • Create a directory for your project
  • Open TouchDesigner and save your .TOE file in your new directory this is an important step – saving your project makes sure that the member project.folder correct points to your .TOE file.
  • Drop the base_save.tox from touchdesigner-save-external\release into your network – I’d recommend doing this at the root of your project, or in a place in your project specifically designed to hold other tools. I like to create a base called tools where I keep all the things that I use for development, or that any machine might need (meaning when you’re thinking on a single .TOE file that’s configured based on a machine’s role)
  • Create a new component, and navigate inside of this new COMP.
  • Use ctrl + s to save your project as you might usually.
  • Notice that you’re now prompted to save your COMP externally – select Yes
  • Create a new folder in your project folder called td-modules (this is my suggestion, though you can use any name you like). Navigate into this folder and compete the save process.
  • Check finder (macOS) or explorer (windows) to see that in td-moduels you now have a new directory for your tox, and inside of that directory is your saved tox file.
  • Notice that the color of your tox has changed so you know that it’s externalized.
  • Continue to work and save. Note that when you use ctrl+s both your project and your tox are saved. If you happen to create an external .TOX inside of a tox that’s already externalized, you’ll be prompted to save both the parent() and the current COMP or just the current COMP.

Using Git

  • Create a new repo
  • Clone / Initialize your repo locally
  • Open TouchDesigner and save your .TOE file in your repo
  • Drop the base_save.tox from touchdesigner-save-external\release into your network – I’d recommend doing this at the root of your project, or in a place in your project specifically designed to hold other tools. I like to create a base called tools where I keep all the things that I use for development, or that any machine might need (meaning when you’re thinking on a single .TOE file that’s configured based on a machine’s role)
  • Create a new component, and navigate inside of this COMP.
  • Use ctrl + s to save your project as you might usually.
  • Notice that you’re now prompted to save your COMP externally – select Yes
  • Create a new folder in your project folder called td-modules (this is my suggestion, though you can use any name you like). Navigate into this folder and compete the save process.
  • Check finder (macOS) or explorer (windows) to see that in td-moduels you now have a new directory for your tox, and inside of that directory is your saved tox file.
  • Notice that the color of your tox has changed so you know that it’s externalized.
  • Continue to work and save. Note that when you use ctrl+s both your project and your tox are saved. If you happen to create an external .TOX inside of a tox that’s already externalized, you’ll be prompted to save both the parent() and the current COMP or just the current COMP.
  • Commit and push your work.

External Text based files

  • Start by following the instructions above to set up your project with the base_save.tox
  • Create a folder in your project for scripts or modules.
  • Start by following the instructions above to set up your project with the base_save.tox
  • Create a folder in your project for scripts or modules.
  • Add a new text DAT to your network, right click and save externally.
  • Set path to your external file in your text DAT and turn on the load on start parameter
  • Start by following the instructions above to set up your project with the base_save.tox
  • Create a folder in your project for scripts or modules.
  • Add a new text DAT to your network, right click and save externally.
  • Set path to your external file in your text DAT and turn on the load on start parameter.
  • Now open your text file in your external editor and work directly with your text file. When you save your file you should see the background of TouchDesigner flash, and the contents of your text DAT reload.

External Extensions

  • Start by following the instructions above to set up your project with the base_save.tox
  • Follow the instructions above for externalizing a python file – this time, make sure you save your .py file inside of your tox’s folder, and make sure that the text DAT is inside of the component that will use the extensions.
  • Tag your text DAT with EXT or whatever extension flag you’ve chosen.
  • Set up a simple extension.
  • Start by following the instructions above to set up your project with the base_save.tox
  • Follow the instructions above for externalizing a python file – this time, make sure you save your .py file inside of your tox’s folder, and make sure that the text DAT is inside of the component that will use the extensions.
  • Tag your text DAT with EXT or whatever extension flag you’ve chosen.
  • Set up a simple extension.
  • Now open your extension in your external editor and work directly with your .py file. When you save your file you should see the background of TouchDesigner flash, the contents of your text DAT reload, and your extension will be reinitialized.

Additional Considerations and Suggestions

At this point, you might have guess that this kind of approach works best in well structured projects. Some suggestions for organization and approach:

  • Think about Order and Structure – while I’ve structured projects lots of different ways, it’s worth finding a file structure that you like and sticking with it. That might be a deeply nested structure (watch out that’ll bite you if you get too deep – at least on windows), or it might be something more flat. Regardless, think about a structure and stay with it.
  • Make Small Simple Tools – to the best of your ability, try to make sure your modules are independent islands. That’s not always possible, but if you can think carefully about creating dependencies, you’ll be happier for it. Use custom parameters on your components to keep modules independent from one another. Use select operators, or In’s and Out’s to build connenctions.
  • Reuse that TOX – while this approach is fancy and fun, especially when working with git, it’s also about making your future self happier. Thank carefully about how you might make something re-usable and portable to another project. THe more you can think through how to make pieces that can easily move from project to project the more time you can spend on the fun stuff… not on the pieces that are fussy and take lots of time.

An Example Project

In the folder called sample_project open the Sample_project.toe to see how this might work.

Credits

Inspired by the work of:

Anton Heestand and Willy Nolan
I’ve had the great fortune of working with both of these find developers. I regularly use an externalization tool authored by these two developers, and this TOX is partially inspired by their work. Many thanks for a tool that keeps on working and makes using GIT with TouchDesigner something that’s reasonable.

Icons

Material Design Icons by Google