A simple tutorial on using expressions with Paint Strokes.

Categories Nuke, TCL

Using TCL expressions in Nuke can help us to evaluate mathematical operations, as well as link values together to create something new. However, an often forgotten feature in Nuke is the ability to add expressions to RotoShapes and Paint strokes (which are also splines under the hood).

Nuke’s built-in “Tracker linking dialog” (pictured above), helps us to link individual vertices to various things in a Tracker node, and is doing so by automatically adding TCL expressions for us! However, what if we wanted to link things the other way around?

Every time you create a paint stroke, vertex points are created, and each one is assigned a unique index number. You can visualize these by first enabling vertex selection, and then enabling the label points option in the RotoPaint node’s Viewer toolbar, as shown below.

We can add an expression to any of these points by right-clicking and choosing “add expression”.

When the dialog box first opens, you can type “curve” to return the current value, as is the case with any other knob. However, if you simply type the name of the curve, “curve.3.main.x” in this example, you’ll get an error…

In order to access the coordinates of any vertex point on a spline, you must type the full path, like so:

As you can see, the Syntax is: <nameOfNode>.curves.<nameOfBrushStrokeOrSpline>.curve.<vertexNumber>.main.<axis>

As a quick example to demonstrate a few concepts: let’s create an animated Snake with nothing but expressions.

We’ll start by creating the head with a Roto node:

We should also create a transform node underneath, with the center-point automatically aligned to the center of the bbox. We can do that by adding an expression to the Transform node’s center knob:

Bounding boxes in Nuke have a single X and Y coordinate, as well as W (width) and H (height) amounts. We’re finding the bbox’s center point by first getting the input node’s bbox coordinates, and then adding half the width and height. No matter how our rotoshape changes, our center point will remain in the center!

Let’s give our snake a body with a RotoPaint node. I’m painting a rough stroke, reducing the number of vertices, and then adjusting the brush strokes hardness to match with the head.

Click GIF for full size.

Now let’s add some expressions to our paint stroke’s vertices. Firstly, we’ll link vertex 0 to the snake’s head by adding the Transform node’s center point and translate values.

It works! Secondly, we want the rest of the brush strokes vertices to move the same way, just offset in time.

For vertex 1, we’re returning vertex 0‘s coordinates from 6 frames earlier. We’re also offsetting the X value by -250, to move it to the left of the snake’s head.

We will do the same thing for vertex 2, except we need to double the values…

Go ahead and do this for every vertex in the paint stroke, incrementing the frame + x-position offset each time.

Now we can animate the snake’s head with our Transform node, and watch what happens! In the spirit of only using expressions, I’m using my bm_NoiseGen gizmo to generate a random animation curve, and am expression-linking the output to our Transform node’s Y translate knob.

One again, click the GIF to view full-res!

We can also make our snake’s head rotate so that it’s pointing in the direction it’s travelling, by using the derivative expression. This expression returns the slope, or speed of a curve on any given frame.

Lastly, our snake is just missing one thing: a name. I, for one, don’t want to be held responsible for naming our snake. After all, we want the computer to do all the work for us, right? I grabbed a big list of names starting with S from the internet, and keeping with the snake theme, I wrote a couple of lines of Python to get Nuke to choose a name for me:

import random

names = "Saban Sabas Sabastian Sabelo Saber Sabien Sabin Sabino Sacha Sachiel Sachin Sachio Sadaat Saddam Sadiri Sadler Saerys Sagan Sagar Sage Sahak Sai Said Sailor Saimir Saint Sajiv Sajiva Sakai Sakari Saku Sal Saladin Salahuddin Salam Salazar Saleem Salem Salim Salinger Salman Salmon Salomon Salomone Salvador Salvatore Sam Sam Beale Sama Samarth Sameeh Sami Samir Sammie Sammuel Sammy Samoset Sampo Sampson Samson Samu Samuel Samuele Samuli Samus Samvel Samwise Sanaullah Sancho Sandeep Sander Sanders Sanderson Sándor Sandro Sandy Sanford Sangeet Sani Sanjay Sanjeev Sanjeewa Sanjiv Sansao Sansleon Sansone Santana Santhosh Santiago Santino Santo Santonio Santos Sarantis Sarat Sarell Sargent Sargis Sargon Sarkis Sarp Sarpong Sascha Sasha Sasuke Satchel Sathish Satia Satin Saturn Saturnino Satwant Saul Saulo Saurabh Sava Saviero Savio Savion Savit Savvas Sawyer Saxby Saxon Saxton Sayers Saylor Scent Scevola Schroder Schroeder Schuler Schuyler Schylar Scipio Scooter Scorewin Scorpius Scot Scott Scottie Scotty Scout Scully Seabern Seager Seamus Sean Seanan Seanix Seath Seathrún Seaton Seattle Seaver Seb Sebastian Sebastiano Sebastião Sébastien Sebastion Sebi Seder Sedrick Seeger Seeley Seger Sehun Seiji Selassie Selby Selevan Selim Selleck Selmer Selwyn Sem Semaj Semih Senan Sendhelp Seneca Seoras Seph Sephiroth Sepp Septimus Serafin Serafino Seraph Seraphim Serge Sergei Sergio Serhat Serri Rafael Serry Rafael Servando Seryozha Seth Seton Sevan Sevastian Sevastyan Seven Severiano Severin Severn Severo Severus Sevin Seymarion Seymour Shad Shadden Shaddock Shade Shaden Shadi Shadley Shadow Shadrach Shae Shafer Shai Shaikh Shainen Shakespeare Shalev Shalom Shaman Shamar Shamus Shandy Shane Shannon Shanon Shantanu Shaokun Shaquille Sharif Sharnovon Shasta Shauftan Shaughnessy Shaun Shauni Shaw Shawinook Shawn Shay Shaydon Shayne Shea Shearjashub Shedrick Shelby Sheldon Shelton Shem Shemar Shep Shepard Shephard Shepherd Shepley Sheppard Sheraga Sheridan Sherlock Sherman Sherrill Sherwin Sherwood Shia Shiloh Shimon Shimshon Shinon Shipley Shirley Shiva Shivam Shiwoo Shlomo Shmuel Shohta Shola Sholom Sholto Shomari Shon Showles Shrikant Shukur Shulem Shye Shyloh Shylon Si Sian Siarl Siarles Siavash Sid Siddarth Siddharth Sidney Siegfried Sierra-117 Sierre Siger Sigge Sigismund Sigmund Sigurd Sigurdur Silas Siler Sillan Silvan Silvano Silvanus Silven Silver Silverio Silvestre Silviano Silvio Sim Simão Simba Simbiah Simcha Simen Simeon Simeus Simkha Simo Simon Simone Simpson Sinan Sinbad Sincere Sinclair Sindre Sindri Sinhue Sinjin Sinqua Sione Sipho Sir Sire Sirius Sisamila Sitka Sivan Sivert Sixten Sixto Sixtus Siyu Sjoerd Skandar Skate Skia Skip Skipper Skofi Sky Skye Skylar Skyler Slade Slaid Slane Slate Slater Slavko Slayden Slayton Sloan Slobodan Sly Smith Smokey Snowden Snyder Socrates Sodapop Soeren Sofian Sofiane Sofien Sogoro Sohan Söhnke Sohrab Sol Solace Solan Solanus Soleil Soloman Solomon Solon Somerled Somerset Sondre Sonnen Sonny Sony Sophian Sora Soren Sorin Sorley Sorrell Sorren Sotiris Soumil Soumyadeep Souta Spade Spalding Sparrow Spartacus Spearman Spellman Spence Spencer Spenser Spike SPinach Spirit Spiro Spiros Springer Spurgeon Spurrier Spyder Spyridon Squandro Squeag Squire St. John Stacey Stacy Stafford Stahley Stamm Stampley Stan Stanford Stanimir Stanislas Stanislaus Stanislav Stanislaw Stanley Stannis Stanton Star Stark Starlin Starsky Staton Stavrianos Stavros Steele Stefan Stefano Stefanos Stefen Steffan Stein Steinar Stejonte Stelios Stellan Sten Steno Stephan Stephanos Stephen Stephon Sterling Stetson Stevan Steve Steven Stevenson Stevie Stevieray Stewart Stian Stieg Stig Stijn Stiles Stirling Stjepan Stockholm Stockman Stockton Stohn Stojan Stokely Stone Stoney Storm Stormalong Strand Stratton Strauss Street Strider Striker Stringer Striver Strom Struan Stryker Stuart Sturt Stuyvesant Sudhir Sueban Sufjan Sufyan Suhail Suhas Sukhdeep Sukhvinder Sukhwinder Sukrajan Sulaiman Sulien Sullivan Sully Sulo Sultan Suman Sumit Summit Sumner Sun Sundara Sunil Sunjit Sunny Suraj Sutter Sutton Suvo Suzaku Svein Sveinn Sven Sverre Swain Swaine Sweeney Swinton Sy Sydney Syed Sykes Sylar Sylas Sylvain Sylvan Sylvana Sylver Sylvester Sylvestre Sylvio Symeon Synclair Szczepan Szebasztián Szymon Søren"

names_list = names.split()

print "Your snake's name is "+random.choice(names_list)

Running this code in Nuke’s script editor returned this:

Nice to meet you, Serge! May your handy expressions slither into everyone’s workflow.

You can download an example nuke script here (right-click > save link as).

While this is a silly little demo, there are numerous ways you can take this knowledge and apply it in your every day work. Perhaps you’re doing beauty work or costume fixes and need to track a texture to a specific RotoPaint vertex point? Maybe you need to expression-link a rotoshape from a Roto node to another rotoshape in a SplineWarp node to improve efficiency? Or maybe you just need a snake friend to keep you company during the COVID pandemic… The list is endless!