TouchDesigner | The Big Bad Ass Lister | Part 1/3

The Big Bad Ass Lister

This one is a different in part because we’ll be looking at something from the TouchDesigner pallet in depth, and also because Ivan from Derivative has very graciously volunteered to help demystify one of the coolest components that you’re not using enough in your projects – Lister. 

There’s a few things to keep in mind as you read through this post – there are two authors: Matthew and Ivan. They talked through what pieces would be great to share about lister, and then split up the examples and writing – that means that you’ll notice a slightly different voice in the writing, and you’ll get to see two different perspectives on how lister works. It’s also worth noting that Ivan is the developer at Derivative who has spent the most time working on lister, and the person who knows the Dark Dank Secrets of this component. There are also a handful of examples that go with everything written here, and we’re hoping that this post helps you find new and exciting ways to use lister in your projects!

Lister Basics

What’s a lister anyways? ! Lister is a shared component that both lives in the palette browser as its own comp, and is deeply integrated into the latest widgets UI kit Derivative has been cooking up. You can find both of these in the Palette browser on the on left hand side of the TouchDesigner UI, or by pulling up the palette browser with ctrl + l (win) / cmd + l (mac). 

Lister from the UI Folder in the Palette
Lister from Basic Widgets

Lister is actually built on top of the List COMP. The List COMP is a wildly powerful component, and replaces some of the pieces that you used to do with the Table COMP. If you haven’t used the Table COMP before, it’s amazing… but gets a little unwieldy pretty quickly. The Table COMP can be used to make radio buttons or other list style interfaces (the op create dialogue is a good example of the Table COMP in action), but it’s all set up with Table DATs, and can be a little hard to read / understand.

The list COMP

The List COMP does many the same things, but unlike the Table COMP, the List COMP has a deep set of python integrations with an internal callback DAT that allows you to think about UI building and operation from a Pythonic perspective rather than with Table DATs. That’s very exciting, but to make a truly reusable and extensible UI component you have to write a lot of Python… and this is where Lister comes into play. Lister is built on top of the List COMP and solves a large number of challenges you might typically encounter. It still has all the raw power of the List COMP, but gives you a huge headstart over trying to create a list UI element from the ground up.

So what can you do with Lister? Anything you might use a list for!

With that said, let’s actually look at how we can get started with lister, and some of the ways we can start to style and configure a lister for use in your projects.

Configuration

When it comes to working with lister, the config COMP is where you’ll actually find all of the most important secrets. The config COMP is docked below lister, and has a few easy to access helpers. On lister you’ll find a handful of pulse open parameters that will make configuration easier to set-up. 

Before we can really dig-in let’s set-up our workspace so we can see some of the interesting pieces of lister in action. To begin we’ll start with a Table DAT that holds a set of rows and columns that we want to turn into a UI element. 

We can start by creating a Table DAT that has two columns and a few rows. I’m going to give mine 6 rows, and name the columns “col1” and “col2”.

A Simple Table DAT

Let’s also add a lister from the palette – in this case we want the lister that’s in the UI Folder.

lister from the palette

To see just how fast lister can be to use, let’s start by just connecting our table DAT to our lister COMP:

lister out of the box

Right away we’ve already got a table up and running. This is a nice start, but we can do a little more to better configure our lister UI element. Some of the most important configuration pieces can be found in the docked base called “listerConfig”:

listerConfig

The listerConfig Base holds the sweet secrets for our lister – let’s take a closer look at how we might set a few configuration elements. Before we dive inside of the config, let’s first set a few of the parameters on lister.

On lister let’s first turn off the Auto-define Columns parameter:

Change pars on Lister COMP

Let’s also change the parameter “Input Table Has Headers” to True – since our input table has headers:

Table has header pars

Like it’s parameter name sake, Auto-define columns will attempt to set-up your lister based on the input table. For this example, we’re going to turn off that parameter, and then click on the “Edit Column Definitions” pulse parameter. This will open a floating window of the colDefine table DAT inside of the listerConfig:

colDefine Table

This table contains many of the configuration elements for our lister’s look. We can see that the table already has some elements set up. We’re going to replace these with our own values so we can see how lister will change. 

First let’s set the column name to be displayed as our header. Our starting table contains fruits in col1 and their quantities in col2 – So I want to change the column Row to be “Fruit” and “Quantity” respectively. 

Our lister’s data structure supports an internal column name that’s different from the display label – in some advanced cases you may want to use this. For now, let’s just set the columnLabel row to have a value of “*” which we can read as – “use the value from the column row.” 

Next let’s change the sourceData row to be the name of the input table’s columns that we’d like to use. My input table had columns called “col1” and “col2” – what’s important to consider here is that our lister’s columns don’t have to be arranged in the same order as our input table. This can be very helpful for more complex list UI elements. 

Let’s set our sourceDataMode to be “string” for both of our columns.

For now let’s style the width and stretch parameters for the column to be the same. Each column can have a width value of 100, and a stretch value of 0. At this point you should have a config table that looks something like this:

finished colDefine Table

Your lister should look something like this:

lister with Updated colDefine Table

Before we experiment with styling our lister anymore, let’s quickly take a look at some of the handy features that already exist. For starters we can see that there’s a hover highlight from our mouse position, and when we click on a row it highlights another color. 

lister with Highlighted rows

Lister also has two DAT outputs. The first lister DAT output is a table DAT version of exactly what’s in lister. The second output is the header columns from our lister, along with the selected row or rows from our lister:

lister output DATs

Let’s next look at how we might style our lister’s output a little more. 

In addition to the column definitions table, there are a host of additional operators we can change inside of our listerConfig DAT that are worth playing with. Let’s head back to our lister’s parameters, and this time click on the pulse parameter called “Edit Config COMP”.

Edit Config COMP

This will open a floating network window that looks into the listerConfig base:

listerConfig COMP

In addition to the column definitions table that we’ve been working with, there’s also a whole cluster of other TOPs. The first two columns of TOPs hold text TOPs that are used to define how our lister is styled. 

By changing these TOPs we in turn change the style for the lister’s columns. Let’s take a quick look at what we might change and the impact that will have on our lister. 

Let’s start on the text TOP called “header” on the font page. We can see that a number of the parameters are set to read-only – but there are a few on this page of parameters that we can change. Let’s start by turning the font x size up to 12 and turning on the “Bold” parameter.

changing the lister Header font size and bold attributes

Next let’s move to the Color page, and change the background color for our header. Here I’m going to make the Font Color bright white, change teh background color to a plumb, and set the bottom border of my TOP to be Border A. You’ll want to make sure that you also set the Border A Alpha parameter to 1 – it’s set to 0 by default. The result should look something like this:

changing the lister Header color attirbutes

Next if we look at our lister we’ll see those changes in action:

results from changes in listerConfig

This same idea also works with our rows – we just have to edit the first column of TOPs in our liserConfig base. I’m going to change my TOPs so that my lister uses this plumb / purple color palette. The only changes I have to make will be to the first column of TOPs:

styling lister rows

The resulting look for the whole lister is something like this:

styled lister

If you wanted to also change the row heights, you can achieve that change by adjusting the header TOP’s vertical resolution, and the master TOP’s vertical resolution. I’m going to change the header TOP’s resolution to 36, and the master TOP’s to 30. I’m also going to turn on row Striping on the lister COMP. The resulting changes look like this:

lister with height adjustments

This is just a start of the kind of customization we can achieve with lister. Now that we have a handle on some of the essential elements for manipulating the look of our lister, let’s take a deeper dive into customization and other lister features.

Auto Config and Copy Auto-Cols

For a simple input table this is a pretty straightforward approach, but sometimes we end up with a table that’s slightly more complicated. A good example of this might be when we’re converting SOP data to a table – this can be helpful in all sorts of situations, but setting up our lister for this many columns could take a  minute. Let’s set up a quick table that holds data converted from a sphere SOP.

We can start with a sphere SOP and change its primitive type to Polygon (this will start us off with fewer rows). Let’s add a null SOP (in case we want to add any other transformations), and then use a SOP to DAT to convert this in a table format. 

SOP to DAT

Similar to Houdnini’s geometry spreadsheet, this table holds all sorts of useful information about our SOP. This often works great for internal project uses, but if we want to create a styled interface for this data we would have to think about how to display this information. 

Geometry Spreadsheet

A lister here can be a great help. Let’s add a new lister form the palette to get started. Next we can connect our DAT to lister.

lister from Geometry Spreadsheet

Lister starts with the “Auto Define Cols” parameter on, which helps us get a starting point from our data right away. If, however, we want to style our lister a little more we’d need to repeat the steps we practiced earlier – going though and creating a column in our colDefine table for each column that we want to display. That’s all well and good, but it’d be oh so nice if there was a way to copy the current auto-config format into our colDefine table to give us a headstart. This gives us an opportunity to look at one of the handiest parameters on lister – Copy Auto-Cols to Config. 

For a table with this many columns it might be a little cumbersome to go through and set all of the colDeinfe elements manually – which makes this parameter incredibly helpful. So let’s go through an setup this lister so we can see the “Copy auto Cols To Config” in action. First, I want to turn on the parameter “Input Table Has Headers.” This SOP to DAT has header information already, and I want to make sure that the first row is treated as a header.

Input Table has Headers

Now we can use the pulse parameter called “Copy Auto Cols to Config.” A good trick to keep in mind here is that pulsing the “Recreate Auto-columns” parameter will adjust column widths to their contents when you press it. This would be helpful when you’re looking to have your columns auto size themselves. 

For this example we’re going to make some changes to our columns after we’ve captured them in the colDefine table. Let’s pulse the “Copy Auto Cols to Config” parameter. After we pulse this parameter, let’s turn off the “Auto-define Columns” parameter so we can make some changes to our lister.

Setting our Auto-define pars

Now let’s use the pulse parameter on lister to open our Edit Column Definitions table. We should see that lister has done all of the hard work of setting up our column definitions table, and now we can focus on just modifying the contents of this table.

The initial Auto-Defined columns

Now that we have the initial work done let’s go through and make some edits to our definitions. For starters, we might consider changing the labels for our columns. The names that come from our SOP to DAT are great when working in TouchDesigner, but aren’t always as descriptive as we might like for a user interface. We can update what’s displayed in the headers by making some changes to the first row of our colDefine DAT. I’m going to change a few names:

  • Index -> Point Index
  • P(0) -> Point.x
  • P(1) -> Point.y
  • P(2 -> Point.z
  • N(0) -> Normal.x
  • N(1) -> Normal.y
  • N(2) -> Normal.z

I’m also going to remove the point weight column, and the groups column. I also want the columns to stretch to fill the lister’s width, so let’s change the stretch row to be 1 for each of the columns. I want the Point Index values to be center justified instead of left justified, so we can change the justify cell in column 1 to be CENTER. Finally, I want the text in the first column to be Bold, so let’s change the fontBold cell to be 1. The resulting table should look like this:

Our adjusted auto defined cols

While we’re here practice using the font TOPs inside of the listerConfig COMP to style your lister. I’m going to adjust my row heights, and add a little color. After a few adjustments, my listerConfig looks like this:

listerConfig updates

And the final lister looks like this:

Geometry spreadsheet lister output

In our next installment we’re going to look at additional mechanics for working with tables, creating buttons in lister, using simple callback functions, and deeper styling with TOP paths. 

You can download all of the examples from this post here.

Happy programming… and lister-ing.

TouchDesigner | SOPs and Stamps

Usually when it comes to working with SOPs I tend to focus on thinking about instances instead of copies – but there are some really excellent use cases for the Copy SOP and one of the most powerful pieces of the copy stop is stamping your copies.

If your shaking your head wondering what Stamps are, you certainly aren’t alone – they’re one of the lesser used features of the Copy SOP (in my opinion) but one that has a wide range of use cases. Recently on the forum there was an excellent question about using the data from CHOPs to set the characteristics of SOPs – Multiple Circle SOPs from CHOP samples. One solution to that particular question is using the ability to Stamp copies, and with that in mind we can pull apart how stamping works.

Let’s start with a simple example. Let’s begin by connecting a Circle SOP to a Copy SOP.

A Circle SOP connected to a Copy SOP.

When we start there’s nothing particularly exciting that happens in this example. In order to make some changes we need to first change our number of copies:

Number of Copies set to 10

This still isn’t particularly interesting just yet, all of the copies of our original circle are all in the same place – all stacked on top of one another. Let’s translate our copies by some small number, and turn on our wireframe view of our geometry so we can better see what’s happening:

Copy Translate X par set to 2

The first copy is moved 2 units to the right, the second copy is moved 4 units to the right, the next 6, etc. This puts all of our copies neatly next to one another.

What if, however, we wanted to change the number of divisions in each copy… we might start with a triangle, and add one division for each copy. There’s no good way to do that out the gate – and it might be easy to think that you need to use a Script SOP to make this work.

Luckily, however, we can make this work with stamping. Let’s start by heading over to the Stamp Page of the Copy SOPs parameters:

The Stamp Page

We’re going to start by first turning on our Stamp inputs parameter. Next let’s figure out what we want to stamp each Copy with… if we want to change the number of divisions in a circle based on what Copy it is, we need a way to attach the copy index to that piece of geometry. Lucky of us there’s a handy python member that let’s us do just that. First let’s name our parameter index, and next we can use a simple python expression to attach our copyIndex to our geometry:

me.copyIndex

me.copyIndex in plain English means – “which copy of the geometry I am.” We can see that our copy index goes up to 9, and like all things programming, we should remember that our indices start at 0 – so our copy index are 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. What’s interesting about using Stamps is that we first Stamp our geometry, but then go back upstream in our network to use that stamp.

So to use our stamp we now need to go to our Circle SOP. The syntax of using Stamps looks like this:

fetchStamp(name, default)

We just used the name index when we stamped our copies, so we might first start with:

fetchStamp('index', 0)

Which means, find the Stamp called index and if you can’t find it, use the value 0. BUT, before we use this expression we need to remember that a circle needs a minimum of 3 divisions – less than 3 and we’ll just end up with a line. Let’s make sure we add 3 to our stamp value since our number of copies starts at 0:

fetchStamp('index', 0) + 3

What does that look like:

Copy Index to define the number of divisions

Okay… that’s pretty cool. But that’s really just the start of our journey here. Where this gets really interesting is if we start to use this new super power to look at other operators – after all we now have a way to index our copies.

Let’s now look at something a little more interesting.

We might instead think about using a Noise TOP to help describe how we’d like to displace the vertices of our copies. The idea in this example is that we’ll start by creating a grid – we’ll use a point SOP to displace our verticies, a tips SOP to fan our one side, and a copy SOP to create a spiral:

Our Point SOP is going to displace the vertices of our SOP by using the point Index to locate the x sample position, and the copyIndex to locate the y sample index:

The resulting Spiral has a noisy feeling that we can adjust with a combination of our noise TOP and copy SOP:

This isn’t a technique that’s well suited for changing in real-time, but it is a great way to think about creating fixed geometry that you might use for any number of environmental elements in your pieces.

TouchDesigner | Instancing Examples

Four years ago I started collecting examples on working with instances. What started as a rough collection of ideas has turned into a collection of over 40 different examples. In this revised set of techniques the format and presentation has also changed.Initially the user had to mouse around networks and look for readmes to learn about the examples. In this new version all examples can be explored through a purpose built UI:

Explorer screen shot

This new starting point allows the developer to quickly jump between examples without needing to open the TouchDesigner network. The interface is re-designed with three primary interaction regions in mind: The Navigator, The Readme, and The Liveview.

The Navigator

The Navigator organizes examples into sensible groupings. These high level containers can be collapsed by clicking on their heading. Each example also includes a button to jump to the example, or to open a TouchDesigner network view of the example. This allows you to both see the example rendered and see how it was built all at the same time.

The Navigator Pane

The Readme

The Readme pane has a short description of what you’re seeing. This set of documentation is intended to go along with each specific example and includes discussion about the particular techniques employed. Using the globe network icon on the Navigator will open the readme in your browser if you’d like a slightly larger window for reading through the documentation.

Right now there’s a small display bug on macOS that prevents the scroll bar from working correctly – that’s okay, you can always use the globe icon to open the readme in your default browser instead. You can follow along with the bug report if you’re a mac user here.

The Readme Pane

The Liveview

The Liveview let’s you see the output render from the network at a glance — making it easy to determine if this technique is one that you’d like to learn more about.

The Liveview Pane

Jump to Network

In addition to exploring the examples through the viewer, there’s also a button to open the network view for the example. This lets you jump immediately into the network and see how the instances were set-up.

The Explorer and an open network view

This project has been a labor of love to collect, organize, and compile materials for other passionate developers and educators. I’m hoping that enthusiasts, instructors, and creative developers alike will find this useful and interesting both as a tool and as a reference. 

Github: Clone the GitHub Repo

Happy Programming!


❤️ Thanks ❤️

…to Zoe Sandoval for their tireless work editing, play testing, and making all of these examples better. If it wasn’t for their handwork, and attention to detail this tool wouldn’t be nearly as complete or well constructed.

… to Ian Shelanskey for his passion and encouragement to keep making examples, and craft collect them into a single unified example.

… to Michael Walczyk for his mentorship, guidance, and constant enthusiasm. I would have been lost in the GLSL wilderness without Mike, and I always appreciate when I can ask him some crazy question about rendering and mathematics.

… to Elburz Sorkhabi and everyone at The Interactive Immersive HQ. Many of you were kind enough to test and look through these examples before posting this. The engagement and hunger for learning TouchDesigner in that community continues to inspire me, and is a reminder about why these kinds of examples are useful and important to share.

… to the Derivative Team for their toolkit that never stops being fun to use, and for their thoughtful feedback and support through building out this collection. From combing through the forum, to late night conversations with Greg and Ben I wouldn’t have gotten this far without them.

A Conversation with Robert Erdös

Recently I had the great honor of participating in Robert Erdös’s recent project TOP Players. Robert is currently working with Les Ateliers Nomad – you can see some of their work on Facebook. During the roller coaster of stay at home orders, and social distancing Robert’s been interviewing TouchDesigner developers and artists and has put together a casual format for having real conversations about work, artistry, and one’s ever evolving practice.

From Contraption:

The first series of “TOP Players” recordings is focused on revealing the people behind the TouchDesigner community video tutorials, people who showed great generosity and skill in helping others find their way. 

One of the primary goals of these conversations is for users to gain access to the most valuable resources that lead to their success in the interactive world.

The 2020 Lockdown has offered me a unique opportunity to reach these wonderful people and try to share a perspective on their distinctive personalities and amazing work skills.

https://contraption.pro/

It was a joy to talk with Robert, and I’d encourage you to both checkout the page he made for this talk, and to follow along with the conversations he’s having with other artists and developers. You can learn more about Robert by checking out his instagram, contraption.pro, or Les Ateliers Nomad.

Follow Robert on

YouTube
Instagram
Behance
Facebook
Les Ateliers Nomad on Facebook

A Conversation with Cocolab

Zoe and I were recently invited to participate in an open conversation about “Making the Best of our Current Situation with the Power of Creativity” hosted by Cocolab. Cocolab is a creative studio based out of Mexico City doing work of all scales – from intimate experiences, to enormous projection events they’ve done it all. Like all of us, they’re working to understand how to navigate this strange time, and have been hosting an ongoing series of talks that explore how we might understand and navigate this changing world. Our conversation was moderated by the ever charismatic and playful Elburz Sorkhabi.

You can see our talk at the facebook link below, and if you’re interested in listening in future conversations you should check out their Instagram feed for the next artist and date.

Learn more about MIR

TouchDesigner | The Object CHOP

The Object CHOP has long been one of the most challenging CHOPs for me to really wrap my head around. Following along with some conversations on the Facebook Help Group 1, it’s clear that I’m not the only one who has bumped their head against how to take advantage of this operator.

With that in mind, here are a few tricks and techniques that you might find helpful when working with the object CHOP.

Distance Between Many Objects Part 1

At first glance, it seems like the object CHOP can only perform calculations between single objects, but in fact you can use this operator to perform calculations between many objects provided that you format the input data correctly, and set up your object CHOP to account for multiple samples.

In a first example let’s say that we want to find the distance between several green spheres and a blue box:

First let’s collect our position information. I’ve used an object CHOP per sphere to find its distance, but you might also use a script CHOP, or a put positions in a table that you reference for the spheres, or drive them with custom parameters. How you position them doesn’t matter. What we need, however, is a single CHOP with three channels that hold the transformation information of those spheres. My trick in this network is to use object CHOPs to find their positions, then put them in sequence with a join CHOP:

Next we can use a single object CHOP that’s fed reference positions from this join CHOP, and a target Geometry COMP:

Other important pieces here are the start and end parameters on the channel page.

This is where we set how many samples the object CHOP will evaluate. This can be a bit confusing – here especially as the join CHOP has started at a sample index of 1 rather than 0. The devil is in the details, so it’s worth keeping a close eye for these kinds of oddities. Because of this we compensate in our start position by moving back one sample index.

Next make sure to set your object CHOP to output measurements, and distance. What you’ll then end up with is a single channel with a sample for each distance between your box and spheres. We can convert this to a table if we wanted to see the actual values:

Distance Between Many Objects Part 2

We may also want to measure distances between multiple blue boxes. Say, for example, that we had two different blue boxes and we wanted to know the distances of our spheres to both of those boxes?

Similar to our first exercise we’ll start by collecting all of the position information for our spheres. We also need position information for our boxes. In this case, however, we need to stretch a single sample to be 4 samples long – this is part of our data preparation step to ensure we correctly calculate distance.

Here a simple stretch CHOP has been used to make sure we have four samples of data for each box. Next we can join this data so all of our box position information is in a single set of CHOP channels:

Before moving on, we need to take a moment to adjust our sphere position data. In our first example we only collected the four positions… we need to set up the correct extend behavior for this series so that our CHOPs know what values to use when CHOPs of mismatched lengths are combined. We can use an extend CHOP set to cycle to do this trick:

Finally, we can then use an object CHOP to calculate the distance between our box and our spheres:

Distance Between Many Objects plus Bearing

If we also calculate the bearing between our boxes and spheres, we’ll end up with rotation information… what can we do with this? We could use this to calculate the correct rotation for a set of instances. For example:

Here each line is correctly rotated, scaled, and placed based on calculations from the object CHOP.

Bearing

You can also use the object CHOP to just calculate bearing – or rotation from one object to another. Here you can see how this might be used to rotate instances to sit flat on a sphere’s surface, or rotate an arrow to point towards an object:

Bearing and Distance

Or you might use the combination of bearing and distance to make some strange abstract art:

Collision

You can also use the object CHOP to simulate a kind of collision calculation where the distance you’re measuring can help you tell how close an object is to another and if they’re on top of one another:

GitHub

Clone the Repo to Follow Along

TouchDesigner | Reflection and Refraction

I can haz Reflections?! Refractions?

Zoe loves all things reflective and refractive and it was almost a year ago that they started looking into how to achieve compelling illusions of reflection and refraction. Then I went to Macau, then Chicago, then Zoe dove headlong into their thesis project… fast forward to 2019, and it was time for me to finally follow through on a long overdue promise to create some examples of reflection and refraction in TouchDesigner. It didn’t hurt that Zoe gently reminded me that it was time for more refractive rendering in life. Good places to start for these kinds of questions are to look at existing references in the world. 

Reflection 

Reflections are hard. In part because they often mean that we need to see the whole world – even the parts that our virtual camera can’t. We might know this intuitively, but the reach of this is easy to forget. When we point the camera in our smartphone at a mirror we see ourselves, the world behind us, above us, and and and. If we point a virtual camera at a virtual mirror we need the same things. That can be a wobbly bit to wrap your head around, and develop a better sense of this challenge I look a look at a reference book I picked up earlier this year – OpenGL 4 Shading Language Cookbook – Second Edition. This has a great chapter on reflection techniques, specifically generating them by using cube-maps. Cubemaps look like an unfolded box, and have a long history of use in computer graphics. 

One of the primary challenges of using cubemaps is that you need to also know the perspective of the object that’s reflective. In other words, cube maps can be very convincing as long as you move the camera, but not the reflective object. But what if we want the option to both move the camera, and the object? In this quick tutorial, we look at how we can use a cube map to create convincing reflections, as well as what steps we need to consider if want not only the camera to move, but the object itself. 


Refraction

The one and only Carlos Garcia (L05) has a great example posted on the TouchDesigner forum. This great example helps illustrate the part of what we’re after with this kind of work is the sleight of hand that hints at refraction, but isn’t necessarily true to the physics of light. Almost all realtime rendering tricks are somewhere between the Truth (with a capital T) of the world, and the truth (sneaky lower case t) of perception. We’ve all fallen for the perceptual tricks of optical illusions, and many times the real work of the digital alchemist is to fool observers into believing a half truth. Carlos’ example proves just that point, and helps us see that with a little tricksy use of the displacement TOP we can achieve a healthy bit of trickery. 

That’s an excellent start to our adventure, but we can dig-in a little more if we keep searching. Another post on the forum links over to an article on medium that showcases an approach for webGL that leverages the use of a UV map to “pre-compute” the direction of displacement of the light that passes through a transparent object. This is an interesting approach, and in fact there’s a middle ground between the webGL example and Carlos’ TOX that gives us some interesting results. 

In the following tutorial we can see how we remix these two ideas. The big picture perspective here is that we can leverage TouchDesigner’s real-time rendering engine to provide the same “pre-computed” asset that’s utilized in the webGL approach, and then use Carlos’ displacement TOP technique. We can also short-cut Carlos’ use of a rendering a second version of the object as a mask, and instead use a threshold TOP looking at our alpha channel to achieve the same effect. This isn’t a huge change, but it’s a bit faster in some implementations and saves us the wobbles that sometimes come with multiple render passes. Finally, a little post processing can help us achieve some more convincing effects that help sell our illusion as a true to the eye. 


Playlist


Individual Videos

TouchDesigner | Packing up a Tox for Distribution

If you’ve been following along with the workshop materials from the TD Summit 2019, there is one more exciting little tid-bit to dig-into. Thinking about how to create a reusable template for creating toxes is no small feat – especially if you want to include external Python libraries. I’ve been thinking about how to approach this challenge and mapped out a rough framework for approaching this challenge. You can see the working repo for this up on github here. During the last part of the workshop on External Python Libraries we covered this a little sneak peak of this technique, and to complete the workshop videos we added a section covering this approach.

The big picture ideas here are to standardize our approach to handling external libraries and automate their installation. This leans on the same concepts we explored in the workshop, and includes using things like a requirements file, using some automated installation scripts, and making sure the path to our project directory is included in our sys.path. The last major change is to convert our general scripts we wrote previously into an extension.

These days I tends to lean towards Extensions over Modules, though you could approach this challenge with Modules very similarly. This set of tutorials will walk us through taking what we created in the previous workshop videos and creating a portable tox we should be able to drag-and-drop into any project. Hopefully, what you take away from this example are some ideas about how to apply this technique and approach to other toxes that you build and share.

Happy Programming!


TouchDesigner | TD Summit 2019 | External Python Libraries

Overview

Hot off the presses, the workshop video from the 2019 TouchDesigner Summit workshop on External Python Libraries is up. You can follow along with all of the materials and outline from the workshop here – External Python Libraries.

If you just want to jump straight to the videos, you can find a playlist below. Happy Programming!


Python has more and more reach these days – from web services to internet of things objects, scientific and statistical analysis of data, what you can do with Python is ever expanding. While it’s possible to do all of this work from the ground up, it’s often easier (and faster) to use libraries that other people have published. TouchDesigner already comes with a few extra libraries included like OpenCV and Numpy. Once you have a handle on working with Python the world feels like it’s your oyster… but how you work with a magical little external library in TouchDesigner can be very tricksy. Worse yet, if you happen to get it working on your machine, making work on another can be infuriating. Over the course of this workshop we’ll take a look at what you can do to make this process as smooth and painless as possible, as well as some considerations and practices that will help you stay sane when you’re trouble shooting this wild Python roller coaster.