One of the fascinating pieces of working in TouchDesigner is the ability to use 3D tools to solve 2D problems. For the last seven months or so I’ve been working on Daniel Fine’s thesis project – Wonder Dome. Dome projection is a wild ride, and one of the many challenges we’ve encountered is thinking about how to place media on the dome without the time intensive process of pre-rendering all of the content specifically for this projection environment. To address some of these issues we started working with Los Angles based Vortex Immersion Media, their lead programmer is the TouchDesigner specialist Jeff Smith of Eve Vapor. Part of the wonderful opportunity we’ve had in working with Vortex is getting to take an early look at Jeff’s custom built Dome Mapping tool. Built exclusively in TouchDesigner it’s an incredibly powerful piece of software built to make the dome warping and blending process straightforward. The next step in the process for us was to consider how we were going to place content on the interior surface of the dome. The dome mapping tool that we’re using uses a square raster as an input, and can be visualized by looking at a polar array. If you’re at all interested in dome projection, start by looking at Paul Bourke’s site – the wealth of information here has proven to be invaluable to the Wonder Dome team as we’ve wrestled with dome projection challenges. This square image is beautiful mapped to the interior surface of the dome, making placing content a matter of considering where on the array you might want a piece of artwork to live.
There are a number of methods for addressing this challenge, and my instinct was to build a simple TouchDesigner network that would allow us to see, place, and manipulate media in real time while we were making the show. Here’s what my simple asset placement component looks like:
This component based approach makes it easy for the design and production team to see what something looks like in the dome in real time, and to place it quickly and easily. Additionally this component is built so that adding in animation for still assets is simple and straight forward.
Let’s start by taking a look at the network that drives this object, and cover the conceptual structure behind its operation.
In this network we have a series of sliders that are controlling some key aspects of the media – orientation along a circular path, distance from the center, and zoom. These sliders also pass out values to a display component to make it easy to take note of the values needed for programming animation.
We also have a render chain that’s doing a few interesting things. First we’re taking a piece of source media, and using that to texture a piece of geometry with the same aspect ratio as our source. Next we’re placing that rectangle in 3D space and locking its movement to a predefined circular pathway. Finally we’re rendering this from the perspective of a camera looking down on the object as though it were on a table.
Here I’m using a circle SOP to create a circle that will be the pathway that my Geo COMP will rotate around. Here I ended this network in a null so that if we needed to make any changes I wouldn’t have to change the export settings for this pathway.
You’ll also notice that we’re looking at the parameters for the circle where I’ve turned on the bulls-eye so we’re only seeing the parameters that I’ve changed. I’ve made this a small NURBS curve to give me a simple circle.
The next thing I want to think about is setting up a surface to be manipulated in 3D space. This could be a rectangle or a grid. I’m using a rectangle in this particular case, as I don’t need any fancy deformation to be applied to this object. In order to see anything made in 3D space we need to render those objects. The render process looks like a simple chain of component operators: a geo COMP, a camera COMP, a light COMP, and a render TOP. In order to render something in 3D space we need a camera (a perspective that we’re viewing the object from), a piece of geometry (something to render), and a light (something to illuminate the object).
We can see in my network below that I’ve used an in TOP so that I can feed this container from the parent portion of the network. I’ve also given this a default image so that I can always see something in my container. You might also notice that while I have a camera and a geo, I don’t have a light COMP. This is because I’m using a material type that doesn’t require any lighting. More about that in a moment. We can also see that my circle is being referenced by the Geo, and that the in TOP is also being referenced by the Geo. To better understand what’s happening here we need to dive into the Geo COMP.
Inside of the Geo COMP we can see a few interesting things at work. One thing you’ll notice is that I have a constant MAT and an info CHOP inside of this object. Both of these operators are referencing the in TOP in that’s in the parent network. My constant is referencing the in to establish what is going to be applied to the Geo as a material. My info CHOP gives me quick access to several of the attributes of my source file. Included in this list of attributes is the resolution of the source media. I can use this information to determine the aspect ratio of the source, and then make sure that my rectangle is sized to match. Using this process I don’t have to rely on a particular aspect ratio for my source material, I can pass this container any shape of rectangular image, and it will size itself appropriately.
Initially I just had three sliders that controlled the placement of my media in this environment. Then I started thinking about what I would really need during our technical rehearsals. It occurred to me that I would want the option to be able to place the media on the surface of the dome from a position other than behind the media server. To address this need I built a simple TouchOSC interface to replicate my three sliders. Next I captured that OSC information with TouchDesigner, and then passed that stream of floats into my container. From here I suddenly had to do some serious thinking about what I wanted this object to do. Ideally, I wanted to be able to control the container either form the media server, or from a remote access panel (TouchOSC). I also wanted the ability to record the position information that was being passed so I could use it later. This meant that I needed to think about how I was going to capture and recall the same information from three possible sources. To do this I first started by packaging my data with merge CHOPs. I also took this opportunity to rename my channels. For example, my OSC data read – osc_rot, osc_dist, osc_zoom; rotation, distance, and zoom sliders from my TouchOSC panel. I repeated this process for the sliders, and for the table that I was using. I also knew that I wanted to rename my stream, and pass it all to a null CHOP before exporting it across the network. To keep my network a little more tidy I used a base to encapsulate all of the patching and selecting, and switching that needed to happen for this algorithm to work properly.
Inside of the base COMP we can see that I’m taking my three in CHOPs selecting for the appropriate channel, passing this to a switch (so I can control what value is driving the rendering portion of my network) and then back out again. You may also notice that I’m passing the switch values to a null, and then exporting that do a opViewer TOP. The opViewer TOP creates a rendered image of the channel operator at work. Why would I do this? Well, I wanted a confidence monitor for my patch-bay. The base COMP allows you to assign a TOP to its display. Doing this meant that I could see into a portion of the base, without having to actually be inside of this component.
With all of the patching setup, I needed to build an interface that would control all of these changes. I also needed a way to capture the values coming out of TouchOSC, store them in a table, and then recall them later.
The solution here was to build a few buttons to drive this interface. To drive the witch CHOP in my base component, I used three buttons encapsulated inside of a container COMP and set to operate as radio buttons. I then used a panel CHOP in the container to export which button was currently being toggled into the on position. Next I added a button COMP to record the values set from TouchOSC. Using a Chop to DAT I was able to capture the float values streaming into my network, and I knew that what I wanted was to be able to copy a set of these values to a table. To do this I used a panel execute DAT. This class of DAT looks at the panel properties of a specified container (buttons and sliders also qualify here), and runs a script when the specified conditions in the DAT are met. This is the portion of the network that gave me the most headache. Understanding how these DATs work, and the best method of working with them took some experimentation. To trouble shoot this, I started by writing my script in a text DAT, and then running it manually. Once I had a script that was doing what I wanted, I then set to the task of better understanding the panel execute DAT. For those interested in Python scripting in TouchDesigner, here’s the simple method that I used:
m = op (“chopto1”)
n = op (“table1”)
Here the operator chopto1 is the DAT that is capturing the OSC stream. The operator table1 is an empty table that I want to copy values to, it’s the destination for my data. The Python method copy starts by specifying the destination, and then the source that you want to pull from.
Finally ready to work with the panel execute DAT, I discovered that all of my headaches were caused by misplacing the script. To get the DAT to operate properly I just had to make sure that my intended script was between the parameter specified, and the return call.
One last helpful hint / tip that I can offer from working on this component is how to specify the order of your buttons in a container. One handy feature in the container parameters page is your ability to have TouchDesigner automatically array your buttons rather than placing them yourself. The catch, how do you specify the order the buttons should appear in? If you look a the parameter page for the buttons themselves, you’ll notice that they have a smartly named parameter named “Alignment Order.” This, sets their alignment order in the parent control panel.
If I’ve learned nothing else, I have learned that sometimes it’s the simplest things that are the easiest to miss.