Why GLSL in TouchDesigner?
GLSL is an awesome tool to use in TouchDesigner. Period. It essentially allows you to create your own TOP operators which a lot of the same functionality and performance as the native TOPs you use in TouchDesigner everyday but it also gives you a ton of benefits. Ever wanted an Over TOP with 4 inputs that allowed you to transform and scale each input independently? You can make it yourself with GLSL in TouchDesigner! So let’s dive into some terms that make learning GLSL a lot easier, but before that…
What is GLSL?
GLSL is the OpenGL Shading Language. It is a programming language used on GPUs to generate graphics. It’s based on C-like syntax, so if you’ve used C or C++ before, it’ll look very familiar. If not, then you’ve got a bit of learning to do ahead of you! What can be a bit tricky about learning GLSL is the assumption that you come from some other field of programming or graphics and these terms would be familiar to you, which is not often the case in TouchDesigner. So now let’s dive into some terms!
Shader is the term we use when referring to GLSL code. It stems from the history and origins of GLSL. When GLSL was first made, much of it’s work was doing shading work on the GPU. It’s since evolved a ton and encompasses 2D graphics, 3D graphics, and even includes general computing of data sets in compute shaders. So you can read shader as code.
A uniform is a type of GLSL variable that we use to pass data from TouchDesigner to the shader. The important thing to know about a uniform is that it is uniform during a full execution of the shader. What is a full execution? A full execution of a shader encompasses all the times the shader runs. This may be confusing if you think about a shader running on the whole image or geometry at once. In reality, the main() loop of the shader is run once per unit of objects passed to it, and the completion of one full loop through all units is considered a full execution. So for example, if we pass 100 vertices to a vertex shader, the main() loop will run 100 times, each time on the next vertex, and when it’s finished running through all of them (a full execution) it starts the next full execution. A uniform value can’t change in the middle of a full execution, so if your value changes while the shader is running the main() loop on vertex 50 of 100, it will continue to use the original value until it’s finished all 100, then the uniform will update.
A scalar value is a type of math value that is usually a single real number. Scalars are usually also one-part values in that they are just a single integer or a single float and not part of some bigger data structures like arrays or vectors (more on those shortly). Something like x = 5 would make x a scalar value of 5. No need to dive to deep on this as long as you remember scalars are usually individual values and are integers or floats.
The term vector may bring fear to your heart depending on what you studied in school. Vectors have different definitions based on the field. A vector in physics is a very different thing than a vector in biology. In GLSL, a vector is what we call a multi-part values, and are usually filled with multiple scalars. So for example, a vector x could have three parts such as (1.0, 2.0, 5.0), and this would be referred to as a vec3, because it has 3 parts. The vectors you’ll be working with in GLSL will either be 2-part, 3-part, or 4-part, so vec2, vec3, and vec4. The different vectors can be used to represent whatever data you like, but a few common uses for vec4‘s are XYZW vectors for vector positions and normals, STPQ vectors for accessing texture co-ordinates, and RGBA vectors for access color values.
Arrays are a data type that is an ordered list of values. It’s similar to a Python list, if you’re familiar with those. They have square brackets around them, such as:
uniform float x
which is an array of floats called x with space for 10 floats in it. You can access these as you’d access any list in Python, with something like current_index = x which would access the element at the 6th position in the array (remember array’s are 0-indexed!). You’ll usually find arrays used for holding a bunch of values like floats or integers that don’t need to stay in pairs like vectors, but that doesn’t limit them to just that. You can make an array of most of the standard data types available in GLSL. So you could make an array of 10x vec3‘s if you wanted or needed.
A sampler is a data type in GLSL that represents a texture. There are many types of samplers that represent the different kinds of textures. You’ll see common samplers like sampler2D for 2D textures, sampler3D for 3D textures, samplerCube for cube map textures, and many more. Some of the built-in TouchDesigner variables that you’re given access to, such as sTD2DInputs is an array of sampler2D’s that TouchDesigner provides to save you some grief when trying to get your TOP inputs.
GLSL shaders in TouchDesigner can take advantage of multiple color buffers to do a lot of interesting things. But first, what is a color buffer? You can think of a color buffer as a “slate” that you draw to. Normally you just draw to your single “slate” and you use one color buffer as your output. Having multiple color buffers allows you to do interesting things like create multi-output TOPs where you can take a bunch of inputs, and route them to different color buffers based on some conditions, and then you can access each color buffer separately almost like a separate output using a Render Select TOP. Buffers are also really helpful when it comes to working with GPU based particle systems, because you can write out all the different data sets you have to different color buffers. For example, you can send all your positions to one color buffer, your particle colors to another, your rotation to yet another, and then your velocity to yet another, etc etc. Using this in combination with a Feedback TOP is absolutely necessary when creating a GPU particle simulations in TouchDesigner because then you can take all that data and feed it back into your shader to computer the next frames data using the last frames data. It’s almost magic!
Hopefully learning these terms thrown around freely in the GLSL world will make learning GLSL a bit easier for you. The best advice I can give when it comes to learning GLSL is start simple and build a solid foundation of terminologies and practices. You’ll find with that you can quickly build on your learning and learn in a way that makes it easy to also look through others peoples code, which is arguably the best way to learn advanced techniques. If you find yourself hungry to learn more GLSL after getting your teeth wet on these terminologies, you can take a deep dive on GLSL shaders in TouchDesigner with my new training Turn on God Mode in TouchDesigner with GLSL Shaders which is on sale for a limited time!