Nuke

From cgwiki

Dust motes expression

Basically noise, warped by noise, smoothstepped at the peaks to simulate dust/motes floating in space. Duplicate this a few times, alter the user controls to set different scales and speeds, and merge them all together (all the anim is in the alpha channel btw)

Motes.gif

The above gif is 3 copies, mult-ed up to an intensity of 30, multed again against a section of a colour wheel, then convolved.


set cut_paste_input [stack 0]
version 8.0 v5
push $cut_paste_input
Reformat {
 format "1024 1024 0 0 1024 1024 1 square_1K"
 name Reformat2
 selected true
 xpos -54
 ypos -220
}
Expression {
 expr3 smoothstep(low,high,noise((x*xscale)+noise(y/warpscale+(frame*speed)),(y*yscale)+noise(x/warpscale+(frame*speed)),((frame+offset)*evolvespeed)))
 name motes
 selected true
 xpos -62
 ypos -128
 addUserKnob {20 User}
 addUserKnob {7 offset}
 offset 0.444
 addUserKnob {7 warpscale}
 warpscale 20
 addUserKnob {7 low}
 low 0.524
 addUserKnob {7 high}
 high 1
 addUserKnob {7 speed}
 speed 0.03
 addUserKnob {7 xscale}
 xscale 0.27
 addUserKnob {7 yscale}
 yscale 0.365
 addUserKnob {7 evolvespeed}
 evolvespeed 0.001
}

Expression to generate random number between 5 and 15 each second

5+floor((noise(floor(frame/24)*0.1)+1*0.5)*10)


Text node to display image sequence name with tcl

This will find the topmost node above the text, assume its a read node, grab the name of the image, and strip the frame number and suffix.

[lrange [split [basename [value [topnode].file]] .] 0 0 ]


Working from inside to outside:

[value [topnode].file] -- get the value of the requested knob, in this case, the 'file' value of the topmost node ( I assume its a read node)

[basename ... ] -- given a full /big/path/to/image/sequence/beauty.1234.exr, return beauty.1234.exr

[ split .... .] -- take a string, and split it by the given character. in this case, split 'beauty.1234.exr' into 'beauty' '1234' 'exr'.

[lrange ... 0 0 ] -- given a list, return elements from x to x. Here, I ask from 0 to 0, ie, just the first element in the array, so here it'd return 'beauty'.

This page has been a great cheat sheet for all things tcl and nuke:

http://thoughtvfx.blogspot.com.au/2012/12/nuke-tcl-tips.html

Obligatory lazy copy/paste setup:

set cut_paste_input [stack 0]
version 8.0 v5
Read {
 inputs 0
 file /big/path/to/image/sequence/beauty.1234.exr
 format "1024 1024 0 0 1024 1024 1 square_1K"
 origset true
 on_error black
 name Read1
 selected true
 xpos -347
 ypos -159
 
}
Text2 {
 font_size_toolbar 144
 font_width_toolbar 100
 font_height_toolbar 100
 message "\[lrange \[split \[basename \[value \[topnode].file]] .] 0 0]"
 box {0 733 {width 1813 x1060 446} {height 878 x1060 878}}
 hidden_bbox {0 733 446 878}
 transforms {{0 2}
   }
 cursor_position 6
 font_size 144
 center {1440 1080}
 cursor_initialised true
 initial_cursor_position {{0 878}
   }
 group_animations {{0} imported: 0 selected: 0 items: "root transform/"}
 animation_layers {{1 11 1440 1080 0 0 1 1 0 0 0 0}
   }
 name Text1
 selected true
 xpos -347
 ypos -53
}

if/then syntax

I always forget this. Set a switch node to 1 if the frame is between 90 and 167, otherwise 0:

(frame>90&&frame<167) ? 1 : 0


basically

thing_to_test ? result_if_true : result_if_false


Copy paste thing if you're lazy:

set cut_paste_input [stack 0]
version 7.0 v9
push 0
push $cut_paste_input
Switch {
 inputs 2
 which {{(frame>90&&frame<167)?1:0}}
 name Switch2
 selected true
 xpos -495
 ypos -522
}


Get digits in the name of a node aka opdigits

Nuke opdigits.gif

Oh TCL, you fickle mistress. Thanks for the tip Lorne!

[ regexp -inline {\d+}  [knob name] ]


Nuke folk will look at that and be all like 'whaaa?', while Houdini folk will look at that and go 'Ah, opdigits, gotcha!'.

For you nuke squares, its a common thing in Houdini to have random behaviour be seeded from the name of a node. So if you have a cool noise thing in an expression, and you decide you want multiple copies of your thing, but have them all be different, as they all get named Expression1, Expression2, Expression63 etc, you can extract the 1, 2, 63, and feed that to your noise function.

Paste this into a nuke script, and keep pasting to see that each copy returns a different result:

set cut_paste_input [stack 0]
version 9.0 v9
push $cut_paste_input
Expression {
 temp_name0 seed
 temp_expr0 "\[ regexp -inline \{\\d+\}  \[knob name] ]"
 temp_name1 scale
 temp_expr1 10*random(seed*10)
 temp_name2 offset
 temp_expr2 random(seed)*2
 expr0 noise((cx+offset)*scale,(cy+offset)*scale,0)
 name Expression1
 selected true
 xpos 207
 ypos -161
}

Tile a uv map

Uv expression tiles.gif

Use an expression node, give it sliders for the number of repeats in x and y, and use modulus to find the remainder of (1/repeats) * repeats.

set cut_paste_input [stack 0]
version 7.0 v9
push $cut_paste_input
Expression {
 temp_name0 rate
 temp_expr0 5
 expr0 r%(1/repeatx)*repeatx
 expr1 g%(1/repeaty)*repeaty
 name Expression2
 label "multiply uvs"
 selected true
 xpos 2359
 ypos -173
 addUserKnob {20 User}
 addUserKnob {7 repeatx R 0 10}
 repeatx 1.55
 addUserKnob {7 repeaty R 0 10}
 repeaty 15
}

Offset uv map with wraparound

Uv expression offset.gif

I had a hacky version of this before, now less hacky. Can make it pan in any direction now, and the speed control works as you'd expect (low values = slow, high values = fast)

set cut_paste_input [stack 0]
version 8.0 v1
push $cut_paste_input
Expression {
 temp_name0 shiftx
 temp_expr0 (time/24*ratex)%1
 temp_name1 shifty
 temp_expr1 (time/24*ratey)%1
 expr0 "( r+shiftx < 0) ? 1+r+shiftx :  (r+shiftx)%1"
 expr1 "( g+shifty < 0) ? 1+g+shifty :  (g+shifty)%1"
 name Expression7
 label "offset uvs"
 selected true
 xpos -322
 ypos -22
 addUserKnob {20 User}
 addUserKnob {7 ratex t "\t\t" R -10 10}
 ratex 1.35
 addUserKnob {7 ratey R -10 10}
 ratey -0.85
 addUserKnob {7 time R -1000 1000}
 time {{frame}}
}

Quick dummy uv map

Uv expression square.jpg

Feeling lazy? Sure you are.

set cut_paste_input [stack 0]
version 7.0 v9
push $cut_paste_input
Expression {
 expr0 x/width
 expr1 y/height
 name Expression8
 label "square uv map"
 selected true
 xpos 2444
 ypos -601
}

Python

# make a node
nuke.nodes.Blur()
 
#assign to a variable
b = nuke.toNode('Blur1')
c = nuke.toNode('Checkerboard4')
 
#set a value
b['size'].setValue(4)
 
#connect 2 nodes
b.setInput(2,c)
 
# get a list of all the attributes
[b.knob(x).name() for x in range(b.getNumKnobs()) ]
# set all write nodes to have their also_merge node to 'all'
nodes = [ n for n in nuke.allNodes() if 'Merge' in n.Class() ]
for n in nodes:
     print n['also_merge'].setValue('all')
 
# set all pbw nodes for the aov-reanders to premultiplied
for node in nuke.allNodes():
    if node.Class() == 'Group' and 'aov' in node['name'].getValue():
        if 'pbw' in node['passName'].getValue():
            try:
                print node['name'].getValue()
                node['unpremultiplied'].setValue(0.0)
                print 'result', node['unpremultiplied'].getValue()
            except:
                print '================bad================='
                print node
 
# set selected reads to have error mode as 'nearest frame'
[ x['on_error'].setValue("nearest_frame") for x in nuke.selectedNodes() ]
 
# set knob default. in this case, make the exposure tool work in stops, and set the label to show you the stops value. similar thing for gamma nodes.
nuke.knobDefault('EXPTool.label','[value red]')
nuke.knobDefault('EXPTool.mode','0')
nuke.knobDefault('Gamma.label','[value value]')

Command line python

http://docs.thefoundry.co.uk/nuke/63/pythondevguide/command_line.html

Start nuke command prompt. On linux, annoyingly, there's no cursor or backspace/delete support, can't get readlines/ncurses up n running yet.

nuke -t


Script that define functions to load a script, return a write node, and execute a write node:

#!/bin/python
import nuke
 
def do():
    inScript = '/depts/cg_treehouse/matthewes/mineral/gammafix.nk'
    nuke.scriptOpen( inScript )
    writes = [ n for n in nuke.allNodes() if 'Write' in n.Class() ]
    return writes[0]
 
def run(n):
    nuke.execute(n,1,200)


Save that as 'batchnuke.py', call it from the nuke command line python prompt like this:

import batchnuke as bn
n = bn.do()
bn.run(n)


Can make chages to the python script and reload it with

reload(bn)


Once this is run, the script should also be available live in the interactive prompt, eg

>>> nodes = nuke.allNodes()
>>> nodes
[<Viewer1 at 0x2b09a50>, <Write1 at 0x2b09a30>, <Grade1 at 0x2b09a10>, <Saturation1 at 0x2b099f0>, <Gamma1 at 0x2b099d0>, <Read1 at 0x2b099b0>]

Batch process, full example

Here's a thing that loads a script, finds every mp4 in the current folder, and for each file creates a new read node, swaps the input on the first node after the initial read (hardcoded to a gamma node for now), updates the write path, renders with new framerange.

Had to create a new read node rather than updating in-place, nuke never updates the last frame on the existing read node for some reason.

import nuke
import os
 
def load():
    inScript = '/path/to/nukescript/gammafix.nk'
    nuke.scriptOpen( inScript )
    writes = [ n for n in nuke.allNodes() if 'Write' in n.Class() ]
    return writes[0]
 
 
def swap():
    files = os.listdir('/location/of/video/folder/')
    files = [f for f in files if f.endswith('.mp4')]
 
    for f in files:
        r = nuke.allNodes('Read')[0]
        g = nuke.allNodes('Gamma')[0]
        print 'old file = ', r['file'].value()
        print 'old range = ', r['last'].getValue()
 
 
        mov=nuke.nodes.Read(name='foo')
        mov['file'].fromUserText(f)
        end = int(mov['last'].getValue())
        print 'new range = ', end
 
 
        g.setInput(0,mov)
 
        w = nuke.allNodes('Write')[0]
 
        print 'old write = ', w['file'].value()
        newwrite = f.replace('thumbnail','cc')
        w['file'].setValue(newwrite)
        print 'new write = ', w['file'].value()
 
        if (os.path.exists(newwrite)):
                print 'skipping file', newwrite
        else:
            nuke.execute(w,1,end)
 
 
"""
usage:
 
> nuke -t
 
import batchnuke as bn; bn.load(); 
reload(bn); bn.swap()
 
"""