{"id":365,"date":"2023-12-06T17:16:41","date_gmt":"2023-12-06T17:16:41","guid":{"rendered":"https:\/\/sachadjordjevic.com\/?page_id=365"},"modified":"2023-12-06T22:08:47","modified_gmt":"2023-12-06T22:08:47","slug":"nuke-python-tcl-scripts-tricks","status":"publish","type":"page","link":"https:\/\/sachadjordjevic.com\/index.php\/nuke-python-tcl-scripts-tricks\/","title":{"rendered":"NUKE: Python &amp; TCL Scripts &amp; Tricks"},"content":{"rendered":"\n<blockquote class=\"wp-block-quote has-base-color has-accent-background-color has-text-color has-background has-link-color wp-elements-c37c0f8a142cb1b9f7b40f011ac2ff5d is-layout-flow wp-block-quote-is-layout-flow\" style=\"font-style:normal;font-weight:200\">\n<p class=\"has-accent-background-color has-background has-small-font-size\" style=\"padding-top:var(--wp--preset--spacing--20);padding-right:var(--wp--preset--spacing--30);padding-bottom:var(--wp--preset--spacing--20);padding-left:var(--wp--preset--spacing--30)\">Foundry&#8217;s Nuke is a premium compositing software with a rich back-end and studio level implementations that can be manipulated and enhanced using python and TCL. This is a compilation of snippets and scripts I&#8217;ve used one time or another over the past years to accomplish specific tasks, and not all of it has been recently tested.<br><br>Note that a lot of these were written <em>before<\/em> Nuke had a lot of tools that it has today. Therefore use the code below carefully, and if you find any issues, something not working &#8211; it could just be a new version of Nuke or there just may be a much better way to do it nowadays.  And remember &#8211; <em>with great power comes great responsibility<\/em>.<\/p>\n<\/blockquote>\n\n\n\n<p><strong>TCL &amp; EXPRESSIONS<\/strong><\/p>\n\n\n\n<p class=\"has-text-align-left\"><strong>Folder where the script is saved:<\/strong> [file root]<br><strong>Root dir:<\/strong> [file dirname [knob [topnode].file]]<br><strong>File name:<\/strong> [file tail [knob [topnode].file]]<br><strong>File extension:<\/strong> [file extension [knob [topnode].file]]<br><strong>Text node shot name and frame # TCL expression:<\/strong><br>[lrange [split [file tail [knob [topnode].file]] _ ] 0 0 ]&nbsp;:: frame [frame]<br><strong>Convert one format to another, and save it somewhere relative to the path:<\/strong><br>[file dirname [knob [topnode].file]]\/..\/..\/jpg\/3200&#215;1800\/[lrange [split [file tail [knob [topnode].file]] . ] 0 0].%04d.jpg<br><\/p>\n\n\n\n<p class=\"has-text-align-left\"><strong>Autowrite based on where your script is<\/strong>:<\/p>\n\n\n\n<p>Providing you prefer your structure to look like this:<\/p>\n\n\n\n<p>[project name]\/[sequences]\/[shot]\/nuke\/scripts<br>[project name]\/[sequences]\/[shot]\/nuke\/renders\/exr<br>[project name]\/[sequences]\/[shot]\/nuke\/renders\/mov<br>&#8230;<\/p>\n\n\n\n<p><strong>step 1:<\/strong> go to your settings and click the Script Directory button to set global relative path to it<\/p>\n\n\n\n<p><strong>step 2:<\/strong> put this in your render node for EXRs. Make sure you check the box to create directories on render. I&#8217;m using four numbers padding, feel free to change that to what you need:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>..\/renders\/&#91;file rootname &#91;file tail &#91;value root.name] ] ]\/exr\/&#91;file rootname &#91;file tail &#91;value root.name] ] ].%04d.exr<\/code><\/pre>\n\n\n\n<p><br><strong>Random Expression:<br><\/strong>main idea: min+random(frame)*(max-min)<br>example (random value between 100 &amp; 300): rint(100+random(frame)*(300-100))<\/p>\n\n\n\n<p><strong>Setting up write nodes for specific frame range &#8211; different approaches:<br><\/strong>Example 1: on the write node add expression:&nbsp;!inrange(frame, first_frame, last_frame)<br>Example 2: on the disable node add expression: ((frame &lt; Read1.first)?true:false)||((frame &gt; Read1.last)?true:false)<\/p>\n\n\n\n<p><strong>Using the Expression node to clamp specific values or generate mattes:<br><\/strong>Clamping Values: On each color channel of the expression node: Color &lt;High Value? Color:New Value Example: r&lt;1.1?r:.9<br>Creating Mattes: On each color channel: Color &gt;High Value&nbsp;? Color&nbsp;:0 Example: r&gt;1.1?r:0<br>Place an additional expression node below the first expression and under the alpha add r+g+b to consolidate the result into one matte<\/p>\n\n\n\n<p><strong>How to write tcl code inside a python script:<\/strong><br>nuke.tcl(&#8216;tcl expression here&#8217;)<\/p>\n\n\n\n<p><em>For example:<br><\/em>nuke.tcl(&#8216;file dirname [knob root.name]&#8217;)<\/p>\n\n\n\n<p><strong>Expression to generate an HD resolution stmap with a single expression node:<\/strong><br>expression 1 (turn off green and blue): (x%1920)\/1920<br>expression 2 (turn off red and blue): (y%1080)\/1080<\/p>\n\n\n\n<p><strong>PYTHON SCRIPTS INDEX<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Check write nodes and create folders if none found<\/li>\n\n\n\n<li>Attach a Furnace DeNoise node to selected nodes<\/li>\n\n\n\n<li>Attach a Write node to selected Read nodes, and embed with expression on disable<\/li>\n\n\n\n<li>Change single or muliple parameters in all selected nodes<\/li>\n\n\n\n<li>Create Write nodes connected with all selected read nodes with correct file name<\/li>\n\n\n\n<li>Disable &#8220;Postage Stamps&#8221; on all nodes<\/li>\n\n\n\n<li>Unhide all nodes&#8217; inputs (if received a script that hides them)<\/li>\n\n\n\n<li>Change the first frame to a certain number &#8211; enhanced version should change the last frame to that number + frame range<\/li>\n\n\n\n<li>Print a selected nodes&#8217; methods<\/li>\n\n\n\n<li>Find all the Timeoffset nodes in a group (called group2) and change value of offset based on its position in an array of found time offsets<\/li>\n\n\n\n<li>Remove all animation from selected nodes<\/li>\n\n\n\n<li>Add keyframes &#8211; Animate mix parameter<\/li>\n\n\n\n<li>Halve the color value of all constant nodes in a script<\/li>\n\n\n\n<li>Find all the transform Nodes in the script and if their input is a crop set scale value X2<\/li>\n\n\n\n<li>Set all gain values of CC nodes X2<\/li>\n\n\n\n<li>Change font size of all Write nodes in the script<\/li>\n\n\n\n<li>Create 20 constants with incrementing color values<\/li>\n\n\n\n<li>Set up write nodes for specific frame range<\/li>\n\n\n\n<li>Use Python to define your own hotkeys<\/li>\n\n\n\n<li>Select all class nodes (class Read in this case)<\/li>\n\n\n\n<li>Write DPX, create Slate and WriteJPG generator &#8211; written for Method Pipeline<\/li>\n\n\n\n<li>Camera with aim TCL<\/li>\n\n\n\n<li>Add a text node with the value from the input node<\/li>\n\n\n\n<li>Multiple Read\/Write nodes tweaker<\/li>\n\n\n\n<li>Import mocha track and create a normal and reversed corner pin out of it<\/li>\n\n\n\n<li>Control \/ smooth curves with a multiplier<\/li>\n\n\n\n<li>Open all property bins of all selected nodes<\/li>\n\n\n\n<li>Write all the read nodes file name in the script editor<\/li>\n\n\n\n<li>Add a text node with the value from the input node<\/li>\n<\/ol>\n\n\n\n<p><strong>1. Check write nodes and create folders if none found<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># script that checks if write nodes have folders\n# and creates them if not\n\nimport os\nimport sys\nimport os.path\nfrom os import system\nfrom os import makedirs\nimport nuke\n\nthis_filename = sys._getframe().f_code.co_filename\nprint('Loading '+this_filename)\n\ndef write_mkdir(nodes = ''):\n    'Make directories from write nodes'\n\n    n = nuke.allNodes()\n\n    for i in n:\n        if i.Class() == \"Write\":\n            i.knob(\"selected\").setValue(True)\n\n    snodes = nuke.selectedNodes()\n    if len(snodes) == 0:\n        nuke.message('ERROR: No Write nodes to work on')\n        return\n\n    for i in snodes:\n        _class = i.Class()\n        if _class == \"Write\":\n            # use this to get only the filename\n            path = nuke.filename(i)\n            if empty continue\n            if path is None:\n                continue\n            # Get Directory Structure with out file name\n            dirPath = os.path.dirname(path)\n            if os.path.isdir (dirPath):\n               nuke.message('Directory already exists:\\n%s'&nbsp;% (dirPath))\n                continue\n            if os.path.isfile (dirPath):\n                # The folder exists as a file\n                msg = \"The directory:\\n%s\\nexists as a file. Delete it and create folder?\"&nbsp;% (dirPath)\n                delete_existing_file = nuke.ask(msg)\n                if (delete_existing_file):\n                    os.unlink (dirPath)\n                else:\n                    return\n            # Create directory\n            try:\n                makedirs(dirPath,0775)\n                nuke.message('Created:\\n%s'&nbsp;% (dirPath))\n            except:\n                if nuke.ask('Create Path: '+ dirPath):\n                    makedirs(dirPath,0775)\n             continue\n                else:\n                    return\n        else:\n            nuke.message('ERROR: Skipping non-Write node.')\n            continue\n\n    return<\/pre>\n\n\n\n<p><strong>2. Attach a Furnace DeNoise node to selected nodes<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># script that attaches a Furnace DeNoise node\n# with default values to selected nodes,\n# and then adds a write node to that Furnace DeNoise node\n\nsn = nuke.selectedNodes()\n\nfor n in sn:\n\n    first = n.firstFrame()\n    last = n.lastFrame()\n    a = n['file'].value()\n    b = n['name'].value()\n    c = a.replace('.%04d.dpx','_denoise.%04d.exr')\n    d = \"DeNoise_\"+b\n\n    dn=nuke.nodes.F_DeNoise (name=d, plateSize=\"Pal Or NTSC\")\n    dn.setInput(0,n)\n    nuke.toNode(d).knob('selected').setValue(True)\n\n    wr = nuke.nodes.Write (name=\"Write_EXR\",file=c, colorspace=\"linear\")\n    wr['disable'].setExpression(\"((frame &lt; \"+b+\".first)?true:false)||((frame &gt;\"+b+\".last)?true:false)\")\n    wr.setInput(0,dn)<\/pre>\n\n\n\n<p><strong>3. Attach a Write node to selected Read nodes, and embed with expression on disable<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># script that attaches a Write node with default values to selected Read nodes\n# and sticks an expression that reads first and last frames from the read notes\n\nsn = nuke.selectedNodes()\n\nfor n in sn:\n\n    first = n.firstFrame()\n    last = n.lastFrame()\n    a = n['file'].value()\n    b = n['name'].value()\n#    c = a.replace('.%04d.sgi','%04d.'+fmt)\n    d = \"DeNoise_\"+b\n\n    wr = nuke.nodes.Write(name=\"WriteFromRead\",file=c, colorspace=\"sRGB\")\n    wr['disable'].setExpression(\"((frame &lt; \"+b+\".first)?true:false)||((frame &gt;\" +b+\".last)?true:false)\")\n    wr.setInput(0,n)<\/pre>\n\n\n\n<p><strong>4. Change single or multiple parameters in all selected nodes<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># SCRIPT THAT CHANGES SINGLE OR MULTIPLE PARAMETERS IN ALL SELECTED NODES\n\nsn = nuke.selectedNodes()\nfor n in sn:\n        n.knob('channels').setValue(\"rgba\")\n        n.knob('colorspace').setValue(\"sRGB\")\n\n#script that adds a text node with the value from the input node.\n\nsn = nuke.selectedNodes()\n\nfor i in sn:\n    txt = nuke.nodes.Text (font =\"\/usr\/share\/fonts\/bitstream-vera\/Vera.ttf\", message = \"[file tail [knob input0.file]]\", size = \"35\")\n    txt.knob[transform.box].setValue(0,0,1920,1080)\n    txt.setInput(0,i)<\/pre>\n\n\n\n<p><strong>5. Create Write nodes connected with all selected read nodes with correct file name<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># MAKE WRITE NODES CONNECTED WITH READ NODES WITH THE CORRECT FILE NAME\n\nsn = nuke.selectedNodes()\n\nfor n in sn:\n    a = n.name()\n    f = n['name'].value()\n    wsgi=nuke.nodes.Write(name='SGI_Write', file=f, colorspace='default')\n    wsgi['file_type'].setValue(\"sgi\")\n    wsgi['channels'].setValue(\"rgba\")\n    wsgi.setInput(0,n)<\/pre>\n\n\n\n<p><strong>6. Disable &#8220;Postage Stamps&#8221; on all nodes<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># DISABLE \"POSTAGE STAMPS\" ON ALL NODES\n\nfor a in nuke.allNodes():\n    try:\n        a['postage_stamp'].setValue(0)\n    except:\n        pass<\/pre>\n\n\n\n<p><strong>7. Unhide all nodes&#8217; inputs (if received a script that hides them)<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># \"UNHIDE\" ALL NODES' INPUTS - USEFUL WHEN RECEIVING A SNEAKY COMP\/LIGHTING SCRIPT\n\nfor a in nuke.allNodes():\n    try:\n        a['hide_input'].setValue(0)\n    except:\npass<\/pre>\n\n\n\n<p><strong>8. Change the first frame to a certain number &#8211; enhanced version should change the last frame to that number + frame range<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># CHANGE THE \"FIRST\" FRAME OF ALL SELECTED NODES THAT ARE READ NODES\n# (EXAMPLE CHANGES THE FIRST FRAME TO 1001)\n\nfor a in nuke.selectedNodes():\n    if a.Class() == 'Read':\n        a['first'].setValue(1001)<\/pre>\n\n\n\n<p><strong>9. Print a selected nodes&#8217; methods<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># PRINT A SELECTED NODES' METHODS\n\nimport struct\n\nnode = nuke.selectedNode()\n\nfor a in node['lookup'].animations():\n    print dir(a)\n    print inputs (dependencies) of a selected node:\n\nfor a in nuke.selectedNode().dependencies():\n    print a.name()\n    print outputs (dependents) of a selected node:\n\nfor a in nuke.selectedNode().dependent():\n    print a.name()<\/pre>\n\n\n\n<p><strong>10. Find all the Timeoffset nodes in a group (called group2) and change value of offset based on its position in an array of found time offsets<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># FIND ALL THE TimeOffset NODES IN A GROUP CALLED \"Group2\", AND CHANGE THE VALUE\n# OF EACH OFFSET BASED ON ITS POSITION IN THE ARRAY OF FOUND TIME OFFSETS\n\ntos = []\n\nfor a in nuke.toNode('Group2').nodes():\n    if a.Class()=='TimeOffset':\n    tos.append(a)\n\nfor b in tos:\n    b['time_offset'].setValue(tos.index(b))\n    set the \u2018bbox\u2019 for any selected Merge, Keymix &amp; Copy nodes to \u201cB\u201d\n\nfor a in nuke.selectedNodes():\n    classTypes = ['Merge' , 'Keymix', 'Copy', ]\n\nfor n in classTypes:\n    if n in a.Class():\n\nfor p in a['bbox'].values():\n    if 'B' in p:\n        a['bbox'].setValue(a['bbox'].values().index(p))<\/pre>\n\n\n\n<p><strong>11. Remove all animation from selected nodes<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># REMOVE ALL ANIMATION FROM SELECTED NODES\n\nfor a in nuke.selectedNodes():\n    for b in a.knobs():\n        a[b].clearAnimated()<\/pre>\n\n\n\n<p><strong>12. Add keyframes &#8211; Animate mix parameter<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># ADD KEYFRAMES - ANIMATE A MIX\n\nfor a in nuke.selectedNodes():\n    a['mix'].setAnimated()\n    a['mix'].setValueAt(1,nuke.frame())\n    a['mix'].setValueAt(0,(nuke.frame() - 1))<\/pre>\n\n\n\n<p><strong>13. Halve the color value of all constant nodes in a script<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># HALVE THE COLOR VALUE OF ALL THE CONSTANT NODES IN A SCRIPT\n\nfor a in nuke.allNodes():\n    if a.Class() == \"Constant\":\n        a['color'].setValue(a['color'].value()[0] \/ 2 , 0)\n        a['color'].setValue(a['color'].value()[1] \/ 2 , 1)\n        a['color'].setValue(a['color'].value()[2] \/ 2 , 2)<\/pre>\n\n\n\n<p><strong>14. Find all the transform Nodes in the script and if their input is a crop set scale value X2<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># FIND ALL THE TRANSFORM NODES IN A SCRIPT, AND IF THEIR INPUT IS A CROP SET THE SCALE\n# VALUE TO BE TWICE ITS CURRENT VALUE (ALSO CHECKS IF THE SCALE IS A LIST ARRAY OR A FLOAT)\n\nfor a in nuke.allNodes():\n    if a.Class() == \"Transform\":\n    if a.input(0).Class() == \"Crop\":\n        x = a['scale'].value()\n    if type(x).__name__ == 'list':\n        a['scale'].setValue(x[0] * 2 , 0)\n        a['scale'].setValue(x[1] * 2 , 1)\n    if type(x).__name__ == 'float':\n        a['scale'].setValue(x*2)<\/pre>\n\n\n\n<p><strong>15. Set all gain values of CC nodes X2<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># SET ALL THE GAIN VALUES OF ALL SELECTED COLOR CORRECT NODES TO TWICE THEIR CURRENT\n\nfor a in nuke.allNodes():\n    if a.Class() == \"ColorCorrect\":\n    a['gain'].setValue(a['gain'].value() * 2)\n    print files with \u2018mov\u2019 in filename\n\nfor a in nuke.allNodes():\n    if 'Read' in a['name'].value():\n    if 'mov' in a['file'].value():\n    print a['file'].value()<\/pre>\n\n\n\n<p><strong>16. Change font size of all Write nodes in the script<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># CHANGE FONT SIZE OF ALL WRITE NODES IN THE SCRIPT\n\nfor a in nuke.selectedNodes():\n    if \"Write\" in a['name'].value():\n    a['note_font_size'].setValue(60)<\/pre>\n\n\n\n<p><strong>17. Create 20 constants with incrementing color values<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># CREATE 20 CONSTANTS WITH INCREMENTING COLOR VALUES\n\ndef makeConstants(amount):\n    for i in range(amount):\n        a= nuke.nodes.Constant()\n        color= float( float(i) \/ float(amount) )\n        a['color'].setValue(color)<\/pre>\n\n\n\n<p><strong>18. Set up write nodes for specific frame range<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># SET UP WRITE NODES FOR SPECIFIC FRAME RANGE\n\nsn = nuke.selectedNodes()\n\nfor n in sn:\n    first = n.firstFrame()\n    last = n.lastFrame()\n    nuke.render( n.name(), first, last, 1 )<\/pre>\n\n\n\n<p><strong>19. Use Python to define your own hotkeys<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#DEFINING YOUR OWN HOTKEYS\n\ndef _autoplace():\n  n = nuke.selectedNodes()\n  for i in n:\n    nuke.autoplace(i)\nt=nuke.toolbar(\"Extras\")\nt.addCommand(\"Auto&amp;place\", \"_autoplace()\", \"Alt+a\")<\/pre>\n\n\n\n<p><strong>20. Select all class nodes (class Read in this case)<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#SELECTING ALL CLASS NODES (READ NODES)\n\nn = nuke.allNodes()\n\nfor s in n:\n    if s.Class() == \"Read\":\n        s.knob(\"selected\").setValue(True)<\/pre>\n\n\n\n<p><strong>21. Write DPX, create Slate and WriteJPG generator &#8211; written for Method Pipeline<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#WRITE DPX, SLATE AND WRITE JPG\n\n# writeDPX, slate and writeJPG generator v0.1 alpha\n# 1. delete the old write_DPX, slate and write_Latest nodes\n# 2. click on the last node in your comp (select it)\n# 3. execute script\n\na=\"[file dirname [value root.name]]\/..\/..\/images\/comp\/[file rootname [file tail [value root.name]]]\/[file rootname [file tail [value root.name]]].%04d.dpx\"\nb=\"[file rootname [file tail [value root.name]]].[frame].dpx\"\nc=\"[file dirname [value root.name]]\/..\/..\/images\/comp\/latest\/[lindex [split [value root.name] \/] 4]_comp_latest.%04d.jpg\"\n\nwdpx=nuke.nodes.Write(name=\"Write_DPX\", file=a, colorspace=\"rec709\")\nwdpx['file_type'].setValue(\"dpx\")\nwdpx.setInput(0,nuke.selectedNode())\n\nnuke.toNode('Write_DPX').knob('selected').setValue(True)\n\nwslate = nuke.nodes.Text (name=\"Slate\", font=\"\/usr\/share\/fonts\/bitstream-vera\/Vera.ttf\", yjustify = \"center\")\nwslate['box'].setValue([0,0,2048,1168])\nwslate['translate'].setValue([50, -550])\nwslate['size'].setValue(25)\nwslate['message'].setValue(b)\nwslate.setInput(0,nuke.selectedNode())\n\nnuke.toNode('Slate').knob('selected').setValue(True)\n\nwjpg=nuke.nodes.Write (name=\"Write_Latest\", file=c, colorspace=\"rec709\")\nwjpg['file_type'].setValue(\"jpg\")\nwjpg['_jpeg_quality'].setValue([1])\nwjpg.setInput(0,nuke.selectedNode())<\/pre>\n\n\n\n<p><strong>22. Camera with aim<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># camera with aim for Nuke v0.1 by Aleksandar Djordjevic\n\nn = nuke.nodes.Camera2()\n\np = 'set lookAt [value lookObject]\\n\n     puts $lookAt\\n\n     set xX \"degrees(atan2($lookAt.translate.y-translate.y,sqrt(pow($lookAt.translate.x-translate.x,2)+pow($lookAt.translate.z-translate.z,2))))\"\\n\n     set yX \"$lookAt.translate.z-this.translate.z &gt;= 0&nbsp;? 180+degrees(atan2($lookAt.translate.x-translate.x,$lookAt.translate.z-translate.z)):180+degrees(atan2($lookAt.translate.x-translate.x,$lookAt.translate.z-translate.z))\"\\n\n     in this.rotate.x {set_expression $xX}\\n\n     in this.rotate.y {set_expression $yX}\\n'\n\ntab = nuke.Tab_Knob(\"Look\",\"Camera Aim\")\nn.addKnob(tab)\n\nk = nuke.Script_Knob(\"knob\", \"look at\")\nn.addKnob(k)\nn.knob(\"knob\").setValue(p)\nk.setTooltip('Press this button after you type in the aim object\\'s name')\n\nm = nuke.String_Knob(\"lookObject\", \"\")\nn.addKnob(m).po\nm.setTooltip('Type your aim object node name here')<\/pre>\n\n\n\n<p><strong>23. Add a text node with the value from the input node<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#script that adds a text node with the value from the input node.\n\nsn = nuke.selectedNodes()\n\nfor i in sn:\n    txt = nuke.nodes.Text (font =\"\/usr\/share\/fonts\/bitstream-vera\/Vera.ttf\", message = \"[file tail [knob input0.file]]\", size = \"35\")\n    txt.knob[transform.box].setValue(0,0,1920,1080)\n    txt.setInput(0,i)<\/pre>\n\n\n\n<p><strong>24. Multiple Read\/Write node tweaker<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># multi node tweaker v0.1 by Aleksandar Djordjevic\n#\n# this script creates a panel that enables the user to manipulate\n# several knobs inside all selected read and write nodes\n# you can select all nodes but it is going to change values only on reads and writes\\\n\nimport nuke\nimport os\n\ndef multiNodeTweaker():\n\n    test = 0\n    origFileName = None\n    replaceInFileName = None\n    booleanCheckBox = None\n    chanVal = 'rgb rgba alpha depth'\n    cspace = 'default linear sRGB rec709 Cineon Gamma1.8 Gamma2.2 Panalog REDlog ViperLog REDSpace'\n    sn = nuke.selectedNodes()\n\n# first checkpoint - is anything selected?\n    if (len(sn) == 0):\n        nuke.message(\"Select one or more Read or Write nodes\")\n        return\n\n# second checkpoint - I will work only on valid node classes\n    for i in sn:\n        if i.Class()&nbsp;!= 'Read' or 'Write':\n            nuke.message(\"No Read or Write nodes selected.\")\n            return\n\n    o = nuke.Panel(\"Multi Node Tweaker\")\n    o.addSingleLineInput('Find:', origFileName)\n    o.addSingleLineInput('Replace:', replaceInFileName)\n    o.addEnumerationPulldown('Color Space',cspace)\n    o.addButton(\"Cancel\")\n    o.addButton(\"Ok\")\n\n# If selected nodes are of Write class, add parameter to mess with the channels\n    for i in sn:\n        if i.Class() == 'Write':\n            test = 1\n    if test == 1:\n        o.addEnumerationPulldown('Channels:',chanVal)\n\n    o.show()\n\n# grab new values\n    origFileName = o.value(\"Find:\")\n    replaceInFileName = o.value(\"Replace:\")\n    cspace = o.value(\"Color Space\")\n    chanVal = o.value(\"Channels:\")\n\n    for n in sn:\n        filename = n['file'].value()\n        newFileName = filename.replace(origFileName,replaceInFileName)\n        n.knob('file').setValue(newFileName)\n        n.knob('colorspace').setValue(cspace)\n        if n.Class() == 'Write':\n                n.knob('channels').setValue(chanVal)<\/pre>\n\n\n\n<p><strong>25. Import mocha track and create a normal and reversed corner pin out of it<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">import nuke, os\n\ndef importMocha():\n    filename = nuke.getFilename(\"Mocha tracking data\", \"*.txt\")\n    f = open(filename)\n    row = -1\n    active = False\n    data = []\n    height = 0\n    for l in f.readlines():\n        items = l.split()\n        if len(items) &lt; 1:\n            active = False\n\n        if l.lower().lstrip().startswith(\"source height\"):\n            height = float(items[2])\n\n        if active:\n            data[row].append(items)\n\n        if l.lower().lstrip().startswith(\"frame\"):\n            row += 1\n            active = True\n            data.append([])\n\n    cornerPinNode = nuke.createNode(\"CornerPin2D\")\n    cornerPinReverseNode = nuke.createNode(\"CornerPin2D\")\n    points = [\"1\", \"2\", \"4\", \"3\"]\n    for c in range(4):\n        #cornerPinNode.knob(\"to\" + str(c + 1)).setAnimated(True)\n        toKnob = cornerPinNode.knob(\"to\" + points[c])\n        fromKnob = cornerPinReverseNode.knob(\"from\" + points[c])\n        for k in (toKnob, fromKnob):\n            k.setAnimated(0, True)\n            k.setAnimated(1, True)\n\n            for (f, x, y) in data[c]:\n                k.setValueAt(float(x), float(f), 0)\n                k.setValueAt(height - float(y), float(f), 1)<\/pre>\n\n\n\n<p><strong>26. Control \/ smooth curves with a multiplier<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Create a node, let's say a camera node. Create a user tab on it, and make a floating point slider called multiplier and labeled multiplier.\n\nThen, in the expression of your x,y,z for translate, rotate, scale, whatever you want to smooth and control punch in this expression:\ncurve-(curve * multiplier)\n\nFor every frame, it will subtract that frame's value with your multiplier, and if it's 0, it's your original value, if it's not, it changes and smooths the curve by a [multiplier] factor.<\/pre>\n\n\n\n<p><strong>27. Open all property bins of all selected nodes<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># open all property bins of all selected nodes\n# set the max panels number to the amount of nodes you selected\n\nimport nuke, os\n\ndef selnode():\n    sn = nuke.selectedNodes()\n    maxPanels = nuke.toNode('preferences')['maxPanels'] \n    panelCount = 0\n\n    for i in sn:\n        panelCount = panelCount+1\n\n    if panelCount &gt; maxPanels.value():\n        maxPanels.setValue(panelCount)\n\n        for n in sn:\n            nuke.show(n)<\/pre>\n\n\n\n<p><strong>28. Write all the read nodes file name in the script editor<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"># write all the read nodes file names in the script editor\n\nfor a in nuke.allNodes():\n     if 'Read' in a['name'].value():\n         print a['file'].vaue()<\/pre>\n\n\n\n<p><strong>29. Add a text node with the value from the input node<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#script that adds a text node with the value from the input node.\n\nsn = nuke.selectedNodes()\n\nfor i in sn:\n     txt = nuke.nodes.Text (font =\"\/usr\/share\/fonts\/bitstream-vera\/Vera.ttf\", message = \"[file tail [knob input0.file]]\", size = \"35\")\n     txt.knob[transform.box].setValue(0,0,1920,1080)\n     txt.setInput(0,i)<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Foundry&#8217;s Nuke is a premium compositing software with a rich back-end and studio level implementations that can be manipulated and enhanced using python and TCL. This is a compilation of snippets and scripts I&#8217;ve used one time or another over the past years to accomplish specific tasks, and not all of it has been recently [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-365","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.8 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>NUKE: Python &amp; TCL Scripts &amp; Tricks - Aleksandar Sacha Djordjevic<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/sachadjordjevic.com\/index.php\/nuke-python-tcl-scripts-tricks\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"NUKE: Python &amp; TCL Scripts &amp; Tricks - Aleksandar Sacha Djordjevic\" \/>\n<meta property=\"og:description\" content=\"Foundry&#8217;s Nuke is a premium compositing software with a rich back-end and studio level implementations that can be manipulated and enhanced using python and TCL. This is a compilation of snippets and scripts I&#8217;ve used one time or another over the past years to accomplish specific tasks, and not all of it has been recently [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/sachadjordjevic.com\/index.php\/nuke-python-tcl-scripts-tricks\/\" \/>\n<meta property=\"og:site_name\" content=\"Aleksandar Sacha Djordjevic\" \/>\n<meta property=\"article:modified_time\" content=\"2023-12-06T22:08:47+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:site\" content=\"@mixedbysacha\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"16 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/sachadjordjevic.com\/index.php\/nuke-python-tcl-scripts-tricks\/\",\"url\":\"https:\/\/sachadjordjevic.com\/index.php\/nuke-python-tcl-scripts-tricks\/\",\"name\":\"NUKE: Python &amp; TCL Scripts &amp; Tricks - Aleksandar Sacha Djordjevic\",\"isPartOf\":{\"@id\":\"https:\/\/sachadjordjevic.com\/#website\"},\"datePublished\":\"2023-12-06T17:16:41+00:00\",\"dateModified\":\"2023-12-06T22:08:47+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/sachadjordjevic.com\/index.php\/nuke-python-tcl-scripts-tricks\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/sachadjordjevic.com\/index.php\/nuke-python-tcl-scripts-tricks\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/sachadjordjevic.com\/index.php\/nuke-python-tcl-scripts-tricks\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/sachadjordjevic.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"NUKE: Python &amp; TCL Scripts &amp; Tricks\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/sachadjordjevic.com\/#website\",\"url\":\"https:\/\/sachadjordjevic.com\/\",\"name\":\"Sacha Djordjevic\",\"description\":\"VFX Supervisor, Audiovisual Artist &amp; Tech Entrepreneur\",\"publisher\":{\"@id\":\"https:\/\/sachadjordjevic.com\/#\/schema\/person\/fba672de47b9a8032e291f5b8da0f31e\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/sachadjordjevic.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/sachadjordjevic.com\/#\/schema\/person\/fba672de47b9a8032e291f5b8da0f31e\",\"name\":\"Sacha\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/sachadjordjevic.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/sachadjordjevic.com\/wp-content\/uploads\/2024\/08\/IMG_20141110_154422_square-scaled.jpg\",\"contentUrl\":\"https:\/\/sachadjordjevic.com\/wp-content\/uploads\/2024\/08\/IMG_20141110_154422_square-scaled.jpg\",\"width\":2560,\"height\":2560,\"caption\":\"Sacha\"},\"logo\":{\"@id\":\"https:\/\/sachadjordjevic.com\/#\/schema\/person\/image\/\"},\"description\":\"Sacha Djordjevic is an artist, executive and entrepreneur working in creative &amp; tech industries.\",\"sameAs\":[\"https:\/\/sachadjordjevic.com\",\"https:\/\/instagram.com\/mixedbysacha\",\"https:\/\/linkedin.com\/in\/aleksvfx\",\"https:\/\/x.com\/mixedbysacha\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"NUKE: Python &amp; TCL Scripts &amp; Tricks - Aleksandar Sacha Djordjevic","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/sachadjordjevic.com\/index.php\/nuke-python-tcl-scripts-tricks\/","og_locale":"en_US","og_type":"article","og_title":"NUKE: Python &amp; TCL Scripts &amp; Tricks - Aleksandar Sacha Djordjevic","og_description":"Foundry&#8217;s Nuke is a premium compositing software with a rich back-end and studio level implementations that can be manipulated and enhanced using python and TCL. This is a compilation of snippets and scripts I&#8217;ve used one time or another over the past years to accomplish specific tasks, and not all of it has been recently [&hellip;]","og_url":"https:\/\/sachadjordjevic.com\/index.php\/nuke-python-tcl-scripts-tricks\/","og_site_name":"Aleksandar Sacha Djordjevic","article_modified_time":"2023-12-06T22:08:47+00:00","twitter_card":"summary_large_image","twitter_site":"@mixedbysacha","twitter_misc":{"Est. reading time":"16 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/sachadjordjevic.com\/index.php\/nuke-python-tcl-scripts-tricks\/","url":"https:\/\/sachadjordjevic.com\/index.php\/nuke-python-tcl-scripts-tricks\/","name":"NUKE: Python &amp; TCL Scripts &amp; Tricks - Aleksandar Sacha Djordjevic","isPartOf":{"@id":"https:\/\/sachadjordjevic.com\/#website"},"datePublished":"2023-12-06T17:16:41+00:00","dateModified":"2023-12-06T22:08:47+00:00","breadcrumb":{"@id":"https:\/\/sachadjordjevic.com\/index.php\/nuke-python-tcl-scripts-tricks\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/sachadjordjevic.com\/index.php\/nuke-python-tcl-scripts-tricks\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/sachadjordjevic.com\/index.php\/nuke-python-tcl-scripts-tricks\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/sachadjordjevic.com\/"},{"@type":"ListItem","position":2,"name":"NUKE: Python &amp; TCL Scripts &amp; Tricks"}]},{"@type":"WebSite","@id":"https:\/\/sachadjordjevic.com\/#website","url":"https:\/\/sachadjordjevic.com\/","name":"Sacha Djordjevic","description":"VFX Supervisor, Audiovisual Artist &amp; Tech Entrepreneur","publisher":{"@id":"https:\/\/sachadjordjevic.com\/#\/schema\/person\/fba672de47b9a8032e291f5b8da0f31e"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/sachadjordjevic.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/sachadjordjevic.com\/#\/schema\/person\/fba672de47b9a8032e291f5b8da0f31e","name":"Sacha","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/sachadjordjevic.com\/#\/schema\/person\/image\/","url":"https:\/\/sachadjordjevic.com\/wp-content\/uploads\/2024\/08\/IMG_20141110_154422_square-scaled.jpg","contentUrl":"https:\/\/sachadjordjevic.com\/wp-content\/uploads\/2024\/08\/IMG_20141110_154422_square-scaled.jpg","width":2560,"height":2560,"caption":"Sacha"},"logo":{"@id":"https:\/\/sachadjordjevic.com\/#\/schema\/person\/image\/"},"description":"Sacha Djordjevic is an artist, executive and entrepreneur working in creative &amp; tech industries.","sameAs":["https:\/\/sachadjordjevic.com","https:\/\/instagram.com\/mixedbysacha","https:\/\/linkedin.com\/in\/aleksvfx","https:\/\/x.com\/mixedbysacha"]}]}},"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/sachadjordjevic.com\/index.php\/wp-json\/wp\/v2\/pages\/365","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sachadjordjevic.com\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/sachadjordjevic.com\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/sachadjordjevic.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sachadjordjevic.com\/index.php\/wp-json\/wp\/v2\/comments?post=365"}],"version-history":[{"count":3,"href":"https:\/\/sachadjordjevic.com\/index.php\/wp-json\/wp\/v2\/pages\/365\/revisions"}],"predecessor-version":[{"id":412,"href":"https:\/\/sachadjordjevic.com\/index.php\/wp-json\/wp\/v2\/pages\/365\/revisions\/412"}],"wp:attachment":[{"href":"https:\/\/sachadjordjevic.com\/index.php\/wp-json\/wp\/v2\/media?parent=365"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}