├── .gitignore ├── my_whotbox_scripts ├── Single │ ├── CornerPin2D │ │ ├── Invert.py │ │ ├── To │ │ │ ├── Delete key.py │ │ │ ├── No animation.py │ │ │ └── Set Key.py │ │ ├── From │ │ │ ├── Delete key.py │ │ │ ├── No animation.py │ │ │ └── Set key.py │ │ └── Set Frame.py │ ├── Viewer │ │ └── Hide Viewer Lines.py │ ├── MergeExpression │ │ └── Difference Expr.py │ ├── Tracker4 │ │ ├── Toggle Rotation.py │ │ ├── Toggle Scale.py │ │ ├── Toggle Translation.py │ │ ├── Create Matchmove.py │ │ └── Create Stab.py │ ├── Dissolve │ │ └── Fun Time.py │ ├── Merge2 │ │ └── Mix Range Expr.py │ ├── Write │ │ ├── Open File Browser.py │ │ ├── Import File.py │ │ └── Fast Export │ │ │ ├── Prerender.py │ │ │ └── Single Frame Export.py │ ├── Read │ │ └── Open File Browser.py │ ├── Matrix │ │ └── Detect Edge.py │ ├── Expression │ │ ├── Switch Despill.py │ │ └── Create RGBA.py │ ├── Roto │ │ └── Shapes To Nodes.py │ ├── Card2 │ │ └── Set Pivot.py │ ├── Card3D │ │ └── Set Pivot.py │ └── Cryptomatte │ │ └── Make Channels.py └── All │ ├── Paste To Selection.py │ ├── Clear Animation On All.py │ ├── Connect To TopNode.py │ ├── Open Project.py │ ├── Copy Project.py │ └── Merge Stack.py └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | material_for_lectioons 3 | .git 4 | .idea 5 | nukepedia_html 6 | Material_ForShowing 7 | W_Hotbox_ForShowing 8 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/CornerPin2D/Invert.py: -------------------------------------------------------------------------------- 1 | for i in nuke.selectedNodes(): 2 | inv = i.knob('invert').value() 3 | i.knob('invert').setValue(1-inv) 4 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/CornerPin2D/To/Delete key.py: -------------------------------------------------------------------------------- 1 | for i in nuke.selectedNodes(): 2 | i.knob('to1').removeKey() 3 | i.knob('to2').removeKey() 4 | i.knob('to3').removeKey() 5 | i.knob('to4').removeKey() 6 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/CornerPin2D/From/Delete key.py: -------------------------------------------------------------------------------- 1 | for i in nuke.selectedNodes(): 2 | i.knob('from1').removeKey() 3 | i.knob('from2').removeKey() 4 | i.knob('from3').removeKey() 5 | i.knob('from4').removeKey() 6 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/CornerPin2D/To/No animation.py: -------------------------------------------------------------------------------- 1 | for i in nuke.selectedNodes(): 2 | i.knob('to1').clearAnimated() 3 | i.knob('to2').clearAnimated() 4 | i.knob('to3').clearAnimated() 5 | i.knob('to4').clearAnimated() 6 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/CornerPin2D/From/No animation.py: -------------------------------------------------------------------------------- 1 | for i in nuke.selectedNodes(): 2 | i.knob('from1').clearAnimated() 3 | i.knob('from2').clearAnimated() 4 | i.knob('from3').clearAnimated() 5 | i.knob('from4').clearAnimated() 6 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/Viewer/Hide Viewer Lines.py: -------------------------------------------------------------------------------- 1 | import nuke 2 | 3 | 4 | value = None 5 | 6 | for i in nuke.allNodes('Viewer'): 7 | 8 | if value == None: 9 | value = i.knob('hide_input').value() 10 | 11 | i.knob('hide_input').setValue(1-value) 12 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/CornerPin2D/Set Frame.py: -------------------------------------------------------------------------------- 1 | frame = str(nuke.frame()) 2 | 3 | for i in nuke.selectedNodes(): 4 | i.knob('copy_to').execute() 5 | i.knob('from1').clearAnimated() 6 | i.knob('from2').clearAnimated() 7 | i.knob('from3').clearAnimated() 8 | i.knob('from4').clearAnimated() 9 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/MergeExpression/Difference Expr.py: -------------------------------------------------------------------------------- 1 | for i in nuke.selectedNodes(): 2 | i.knob('expr0').setValue('0') 3 | i.knob('expr1').setValue('0') 4 | i.knob('expr2').setValue('0') 5 | i.knob('expr3').setValue('Ar!=Br||Ag!=Bg||Ab!=Bb ? 1 : 0') 6 | 7 | i['label'].setValue('a: [value expr3]') 8 | -------------------------------------------------------------------------------- /my_whotbox_scripts/All/Paste To Selection.py: -------------------------------------------------------------------------------- 1 | import nuke 2 | 3 | 4 | nodes_before_selection = nuke.allNodes() 5 | 6 | sel = nuke.selectedNodes() 7 | for node in sel: 8 | node.selectOnly() 9 | nuke.nodePaste('%clipboard%') 10 | 11 | [n.setSelected(True) for n in nuke.allNodes() if n not in nodes_before_selection] 12 | -------------------------------------------------------------------------------- /my_whotbox_scripts/All/Clear Animation On All.py: -------------------------------------------------------------------------------- 1 | import nuke 2 | 3 | 4 | def copyWithClear(node=None): 5 | for name, knob in node.knobs().items(): 6 | try: 7 | if knob.isAnimated(): 8 | knob.clearAnimated() 9 | except AttributeError: 10 | pass 11 | 12 | for i in nuke.selectedNodes(): 13 | copyWithClear(i) 14 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/Tracker4/Toggle Rotation.py: -------------------------------------------------------------------------------- 1 | for i in nuke.selectedNodes(): 2 | #6 = translate, 7 = rotate, 8 = scale 3 | transformMode = 7 4 | 5 | value = 1 - i.knob('tracks').value(transformMode) 6 | 7 | #count tracks 8 | tracks = 0 9 | while i.knob('tracks').isAnimated(31 * tracks + 2): 10 | tracks += 1 11 | 12 | for track in range(tracks): 13 | i.knob('tracks').setValue(value, 31 * track + transformMode) -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/Tracker4/Toggle Scale.py: -------------------------------------------------------------------------------- 1 | for i in nuke.selectedNodes(): 2 | #6 = translate, 7 = rotate, 8 = scale 3 | transformMode = 8 4 | 5 | value = 1 - i.knob('tracks').value(transformMode) 6 | 7 | #count tracks 8 | tracks = 0 9 | while i.knob('tracks').isAnimated(31 * tracks + 2): 10 | tracks += 1 11 | 12 | for track in range(tracks): 13 | i.knob('tracks').setValue(value, 31 * track + transformMode) -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/Tracker4/Toggle Translation.py: -------------------------------------------------------------------------------- 1 | for i in nuke.selectedNodes(): 2 | #6 = translate, 7 = rotate, 8 = scale 3 | transformMode = 6 4 | 5 | value = 1 - i.knob('tracks').value(transformMode) 6 | 7 | #count tracks 8 | tracks = 0 9 | while i.knob('tracks').isAnimated(31 * tracks + 2): 10 | tracks += 1 11 | 12 | for track in range(tracks): 13 | i.knob('tracks').setValue(value, 31 * track + transformMode) -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/Dissolve/Fun Time.py: -------------------------------------------------------------------------------- 1 | for i in nuke.selectedNodes(): 2 | i.knob('knobChanged').setValue('n = nuke.thisNode()\nk = nuke.thisKnob()\nif k.name() == "which":\n mult = n["which"].value()\n r = int(200 * mult) + 40\n g = int(200 * mult) + 40\n b = int(200 * mult) + 40\n hexColor = int("%02x%02x%02x%02x" %(r,g,b,1),16)\n n.knob("tile_color").setValue(int(hexColor))') 3 | i['label'].setValue('Which: [value which]') 4 | i.setSelected(False) 5 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/CornerPin2D/To/Set Key.py: -------------------------------------------------------------------------------- 1 | for i in nuke.selectedNodes(): 2 | f1 = i.knob('to1').getValue() 3 | f2 = i.knob('to2').getValue() 4 | f3 = i.knob('to3').getValue() 5 | f4 = i.knob('to4').getValue() 6 | 7 | i.knob('to1').setAnimated() 8 | i.knob('to1').setValue(f1) 9 | i.knob('to2').setAnimated() 10 | i.knob('to2').setValue(f2) 11 | i.knob('to3').setAnimated() 12 | i.knob('to3').setValue(f3) 13 | i.knob('to4').setAnimated() 14 | i.knob('to4').setValue(f4) 15 | -------------------------------------------------------------------------------- /my_whotbox_scripts/All/Connect To TopNode.py: -------------------------------------------------------------------------------- 1 | import nuke 2 | 3 | 4 | def get_top_node(nodes): 5 | temp_dict = {} 6 | for node in nodes: 7 | temp_dict[node] = node.ypos() 8 | temp_dict = {k: v for k, v in sorted(temp_dict.items(), key=lambda item: item[1])} 9 | l = [k for k in temp_dict] 10 | return l[0] 11 | 12 | 13 | selected = nuke.selectedNodes() 14 | 15 | top_node = get_top_node(selected) 16 | 17 | for node in [node for node in selected if node != top_node]: 18 | node.setInput(0, top_node) 19 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/CornerPin2D/From/Set key.py: -------------------------------------------------------------------------------- 1 | for i in nuke.selectedNodes(): 2 | f1 = i.knob('from1').getValue() 3 | f2 = i.knob('from2').getValue() 4 | f3 = i.knob('from3').getValue() 5 | f4 = i.knob('from4').getValue() 6 | 7 | i.knob('from1').setAnimated() 8 | i.knob('from1').setValue(f1) 9 | i.knob('from2').setAnimated() 10 | i.knob('from2').setValue(f2) 11 | i.knob('from3').setAnimated() 12 | i.knob('from3').setValue(f3) 13 | i.knob('from4').setAnimated() 14 | i.knob('from4').setValue(f4) 15 | -------------------------------------------------------------------------------- /my_whotbox_scripts/All/Open Project.py: -------------------------------------------------------------------------------- 1 | import os 2 | import platform 3 | import subprocess 4 | 5 | 6 | operatingSystem = platform.system() 7 | root_name = nuke.root().name() 8 | openPath = os.path.normpath(root_name) 9 | 10 | if os.path.exists(openPath) and root_name != 'Root': 11 | if operatingSystem == "Windows": 12 | subprocess.call(("explorer", "/select,", openPath)) 13 | elif operatingSystem == "Darwin": 14 | subprocess.call(["open", "-R", openPath]) 15 | else: 16 | subprocess.Popen(["xdg-open", openPath]) 17 | else: 18 | nuke.message("My Master, no path \n\n" + openPath) 19 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/Merge2/Mix Range Expr.py: -------------------------------------------------------------------------------- 1 | for node in nuke.selectedNodes(): 2 | node["mix"].setExpression(""" 3 | [ 4 | set label [value label] 5 | set index_first 0 6 | set pattern_exists [regexp {\d+ - \d+} $label] 7 | 8 | if {$pattern_exists} {} {return 1} 9 | 10 | while {$index_first+2 <= [llength $label]} { 11 | set index_last [expr $index_first + 2] 12 | 13 | if {[lindex $label $index_first] <= [value frame] && [lindex $label $index_last] >= [value frame]} {return 1} 14 | 15 | set index_first [expr $index_first + 3] 16 | } 17 | 18 | return 0 19 | ] 20 | """) 21 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/Write/Open File Browser.py: -------------------------------------------------------------------------------- 1 | import os 2 | import platform 3 | import subprocess 4 | 5 | 6 | operatingSystem = platform.system() 7 | 8 | for i in nuke.selectedNodes(): 9 | 10 | path_file = i.knob('file').value() 11 | 12 | 13 | if path_file.endswith("mov") or path_file.endswith("mp4"): 14 | path_open = os.path.normpath(path_file) 15 | else: 16 | path_open = os.path.normpath(os.path.dirname(path_file)) 17 | 18 | 19 | if os.path.exists(path_open): 20 | 21 | if operatingSystem == "Windows": 22 | subprocess.call(("explorer", "/select,", path_open)) 23 | elif operatingSystem == "Darwin": 24 | subprocess.call(["open", "-R", path_open]) 25 | else: 26 | subprocess.call(["nautilus", "--select", path_open]) 27 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/Read/Open File Browser.py: -------------------------------------------------------------------------------- 1 | import os 2 | import platform 3 | import subprocess 4 | import webbrowser 5 | 6 | 7 | operatingSystem = platform.system() 8 | 9 | 10 | for node in nuke.selectedNodes(): 11 | file = node.knob('file') 12 | file_val = file.value() 13 | 14 | if file_val.endswith("mov") or file_val.endswith("mp4"): 15 | openPath = os.path.normpath(file_val) 16 | else: 17 | openPath = os.path.normpath(os.path.dirname(file_val)) 18 | 19 | if os.path.exists(openPath): 20 | if operatingSystem == "Windows": 21 | subprocess.call(("explorer", "/select,", openPath)) 22 | elif operatingSystem == "Darwin": 23 | subprocess.call(["open", "-R", openPath]) 24 | else: 25 | subprocess.call(["nautilus", "--select", openPath]) 26 | else: 27 | nuke.message("My Master, no path \n\n" + openPath) 28 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/Tracker4/Create Matchmove.py: -------------------------------------------------------------------------------- 1 | # Add selected nodes to dictionary for sort in by position 2 | dict_trackers = {} 3 | for i in nuke.selectedNodes(): 4 | Y = i.ypos() 5 | dict_trackers[Y] = i 6 | list_dict_trackers = sorted(dict_trackers.items()) 7 | 8 | # Select all nodes 9 | for i in nuke.allNodes(): 10 | i.setSelected(True) 11 | 12 | # Create new nodes 13 | for key, value in list_dict_trackers: 14 | value.knob("cornerPinOptions").setValue(5) 15 | value.knob("createCornerPin").execute() 16 | 17 | # Inverst selection to select new created nodes 18 | nuke.invertSelection() 19 | 20 | 21 | # Get list of new created nodes 22 | list_new_trackers = [] 23 | for I in nuke.selectedNodes(): 24 | list_new_trackers.append(I) 25 | 26 | # Connect bot new nodes to top new nodes 27 | lenth = len(list_new_trackers) 28 | if lenth > 1: 29 | bot = 0 30 | top = 1 31 | while bot != lenth-1: 32 | list_new_trackers[bot].setInput(0, list_new_trackers[top]) 33 | bot = bot + 1 34 | top = top + 1 35 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/Tracker4/Create Stab.py: -------------------------------------------------------------------------------- 1 | # Add selected nodes to dictionary for sort in by position 2 | dict_trackers = {} 3 | for i in nuke.selectedNodes(): 4 | Y = i.ypos() 5 | dict_trackers[Y] = i 6 | list_dict_trackers = sorted(dict_trackers.items()) 7 | 8 | # Select all nodes 9 | for i in nuke.allNodes(): 10 | i.setSelected(True) 11 | 12 | # Create new nodes 13 | for key, value in list_dict_trackers: 14 | value.knob("cornerPinOptions").setValue(4) 15 | value.knob("createCornerPin").execute() 16 | 17 | # Inverst selection to select new created nodes 18 | nuke.invertSelection() 19 | 20 | 21 | # Get list of new created nodes 22 | list_new_trackers = [] 23 | for I in nuke.selectedNodes(): 24 | list_new_trackers.append(I) 25 | 26 | # Connect bot new nodes to top new nodes 27 | lenth = len(list_new_trackers) 28 | if lenth > 1: 29 | bot = 0 30 | top = 1 31 | while bot != lenth-1: 32 | list_new_trackers[bot].setInput(0, list_new_trackers[top]) 33 | bot = bot + 1 34 | top = top + 1 35 | 36 | 37 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/Matrix/Detect Edge.py: -------------------------------------------------------------------------------- 1 | # indexes: 2 | # 0 is left | 1 is right | 2 is top 3 | # 3 is bot | 4 is left_bot | 5 is left_top 4 | # 6 is right_bot | 7 is right_top 5 | 6 | index = 0 7 | 8 | for i in nuke.selectedNodes(): 9 | left = [-1, 0, 1, 10 | -1, 0, 1, 11 | -1, 0, 1] 12 | right = [1, 0, -1, 13 | 1, 0, -1, 14 | 1, 0, -1] 15 | top = [-1, -1, -1, 16 | 0, 0, 0, 17 | 1, 1, 1] 18 | bot = [1, 1, 1, 19 | 0, 0, 0, 20 | -1, -1, -1] 21 | left_bot = [0, 1, 1, 22 | -1, 0, 1, 23 | -1, -1, 0] 24 | left_top = [-1, -1, 0, 25 | -1, 0, 1, 26 | 0, 1, 1] 27 | right_bot = [1, 1, 0, 28 | 1, 0, -1, 29 | 0, -1, -1] 30 | right_top = [0, -1, -1, 31 | 1, 0, -1, 32 | 1, 1, 0] 33 | 34 | index_compare = ["left", "right", "top", "bot", "left_bot", "left_top", "right_bot", "right_top"] 35 | 36 | counter = 0 37 | for v in eval(index_compare[index]): 38 | i['matrix'].setValue(v, counter) 39 | counter += 1 40 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/Expression/Switch Despill.py: -------------------------------------------------------------------------------- 1 | for i in nuke.selectedNodes(): 2 | blue = 'b>(r+g)/2?(r+g)/2:b' 3 | green = 'g>(r+b)/2?(r+b)/2:g' 4 | 5 | if i['temp_name3'].value() == '': 6 | i.knob('expr0').setValue('r') 7 | i.knob('expr1').setValue(green) 8 | i.knob('expr2').setValue('b') 9 | i.knob('expr3').setValue('a') 10 | i['label'].setValue('g: [value expr1]') 11 | 12 | i['temp_name3'].setValue('green_set') 13 | 14 | r = int(105) 15 | g = int(139) 16 | b = int(114) 17 | hexColor = int("%02x%02x%02x%02x" %(r,g,b,1),16) 18 | i.knob("tile_color").setValue(int(hexColor)) 19 | 20 | elif i['temp_name3'].value() == 'green_set': 21 | i.knob('expr0').setValue('r') 22 | i.knob('expr1').setValue('g') 23 | i.knob('expr2').setValue(blue) 24 | i.knob('expr3').setValue('a') 25 | i['label'].setValue('g: [value expr2]') 26 | 27 | i['temp_name3'].setValue('') 28 | 29 | r = int(66) 30 | g = int(97) 31 | b = int(109) 32 | hexColor = int("%02x%02x%02x%02x" %(r,g,b,1),16) 33 | i.knob("tile_color").setValue(int(hexColor)) 34 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/Roto/Shapes To Nodes.py: -------------------------------------------------------------------------------- 1 | import nuke 2 | import nukescripts 3 | 4 | 5 | def try_to_set_knob_values(from_node, to_node): 6 | for k_name in from_node.knobs(): 7 | try: 8 | if not k_name == "name": 9 | to_node[k_name].setValue(from_node[k_name].value()) 10 | except: 11 | pass 12 | 13 | for node in [n for n in nuke.selectedNodes()]: 14 | 15 | x, y = node.xpos(), node.ypos() 16 | 17 | TASK = nuke.ProgressTask("Creating rotos...") 18 | TASK.setMessage("Please, wait...") 19 | 20 | counter = 0 21 | for shape in node["curves"].rootLayer: 22 | 23 | if TASK.isCancelled(): 24 | break 25 | 26 | x = x + 125 27 | 28 | new_node = nuke.nodes.Roto() 29 | try_to_set_knob_values(from_node=node, to_node=new_node) 30 | 31 | new_node['curves'].rootLayer.setTransform(node['curves'].rootLayer.getTransform()) 32 | 33 | new_node.setXYpos(x, y) 34 | 35 | new_node.setName(node.name() + "_" + shape.name) 36 | 37 | new_node['curves'].rootLayer.append(shape.clone()) 38 | 39 | TASK.setProgress(int(float(counter) / float(len(node["curves"].rootLayer)) * 100)) 40 | counter += 1 41 | 42 | node.setSelected(False) 43 | 44 | TASK.setProgress(100) 45 | del TASK 46 | -------------------------------------------------------------------------------- /my_whotbox_scripts/All/Copy Project.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import re 4 | 5 | def lastCopyPlusOne(nk_last_copy): 6 | separate = nk_last_copy.split('_COPY_') 7 | number_plus_one = str(int((separate[-1]).replace('.nk', '')) + 1).zfill(3) 8 | 9 | return str(separate[0] + '_COPY_' + str(number_plus_one) + '.nk') 10 | 11 | root = nuke.root().name() 12 | if root == 'Root': 13 | nuke.message('Please save prj first') 14 | else: 15 | root_parts = os.path.split(root) 16 | root_name = root_parts[1] 17 | root_path = root_parts[0] 18 | 19 | nk_files = [] 20 | for file in os.listdir(root_path): 21 | print('wrok with ' + file) 22 | if os.path.isfile(os.path.join(root_path, file)): 23 | if file.endswith(".nk"): 24 | nk_files.append(file) 25 | print(f'got nk_files: {nk_files}') 26 | 27 | nk_copies = [] 28 | for nk_file in nk_files: 29 | if '_COPY_' in nk_file: 30 | nk_copies.append(nk_file) 31 | print(f'got nk_copies: {nk_copies}') 32 | 33 | if len(nk_copies) > 0: 34 | nk_copies = sorted(nk_copies) 35 | nk_last_copy = nk_copies[-1] 36 | shutil.copy(root, os.path.join(root_path, lastCopyPlusOne(nk_last_copy))) 37 | nuke.message('Copied with filename ' + str(lastCopyPlusOne(nk_last_copy))) 38 | else: 39 | shutil.copy(root, os.path.join(root_path, root_name.replace('.nk', '')+'_COPY_001.nk')) 40 | nuke.message('Copied with filename ' + str(root_name.replace('.nk', '')+'_COPY_001.nk')) 41 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/Expression/Create RGBA.py: -------------------------------------------------------------------------------- 1 | def set_channel(node, channel): 2 | count = 0 3 | while count < 4: 4 | node.knob('expr' + str(count)).setValue(channel) 5 | count += 1 6 | 7 | for i in nuke.selectedNodes(): 8 | exprR = nuke.nodes.Expression(name='R') 9 | exprG = nuke.nodes.Expression(name='G') 10 | exprB = nuke.nodes.Expression(name='B') 11 | exprA = nuke.nodes.Expression(name='A') 12 | dot = nuke.nodes.Dot() 13 | 14 | set_channel(exprR, 'r') 15 | set_channel(exprG, 'g') 16 | set_channel(exprB, 'b') 17 | set_channel(exprA, 'a') 18 | 19 | exprR.setXpos(i.xpos() - 150) 20 | exprR.setYpos(i.ypos()) 21 | exprG.setXpos(i.xpos()) 22 | exprG.setYpos(i.ypos()) 23 | exprB.setXpos(i.xpos() + 150) 24 | exprB.setYpos(i.ypos()) 25 | exprA.setXpos(i.xpos() + 300) 26 | exprA.setYpos(i.ypos()) 27 | dot.setXpos(i.xpos() + 108) 28 | dot.setYpos(i.ypos() - 100) 29 | 30 | # blood color 31 | r = int(141) 32 | g = int(81) 33 | b = int(93) 34 | hexColor = int("%02x%02x%02x%02x" %(r,g,b,1),16) 35 | exprR.knob("tile_color").setValue(int(hexColor)) 36 | 37 | # grass color 38 | r = int(105) 39 | g = int(139) 40 | b = int(114) 41 | hexColor = int("%02x%02x%02x%02x" %(r,g,b,1),16) 42 | exprG.knob("tile_color").setValue(int(hexColor)) 43 | 44 | # ocean color 45 | r = int(66) 46 | g = int(97) 47 | b = int(109) 48 | hexColor = int("%02x%02x%02x%02x" %(r,g,b,1),16) 49 | exprB.knob("tile_color").setValue(int(hexColor)) 50 | 51 | exprR.setInput(0, dot) 52 | exprG.setInput(0, dot) 53 | exprB.setInput(0, dot) 54 | exprA.setInput(0, dot) 55 | 56 | nuke.delete(i) 57 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/Card2/Set Pivot.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | 4 | # SET INDEX 5 | # 0 = left bot | 1 = bot | 2 = right bot | 3 = left | 4 = center 6 | # 5 = right | 6 = left top | 7 = top | 8 = right top 7 | index = 0 8 | 9 | 10 | def printMatrix4(matrix): 11 | # Only for scripting. Print Matrix4 in Script Editor 12 | row = '| ' + 4 * '{: .4f} ' + '|' 13 | print() 14 | print(row.format(matrix[0], matrix[4], matrix[8], matrix[12])) 15 | print(row.format(matrix[1], matrix[5], matrix[9], matrix[13])) 16 | print(row.format(matrix[2], matrix[6], matrix[10], matrix[14])) 17 | print(row.format(matrix[3], matrix[7], matrix[11], matrix[15])) 18 | 19 | 20 | def getMatrixFromNode(node): 21 | # Get Matrix4 from node 22 | try: 23 | nodeMatrix = nuke.math.Matrix4() 24 | if 'world_matrix' in [k for k in node.knobs()]: 25 | knobname = 'world_matrix' 26 | elif 'matrix' in [k for k in node.knobs()]: 27 | knobname = 'matrix' 28 | else: 29 | raise NameError 30 | 31 | for x in range(node[knobname].width()): 32 | for y in range(node[knobname].height()): 33 | nodeMatrix[x*4+y] = node[knobname].value(y,x) 34 | 35 | except (NameError, AttributeError): 36 | nuke.message('No matrix found') 37 | nodeMatrix.makeIdentity() 38 | 39 | return nodeMatrix 40 | 41 | 42 | def movePivotToAxis(selNode, newPivot=nuke.math.Vector3(0.0, 0.0, 0.0)): 43 | # variables 44 | oldTranslate = nuke.math.Vector3(float(selNode['translate'].x()), float(selNode['translate'].y()), float(selNode['translate'].z())) 45 | oldPivot = nuke.math.Vector3(float(selNode['pivot'].x()), float(selNode['pivot'].y()), float(selNode['pivot'].z())) 46 | oldLocalTranslate = -oldPivot 47 | oldGlobalPivot = oldTranslate + oldPivot 48 | 49 | # get matrix from node 50 | m1 = getMatrixFromNode(selNode) 51 | 52 | # get localTranslate 53 | oldFullGlobalTranslate = m1.transform(oldLocalTranslate) 54 | oldFullGlobalTranslate = oldFullGlobalTranslate + oldGlobalPivot 55 | localTranslate = oldFullGlobalTranslate - newPivot 56 | 57 | # inverse node matrix 58 | m1 = m1.inverse() 59 | 60 | # multiply matrix to localTranslate and get new Vector3 value 61 | localTranslate = m1.transform(localTranslate) 62 | 63 | # set position and pivot values to card 64 | selNode['translate'].setValue(newPivot+localTranslate) 65 | selNode['pivot'].setValue(-localTranslate) 66 | 67 | def getCardPointsDefaultPosition(oldCard): 68 | # Function creates card, find default corner position 69 | # and return sorted Vector3 values of corners 70 | 71 | card = nuke.nodes.Card(rows=2, columns=2) 72 | 73 | card['image_aspect'].setValue(oldCard['image_aspect'].value()) 74 | 75 | geoNode = nuke.nodes.PythonGeo(inputs=[card]) 76 | points = geoNode['geo'].getGeometry()[0].points() 77 | 78 | points_sorted = [] 79 | for i in range(0, len(points), 3): 80 | v = nuke.math.Vector3(points[i], points[i+1], points[i+2]) 81 | points_sorted.append(v) 82 | 83 | nuke.delete(card) 84 | nuke.delete(geoNode) 85 | 86 | return points_sorted 87 | 88 | 89 | def getPoints(card, index): 90 | # Get points position of Card3 according to Card3 Matrix4 91 | # card = node Card3 | index = which corner of Card3 get 92 | 93 | # pos = it is default position of all Card3 corners 94 | # starting with left bot to right top including center 95 | 96 | pos = getCardPointsDefaultPosition(card) 97 | 98 | # get card Matrix4 99 | matrix = getMatrixFromNode(card) 100 | 101 | # transform pos according to the Card3 Matrix4 and return new Vector3 value 102 | return matrix.transform(pos[index]) 103 | 104 | nodes = [] 105 | for i in nuke.selectedNodes(): 106 | nodes.append(i) 107 | 108 | for node in nodes: 109 | movePivotToAxis(node, getPoints(node, index)) 110 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/Card3D/Set Pivot.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | 4 | # SET INDEX 5 | # 0 = left bot | 1 = bot | 2 = right bot | 3 = left | 4 = center 6 | # 5 = right | 6 = left top | 7 = top | 8 = right top 7 | index = 0 8 | 9 | 10 | def printMatrix4(matrix): 11 | # Only for scripting. Print Matrix4 in Script Editor 12 | row = '| ' + 4 * '{: .4f} ' + '|' 13 | print() 14 | print(row.format(matrix[0], matrix[4], matrix[8], matrix[12])) 15 | print(row.format(matrix[1], matrix[5], matrix[9], matrix[13])) 16 | print(row.format(matrix[2], matrix[6], matrix[10], matrix[14])) 17 | print(row.format(matrix[3], matrix[7], matrix[11], matrix[15])) 18 | 19 | 20 | def getMatrixFromNode(node): 21 | # Get Matrix4 from node 22 | try: 23 | nodeMatrix = nuke.math.Matrix4() 24 | if 'world_matrix' in [k for k in node.knobs()]: 25 | knobname = 'world_matrix' 26 | elif 'matrix' in [k for k in node.knobs()]: 27 | knobname = 'matrix' 28 | else: 29 | raise NameError 30 | 31 | for x in range(node[knobname].width()): 32 | for y in range(node[knobname].height()): 33 | nodeMatrix[x*4+y] = node[knobname].value(y,x) 34 | 35 | except (NameError, AttributeError): 36 | nuke.message('No matrix found') 37 | nodeMatrix.makeIdentity() 38 | 39 | return nodeMatrix 40 | 41 | 42 | def movePivotToAxis(selNode, newPivot=nuke.math.Vector3(0.0, 0.0, 0.0)): 43 | # variables 44 | oldTranslate = nuke.math.Vector3(float(selNode['translate'].x()), float(selNode['translate'].y()), float(selNode['translate'].z())) 45 | oldPivot = nuke.math.Vector3(float(selNode['pivot'].x()), float(selNode['pivot'].y()), float(selNode['pivot'].z())) 46 | oldLocalTranslate = -oldPivot 47 | oldGlobalPivot = oldTranslate + oldPivot 48 | 49 | # get matrix from node 50 | m1 = getMatrixFromNode(selNode) 51 | 52 | # get localTranslate 53 | oldFullGlobalTranslate = m1.transform(oldLocalTranslate) 54 | oldFullGlobalTranslate = oldFullGlobalTranslate + oldGlobalPivot 55 | localTranslate = oldFullGlobalTranslate - newPivot 56 | 57 | # inverse node matrix 58 | m1 = m1.inverse() 59 | 60 | # multiply matrix to localTranslate and get new Vector3 value 61 | localTranslate = m1.transform(localTranslate) 62 | 63 | # set position and pivot values to card 64 | selNode['translate'].setValue(newPivot+localTranslate) 65 | selNode['pivot'].setValue(-localTranslate) 66 | 67 | def getCardPointsDefaultPosition(oldCard): 68 | # Function creates card, find default corner position 69 | # and return sorted Vector3 values of corners 70 | 71 | card = nuke.nodes.Card(rows=2, columns=2) 72 | 73 | card['image_aspect'].setValue(1) 74 | card.setInput(0, oldCard.dependencies()[0]) 75 | 76 | geoNode = nuke.nodes.PythonGeo(inputs=[card]) 77 | points = geoNode['geo'].getGeometry()[0].points() 78 | 79 | points_sorted = [] 80 | for i in range(0, len(points), 3): 81 | v = nuke.math.Vector3(points[i], points[i+1], points[i+2]) 82 | points_sorted.append(v) 83 | 84 | nuke.delete(card) 85 | nuke.delete(geoNode) 86 | 87 | return points_sorted 88 | 89 | 90 | def getPoints(card, index): 91 | # Get points position of Card3 according to Card3 Matrix4 92 | # card = node Card3 | index = which corner of Card3 get 93 | 94 | # pos = it is default position of all Card3 corners 95 | # starting with left bot to right top including center 96 | 97 | pos = getCardPointsDefaultPosition(card) 98 | 99 | # get card Matrix4 100 | matrix = getMatrixFromNode(card) 101 | 102 | # transform pos according to the Card3 Matrix4 and return new Vector3 value 103 | return matrix.transform(pos[index]) 104 | 105 | nodes = [] 106 | for i in nuke.selectedNodes(): 107 | nodes.append(i) 108 | 109 | for node in nodes: 110 | movePivotToAxis(node, getPoints(node, index)) 111 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MY WHOTBOX SCRIPTS 2 | 3 | [YouTube](https://www.youtube.com/@parfprod1/videos) 4 | [Nukepedia](http://www.nukepedia.com/python/nodegraph/my-whotbox-scripts) 5 | 6 | I'm long-time user of WHotBox for NukeX, and now I would like to share some useful scripts for it. 7 | 8 | ### SINGLE NODES 9 | 10 | ##### Card2 / Card3D 11 | - Set Pivot: 12 | - Script works on matrix. It helps to set pivot point to Card - no matter how strong it deformed. 13 | ![Alt Text](http://www.nukepedia.com/images/users/NyanNyanGringo/my_whotbox_scripts/my_whotbox_scripts_card2.gif) 14 | 15 | ##### CornerPin2D 16 | This bundle of scripts are simple but save much time. 17 | - Set Frame: 18 | - Copies "to" params to "from" and remove all keyframes. 19 | - Invert: 20 | - Switch between Matchmove and Stabilize mode. 21 | - Set key: 22 | - Set keyframe to "to" or to "from" knobs in current frame. 23 | - No animation: 24 | - Removes animation in "to" or "from" knobs. 25 | - Delete key: 26 | - Delete keyframes in "to" or "from" knobs in current frame. 27 | ![Alt Text](http://www.nukepedia.com/images/users/NyanNyanGringo/my_whotbox_scripts/my_whotbox_scripts_cornerpin.gif) 28 | 29 | ##### Cryptomatte 30 | - Make Channels: 31 | - Lays out all not empty cryptomatte layers. 32 | ![Alt Text](http://www.nukepedia.com/images/users/NyanNyanGringo/my_whotbox_scripts/my_whotbox_scripts_crypt.gif) 33 | 34 | ##### Dissolve 35 | - Fun Time: 36 | - Makes connection between which knob and tile color in dissolve. 37 | ![Alt Text](http://www.nukepedia.com/images/users/NyanNyanGringo/my_whotbox_scripts/my_whotbox_scripts_dissolve.gif) 38 | 39 | ##### Expression 40 | - Create RGBA: 41 | - Creates 4 expression nodes that spread out input for 4 channels: r, g, b and a. 42 | - Switch Despill: 43 | - Switch expression to green/blue despill. 44 | ![Alt Text](http://www.nukepedia.com/images/users/NyanNyanGringo/my_whotbox_scripts/my_whotbox_scripts_expr.gif) 45 | 46 | ##### Matrix (3x3) 47 | - Detect Edge: 48 | - Set to matrix knobs values that helps to detect edges of input. 49 | ![Alt Text](http://www.nukepedia.com/images/users/NyanNyanGringo/my_whotbox_scripts/my_whotbox_scripts_matrix.gif) 50 | 51 | ##### Merge2 52 | - Mix Range Expr: 53 | - Set to mix knob expression that switch mix between 0 and 1 based on label range values. For example if label contains two strins "1 - 100" and "150 - 175" in range of 1 to 100 and range from 150 to 175 mix value will 1 - in any other frames mix value will be 0. 54 | ![Alt Text](http://www.nukepedia.com/images/users/NyanNyanGringo/my_whotbox_scripts/my_whotbox_scripts_merge2.gif) 55 | 56 | ##### MergeExpression 57 | - Difference Expr: 58 | - Find difference between RGB channels of A and B inputs. If in pixel difference of values found 59 | - this pixel will be 1 in alpha channes. If not difference - pixel will be zero. 60 | - Useful to make a mask in the end of script for Grain nodes comparing source and compose result images. 61 | ![Alt Text](http://www.nukepedia.com/images/users/NyanNyanGringo/my_whotbox_scripts/my_whotbox_scripts_mergedifference.gif) 62 | 63 | ##### Read 64 | - Open File Browser: 65 | - Opens current Read file in finder if it exists and select it. 66 | ![Alt Text](http://www.nukepedia.com/images/users/NyanNyanGringo/my_whotbox_scripts/my_whotbox_scripts_read.gif) 67 | 68 | ##### Roto 69 | - Shapes To Nodes: 70 | - Convert all Roto shapes to single nodes. 71 | ![Alt Text](http://www.nukepedia.com/images/users/NyanNyanGringo/my_whotbox_scripts/my_whotbox_scripts_roto.gif) 72 | 73 | ##### Tracker4 74 | This bundle of scripts are simple but save much time. 75 | - Create Matchmove: 76 | - Craetes transform matchmove nodes from tracker or trackers. 77 | - Create Stab: 78 | - Craetes transform stabilize nodes from tracker or trackers. 79 | - Toggle Rotation*: 80 | - Switch on/off rotation for all trackers. 81 | - Toggle Scale*: 82 | - Switch on/off scale for all trackers. 83 | - Toggle Translation*: 84 | - Switch on/off transaltion for all trackers. 85 | * not my scripts - do not remember author. 86 | ![Alt Text](http://www.nukepedia.com/images/users/NyanNyanGringo/my_whotbox_scripts/my_whotbox_scripts_tracker4.gif) 87 | 88 | ##### Viewer 89 | - Hide Viewer Lines: 90 | - Hide viewer lines when it is not selected. 91 | ![Alt Text](http://www.nukepedia.com/images/users/NyanNyanGringo/my_whotbox_scripts/my_whotbox_scripts_viewer.gif) 92 | 93 | ##### Write 94 | - Open File Browser: 95 | - Opens current Write file in finder if it exists and select it. 96 | - Import File: 97 | - Import current Write file to Nuke. 98 | - Prerender: 99 | - Script to make fast prerenders. It automatically read values from topnode so all you need to do is to write unique name. 100 | - Single Frame Export: 101 | - Works as Prerender but exports only single frame. 102 | ![Alt Text](http://www.nukepedia.com/images/users/NyanNyanGringo/my_whotbox_scripts/my_whotbox_scripts_write.gif) 103 | 104 | ### ALL NODES 105 | 106 | ##### Project 107 | - Copy Project: 108 | - Make a new copy of script near current script. 109 | - Open Project: 110 | - Opens current project in finder and select it. 111 | ![Alt Text](http://www.nukepedia.com/images/users/NyanNyanGringo/my_whotbox_scripts/my_whotbox_scripts_project.gif) 112 | 113 | ##### Selection 114 | - Clear Animation On All: 115 | - Clear animation on selected nodes knobs. 116 | ![Alt Text](http://www.nukepedia.com/images/users/NyanNyanGringo/my_whotbox_scripts/my_whotbox_scripts_clear_anim.gif) 117 | - Connect To TopNode: 118 | - Connect selected nodes to topnode of selection. 119 | ![Alt Text](http://www.nukepedia.com/images/users/NyanNyanGringo/my_whotbox_scripts/my_whotbox_scripts_topnode.gif) 120 | - Paste To Selection: 121 | - Paste info from boofer to selected nodes. 122 | ![Alt Text](http://www.nukepedia.com/images/users/NyanNyanGringo/my_whotbox_scripts/my_whotbox_scripts_paste.gif) 123 | - Merge Stack: 124 | - Creates stack of merges for selected nodes. 125 | ![Alt Text](http://www.nukepedia.com/images/users/NyanNyanGringo/my_whotbox_scripts/my_whotbox_scripts_mergestack.gif) 126 | 127 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/Cryptomatte/Make Channels.py: -------------------------------------------------------------------------------- 1 | import ast 2 | 3 | 4 | nuke_ver = nuke.NUKE_VERSION_MAJOR 5 | 6 | 7 | if nuke_ver >= 13: 8 | def maxValue(srcNode, channel='red'): 9 | expr = nuke.nodes.Expression(inputs=[srcNode], expr0="a") 10 | grade = nuke.nodes.Grade(inputs=[expr], channels=channel, white=100) 11 | reformat = nuke.nodes.Reformat(inputs=[grade], type=2, scale=0.1, filter=0) 12 | width = reformat.width() 13 | height = reformat.height() 14 | curve_tool = nuke.nodes.CurveTool(inputs=[reformat], channels=channel) 15 | curve_tool.knob('ROI').setValue(width, 2) 16 | curve_tool.knob('ROI').setValue(height, 3) 17 | nuke.execute(curve_tool, nuke.frame(), nuke.frame()) 18 | maxValue = curve_tool.knob('intensitydata').value() 19 | 20 | nuke.delete(grade) 21 | nuke.delete(reformat) 22 | nuke.delete(curve_tool) 23 | nuke.delete(expr) 24 | 25 | return maxValue 26 | 27 | 28 | for crypt in nuke.selectedNodes(): 29 | 30 | # create matte_list 31 | metadate = crypt.metadata() 32 | for key in metadate: 33 | if 'manifest' in key: 34 | metadate_values = metadate[key] 35 | 36 | matte_list = [] 37 | for key in ast.literal_eval(metadate_values): 38 | matte_list.append(key) 39 | 40 | 41 | # delete cryptomatte node, find read node 42 | read = (crypt.dependencies())[0] 43 | nuke.delete(crypt) 44 | 45 | count = 0 46 | count_x = 0 47 | while count < len(matte_list): 48 | color_green = 16712451 49 | dot = nuke.nodes.Dot(inputs=[read], hide_input=1, tile_color=color_green) 50 | crypt_new = nuke.nodes.Cryptomatte(inputs=[dot], matteList=matte_list[count]) 51 | 52 | if maxValue(crypt_new) == 0: 53 | nuke.delete(crypt_new) 54 | nuke.delete(dot) 55 | else: 56 | expr = nuke.nodes.Expression(inputs=[crypt_new], expr0="a*10", expr1="a*10", expr2="b+a*10", postage_stamp=True, tile_color=color_green) 57 | 58 | crypt_new.setXpos(read.xpos() + count_x) 59 | dot.setXpos(read.xpos() + count_x + 34) 60 | expr.setXpos(read.xpos() + count_x) 61 | 62 | crypt_new.setYpos(read.ypos() + 150) 63 | dot.setYpos(read.ypos() + 120) 64 | expr.setYpos(crypt_new.ypos() + 25) 65 | 66 | count_x += 100 67 | 68 | count += 1 69 | 70 | 71 | elif nuke_ver == 12: 72 | # Function to understand if channel red is zero or not 73 | def getMax(srcNode, channel='red'): 74 | grade = nuke.nodes.Grade(inputs=[srcNode], channels=channel, white=100) 75 | reformat = nuke.nodes.Reformat(inputs=[grade], type=2, scale=0.1, filter=0) 76 | width = reformat.width() 77 | height = reformat.height() 78 | curve_tool = nuke.nodes.CurveTool(inputs=[reformat], channels=channel) 79 | curve_tool.knob('ROI').setValue(width, 2) 80 | curve_tool.knob('ROI').setValue(height, 3) 81 | nuke.execute(curve_tool, nuke.frame(), nuke.frame()) 82 | maxValue = curve_tool.knob('intensitydata').value() 83 | 84 | nuke.delete(grade) 85 | nuke.delete(reformat) 86 | nuke.delete(curve_tool) 87 | 88 | return maxValue 89 | 90 | 91 | # Bake all selected cryptomatte nodes 92 | cryptomattes = [] 93 | for i in nuke.selectedNodes(): 94 | cryptomattes.append(i) 95 | i.setSelected(False) 96 | 97 | # Main 98 | for cryptomatte in cryptomattes: 99 | 100 | # Select all projects nodes 101 | nodes_selected_old = [] 102 | for i in nuke.allNodes(): 103 | nodes_selected_old.append(i.name()) 104 | 105 | # Execute manifest from cryptomatte 106 | cryptomatte.knob('unloadManifest').execute() 107 | 108 | 109 | # Take read name and delete cryptomatte node 110 | read = (cryptomatte.dependencies())[0] 111 | nuke.delete(cryptomatte) 112 | 113 | # Select new created nodes 114 | nodes_selected_new = [] 115 | for i in nuke.allNodes(): 116 | if not i.name() in nodes_selected_old: 117 | nodes_selected_new.append(i) 118 | 119 | 120 | for i in nodes_selected_new: 121 | #delete empty nodes 122 | maxV = getMax(i) 123 | if maxV == 0: 124 | nuke.delete(i) 125 | 126 | # select not empty nodes 127 | if i in nuke.allNodes(): 128 | i.setSelected(True) 129 | 130 | # not empty nodes: postion, organize 131 | count_nodes = 0 132 | count_postion = 0 133 | while count_nodes <= len(nuke.selectedNodes()): 134 | for i in nuke.selectedNodes(): 135 | i.knob('postage_stamp').setValue(True) 136 | i.setYpos(read.ypos()+225) 137 | i.setXpos(read.xpos() + count_postion) 138 | 139 | dot = nuke.nodes.Dot(hide_input=1, tile_color=16712451) 140 | dot.setXpos(i.xpos()+33) 141 | dot.setYpos(i.ypos()-50) 142 | dot.setInput(0, read) 143 | i.setInput(0, dot) 144 | dot.knob('hide_input').setValue(1) 145 | dot.knob('hide_input').setValue(1) 146 | 147 | count_nodes += 1 148 | count_postion += 125 149 | 150 | i.setSelected(False) 151 | 152 | 153 | # add choice for details (decrease or increase scale in reformat) 154 | # arrange in node graph nodes 155 | # make good text for all knobs 156 | # make beautiful connections to all knobs 157 | elif nuke_ver < 12: 158 | nuke.message('Version of nuke is not supported. Sorryy...') 159 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/Write/Import File.py: -------------------------------------------------------------------------------- 1 | import os 2 | import nuke 3 | import re 4 | 5 | 6 | MOV_EXTENSIONS = [".mov", ".mp4"] 7 | SEQUENCE_EXNTENSIONS = [".exr", ".dpx", ".png", ".tiff", ".psd", ".jpeg", ".jpg"] 8 | EXTENSIONS = MOV_EXTENSIONS + SEQUENCE_EXNTENSIONS 9 | 10 | 11 | # STRING HELPERS 12 | 13 | 14 | def get_start_end_indexes(where_search, what_search): 15 | if find := re.finditer(what_search, where_search): 16 | return [(m.start(0), m.end(0)) for m in find] 17 | 18 | 19 | def replace_on_end(what_replace: str, for_what_replace: str, where_replace: str, _on_start=False) -> str: 20 | """ 21 | Work as classic replace but only for one element in the end of string 22 | """ 23 | if indexes := get_start_end_indexes(where_replace, what_replace): 24 | index_in, index_out = indexes[-1] 25 | string = "".join([where_replace[:index_in], for_what_replace, where_replace[index_out:]]) 26 | return string 27 | return where_replace 28 | 29 | 30 | def get_file_extension(file_path): 31 | """Return file extension (with dot), if it is supported and exists""" 32 | try: 33 | file_extension = "." + file_path.split(".")[-1] 34 | except IndexError as e: 35 | message = f"Can't get file extension: {e}" 36 | nuke.message(message) 37 | raise IndexError(message) 38 | 39 | if file_extension not in EXTENSIONS: 40 | message = f"Not supported extension: {file_extension}. Supported: " + ", ".join(EXTENSIONS) 41 | nuke.message(message) 42 | raise ValueError(message) 43 | 44 | return file_extension 45 | 46 | 47 | def file_is_sequence(file_path: str) -> bool: 48 | file_extension = get_file_extension(file_path) 49 | 50 | if file_extension in MOV_EXTENSIONS: 51 | return False 52 | return True 53 | 54 | 55 | def get_file_name(file_full_name: str) -> str: 56 | """Return file name without extension and version""" 57 | file_extension = get_file_extension(file_full_name) 58 | 59 | # remove extension 60 | file_name = replace_on_end(file_extension, "", file_full_name) 61 | 62 | # remove %d или %00d или .#### 63 | file_name = re.sub("%(\d+|)d", "", file_name) 64 | file_name = re.sub("\.#+", "", file_name) 65 | 66 | # remove version 67 | file_name = re.sub("_v\d+", "", file_name) 68 | 69 | # remove dots in the end if exists 70 | return re.sub("\.+$", "", file_name) 71 | 72 | 73 | # NUKE HELPERS 74 | 75 | 76 | def convert_tcl(tcl_code: str, node: nuke.Node = None, return_all_string: bool = True) -> str: 77 | """ 78 | Convert TCL code to Python and execute it. 79 | 80 | :param tcl_code: ... 81 | :param node: node which contains this TCL code. 82 | :param return_all_string: if False, return TCL code without any other string. 83 | :return: result of TCL code after executing. 84 | """ 85 | if node: # convert TCL "topnode" command 86 | tcl_code = tcl_code.replace("[topnode]", f"[topnode {node.name()}]") 87 | tcl_code = tcl_code.replace("[topnode this", f"[topnode {node.name()}") 88 | tcl_code = tcl_code.replace("[topnode input", f"[topnode {node.name()}.input") 89 | tcl_code = tcl_code.replace("[topnode parent", f"[topnode {node.name()}.parent") 90 | 91 | if return_all_string: 92 | return nuke.tcl("subst", tcl_code) 93 | return nuke.tcl(tcl_code) 94 | 95 | 96 | def set_colorspace_from_write_to_read(write_node, read_node): 97 | write_colorspace = write_node["colorspace"].value() 98 | 99 | if "default (" in write_colorspace: 100 | read_node["colorspace"].setValue(0) 101 | return 102 | 103 | read_node["colorspace"].setValue(write_colorspace) 104 | 105 | 106 | # OS HELPERS 107 | 108 | 109 | def check_path_exists(file_path: str) -> bool: 110 | 111 | if not file_path: 112 | return False 113 | 114 | if get_file_extension(file_path) in MOV_EXTENSIONS and not os.path.exists(file_path): 115 | return False 116 | 117 | if get_file_extension(file_path) in SEQUENCE_EXNTENSIONS and not os.path.exists(os.path.dirname(file_path)): 118 | return False 119 | 120 | return True 121 | 122 | 123 | # START 124 | 125 | 126 | def start(): 127 | for write_node in nuke.selectedNodes(): 128 | file_path = write_node.knob('file').value() 129 | file_path = convert_tcl(file_path, write_node) 130 | 131 | if not check_path_exists(file_path): 132 | nuke.message(f"File doesn't exists:\n\n{file_path}") 133 | return 134 | 135 | if file_is_sequence(file_path): 136 | 137 | file_dir = os.path.dirname(file_path) 138 | file_full_name = os.path.basename(file_path) 139 | file_name = get_file_name(file_full_name) 140 | file_extension = get_file_extension(file_full_name) 141 | 142 | nuke_file_name = str() 143 | for f in nuke.getFileNameList(file_dir): 144 | 145 | if not file_extension in f: 146 | continue 147 | if not file_name in f: 148 | continue 149 | 150 | nuke_file_name = f 151 | 152 | assert nuke_file_name, f"Unsuspected Error!" 153 | nuke_file_path = os.path.join(file_dir, nuke_file_name).replace("\\", "/") 154 | 155 | regexp_pattern = " \d+-\d+$" 156 | more_than_one_file_in_sequence = re.findall(regexp_pattern, nuke_file_name) 157 | if more_than_one_file_in_sequence: 158 | frame_range = re.findall(regexp_pattern, nuke_file_name)[0] 159 | read_node = nuke.nodes.Read(file=re.split(regexp_pattern, nuke_file_path)[0], 160 | first=frame_range.split("-")[0], 161 | last=frame_range.split("-")[1]) 162 | else: 163 | read_node = nuke.createNode('Read', "file {" + nuke_file_path + "}", inpanel=False) 164 | 165 | set_colorspace_from_write_to_read(write_node, read_node) 166 | 167 | else: 168 | read_node = nuke.createNode('Read', "file {" + file_path + "}", inpanel=False) 169 | 170 | read_node.setXpos(write_node.xpos()) 171 | read_node.setYpos(write_node.ypos() + 100) 172 | 173 | 174 | if __name__ == "W_hotbox": 175 | start() 176 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/Write/Fast Export/Prerender.py: -------------------------------------------------------------------------------- 1 | import nuke 2 | import nukescripts 3 | import os, re 4 | 5 | 6 | class Panel(nukescripts.PythonPanel): 7 | def __init__(self, write): 8 | nukescripts.PythonPanel.__init__(self, 'Fast Export: Prerender') 9 | 10 | # print(dir(self)) 11 | 12 | self.can_I_render = False 13 | self.write = write 14 | 15 | # changeable variables 16 | self.var1 = "prerenders" 17 | 18 | # variables 19 | self.all_ok = False 20 | self.root = os.path.split(nuke.root().name())[0] 21 | self.extensions = ["dpx", "exr", "hdr", "jpeg", "mov", "png", "tiff", "mp4"] 22 | 23 | # construct 24 | self.read_file, self.read_ext, self.read_cc = self.getReadValues() 25 | self.setupUI() 26 | self.setPanelKnobValues() 27 | self.showModal() 28 | 29 | def start(self): 30 | return self.can_I_render 31 | 32 | def setupUI(self): 33 | self.p_name = nuke.String_Knob("p_name", "Prerender name:", "") 34 | self.addKnob(self.p_name) 35 | 36 | self.p_fakeok = nuke.PyScript_Knob("p_fakeok", "Render!") 37 | self.addKnob(self.p_fakeok) 38 | self.p_fakeok.clearFlag(nuke.STARTLINE) 39 | self.p_fakeok.setVisible(False) 40 | 41 | self.p_ok = nuke.PyScript_Knob("p_ok", "Render!") 42 | self.addKnob(self.p_ok) 43 | self.p_ok.clearFlag(nuke.STARTLINE) 44 | self.p_ok.setEnabled(False) 45 | 46 | self.p_div0 = nuke.Text_Knob('', '', ' ') 47 | self.addKnob(self.p_div0) 48 | 49 | self.p_ext = nuke.Enumeration_Knob("p_ext", "Extension:", self.extensions) 50 | self.addKnob(self.p_ext) 51 | self.p_ext.setFlag(nuke.STARTLINE) 52 | self.p_ext.setEnabled(False) 53 | 54 | self.p_cc = nuke.Enumeration_Knob("p_cc", "Colorspace:", []) 55 | self.addKnob(self.p_cc) 56 | self.p_cc.clearFlag(nuke.STARTLINE) 57 | self.p_cc.setEnabled(False) 58 | 59 | self.p_first = nuke.Int_Knob("p_first", "First:") 60 | self.addKnob(self.p_first) 61 | self.p_first.clearFlag(nuke.STARTLINE) 62 | self.p_first.setEnabled(False) 63 | 64 | self.p_last = nuke.Int_Knob("p_last", "Last:") 65 | self.addKnob(self.p_last) 66 | self.p_last.clearFlag(nuke.STARTLINE) 67 | self.p_last.setEnabled(False) 68 | 69 | self.p_fps = nuke.Int_Knob("p_fps", "FPS:") 70 | self.addKnob(self.p_fps) 71 | self.p_fps.clearFlag(nuke.STARTLINE) 72 | self.p_fps.setEnabled(False) 73 | self.p_fps.setVisible(False) 74 | 75 | self.p_div1 = nuke.Text_Knob('', '', ' ') 76 | self.addKnob(self.p_div1) 77 | 78 | self.p_log = nuke.Multiline_Eval_String_Knob("p_log", "Prerender folder files:", "") 79 | self.addKnob(self.p_log) 80 | self.p_log.setFlag(nuke.STARTLINE) 81 | # self.p_log.setEnabled(False) 82 | 83 | self.setMinimumSize(950, 500) 84 | 85 | def knobChanged(self, knob): 86 | if knob is self.p_name: 87 | self.setEnabledDisabled() 88 | if knob is self.p_log: 89 | self.setLogKnobValues() 90 | if knob is self.p_ok: 91 | self.setWriteValues() 92 | if knob is self.p_ext: 93 | if knob.value() == "mov" or knob.value() == "mp4": 94 | self.p_fps.setVisible(True) 95 | else: 96 | self.p_fps.setVisible(False) 97 | 98 | def setEnabledDisabled(self): 99 | if self.p_name.value() == "": 100 | self.p_ok.setEnabled(False) 101 | self.p_ext.setEnabled(False) 102 | self.p_cc.setEnabled(False) 103 | self.p_first.setEnabled(False) 104 | self.p_last.setEnabled(False) 105 | self.p_fps.setEnabled(False) 106 | else: 107 | self.p_ok.setEnabled(True) 108 | self.p_ext.setEnabled(True) 109 | self.p_cc.setEnabled(True) 110 | self.p_first.setEnabled(True) 111 | self.p_last.setEnabled(True) 112 | self.p_fps.setEnabled(True) 113 | 114 | def getReadValues(self): 115 | topnode_file = nuke.tcl("value [topnode %s].file" % self.write.name()) 116 | topnode_endswith = topnode_file.split(".")[-1] 117 | topnode_colorspace = nuke.tcl("value [topnode %s].colorspace" % self.write.name()) 118 | topnode_colorspace = topnode_colorspace.replace("default (", "").replace(")", "") 119 | 120 | return topnode_file, topnode_endswith, topnode_colorspace 121 | 122 | def setPanelKnobValues(self): 123 | 124 | # Set extension 125 | self.p_ext.setValue(self.read_ext) 126 | 127 | # Set colospace 128 | tempWrite = nuke.nodes.Write() 129 | colospaces = tempWrite['colorspace'].values() 130 | nuke.delete(tempWrite) 131 | self.p_cc.setValues(colospaces) 132 | self.p_cc.setValue(self.read_cc) 133 | 134 | # Set First and Last 135 | self.p_first.setValue(self.write.firstFrame()) 136 | self.p_last.setValue(self.write.lastFrame()) 137 | 138 | # Set FPS 139 | topnode_name = nuke.tcl("value [topnode %s].name" % write.name()) 140 | metadate = nuke.toNode(topnode_name).metadata() 141 | for key, value in metadate.items(): 142 | if "frame_rate" in key: 143 | self.p_fps.setValue(int(value)) 144 | if self.p_ext.value() == "mov" or self.p_ext.value() == "mp4": 145 | self.p_fps.setVisible(True) 146 | else: 147 | self.p_fps.setVisible(False) 148 | 149 | # Set log 150 | self.setLogKnobValues() 151 | 152 | def setLogKnobValues(self): 153 | path = os.path.join(self.root, self.var1) 154 | if os.path.exists(path): 155 | files = os.listdir(path) 156 | self.p_log.setValue(str("\n".join(files))) 157 | else: 158 | self.p_log.setValue("Prerender directory not created.") 159 | 160 | def setWriteValues(self): 161 | # values for write 162 | prerender_path = os.path.join(self.root, self.var1) 163 | if self.p_ext.value() == "mov" or self.p_ext.value() == "mp4": 164 | file_type = "mov" 165 | path = os.path.join(prerender_path, self.p_name.value() + "." + file_type) 166 | else: 167 | file_type = self.p_ext.value() 168 | path = os.path.join(prerender_path, self.p_name.value()) 169 | path = os.path.join(path, self.p_name.value() + ".####." + file_type) 170 | 171 | if not self.checkFileExists(path) and nuke.ask("Start render?"): 172 | # set values to write 173 | self.write.resetKnobsToDefault() 174 | self.write['file'].setValue(path.replace("\\", "/")) 175 | self.write['file_type'].setValue(file_type) 176 | self.write['colorspace'].setValue(self.p_cc.value()) 177 | self.write['create_directories'].setValue("1") 178 | self.write['first'].setValue(self.p_first.value()) 179 | self.write['last'].setValue(self.p_last.value()) 180 | self.write['channels'].setValue("all") 181 | if file_type == "mov": 182 | self.write["mov_prores_codec_profile"].setValue("ProRes 4:4:4:4 12-bit") 183 | self.write["mov64_fps"].setValue(self.p_fps.value()) 184 | 185 | self.can_I_render = True 186 | self.finishModalDialog(True) 187 | 188 | def checkFileExists(self, path_to_file): 189 | 190 | if self.p_ext.value() == "mov" or self.p_ext.value() == "mp4": 191 | 192 | if os.path.exists(path_to_file): 193 | if nuke.ask('Prerender with name ' + self.p_name.value() + ' already exists! Rewrite?'): 194 | return False 195 | else: 196 | return True 197 | else: 198 | return False 199 | 200 | else: 201 | 202 | if os.path.exists(os.path.split(path_to_file)[0]): 203 | if nuke.ask('Prerender with name ' + self.p_name.value() + ' already exists! Rewrite?'): 204 | return False 205 | else: 206 | return True 207 | else: 208 | return False 209 | 210 | 211 | ### CHECK BEFORE START QT ### 212 | 213 | 214 | writes = [] 215 | for write in nuke.selectedNodes(): 216 | writes.append(write) 217 | 218 | check = 0 219 | if check == 0: 220 | if len(writes) == 1: 221 | check += 1 222 | write = writes[0] 223 | else: 224 | nuke.message("Please select only one Write node!") 225 | 226 | if check == 1: 227 | if nuke.root().name() != 'Root': 228 | check += 1 229 | else: 230 | nuke.message("Please save project first!") 231 | 232 | if check == 2: 233 | if write.inputs() == 1: 234 | check += 1 235 | else: 236 | nuke.message("Please connect input to write!") 237 | 238 | if check == 3: 239 | topnode_name = nuke.tcl("value [topnode %s].name" % write.name()) 240 | if nuke.toNode(topnode_name).Class() == "Read": 241 | check += 1 242 | else: 243 | nuke.message("Topnode is not Read!") 244 | 245 | 246 | ### START ### 247 | 248 | 249 | if check == 4: 250 | p = Panel(writes[0]) 251 | ok = p.start() 252 | if ok: 253 | nuke.execute(writes[0], int(writes[0].knob('first').value()), int(writes[0].knob('last').value())) 254 | nuke.message("Render finished!") 255 | -------------------------------------------------------------------------------- /my_whotbox_scripts/Single/Write/Fast Export/Single Frame Export.py: -------------------------------------------------------------------------------- 1 | import nuke 2 | import nukescripts 3 | import os, re, shutil 4 | 5 | 6 | unique_write_name = "WriteE847V309FG27E43" 7 | 8 | 9 | class Panel(nukescripts.PythonPanel): 10 | def __init__(self, write): 11 | nukescripts.PythonPanel.__init__(self, 'Fast Export: Single Frame') 12 | 13 | # print(dir(self)) 14 | 15 | self.can_I_render0 = False 16 | self.can_I_render1 = False 17 | self.write = write 18 | 19 | # changeable variables 20 | self.var1 = "single_frames" 21 | 22 | # variables 23 | self.all_ok = False 24 | self.root = os.path.split(nuke.root().name())[0] 25 | self.extensions = ["dpx", "exr", "hdr", "jpeg", "png", "tiff"] 26 | 27 | # construct 28 | self.read_file, self.read_ext, self.read_cc = self.getReadValues() 29 | self.setupUI() 30 | self.setPanelKnobValues() 31 | self.showModal() 32 | 33 | def start(self): 34 | return self.can_I_render0, self.can_I_render1 35 | 36 | def setupUI(self): 37 | self.p_name = nuke.String_Knob("p_name", "Single Frame name:", "") 38 | self.addKnob(self.p_name) 39 | 40 | self.p_fakeok = nuke.PyScript_Knob("p_fakeok", "Render!") 41 | self.addKnob(self.p_fakeok) 42 | self.p_fakeok.clearFlag(nuke.STARTLINE) 43 | self.p_fakeok.setVisible(False) 44 | 45 | self.p_frame = nuke.Int_Knob("p_frame", "") 46 | self.addKnob(self.p_frame) 47 | self.p_frame.clearFlag(nuke.STARTLINE) 48 | self.p_frame.setEnabled(False) 49 | 50 | self.p_ok = nuke.PyScript_Knob("p_ok", "Render!") 51 | self.addKnob(self.p_ok) 52 | self.p_ok.clearFlag(nuke.STARTLINE) 53 | self.p_ok.setEnabled(False) 54 | 55 | self.p_div0 = nuke.Text_Knob('', '', ' ') 56 | self.addKnob(self.p_div0) 57 | 58 | self.p_use_frame_in_name = nuke.Boolean_Knob("p_use_frame_in_name", "Show frames in files name?", "1") 59 | self.addKnob(self.p_use_frame_in_name) 60 | self.p_use_frame_in_name.setFlag(nuke.STARTLINE) 61 | self.p_use_frame_in_name.setEnabled(False) 62 | 63 | self.p_ext0 = nuke.Enumeration_Knob("p_ext0", "Preview", self.extensions) 64 | self.addKnob(self.p_ext0) 65 | self.p_ext0.setFlag(nuke.STARTLINE) 66 | self.p_ext0.setEnabled(False) 67 | 68 | self.p_cc0 = nuke.Enumeration_Knob("p_cc0", "", []) 69 | self.addKnob(self.p_cc0) 70 | self.p_cc0.clearFlag(nuke.STARTLINE) 71 | self.p_cc0.setEnabled(False) 72 | 73 | self.p_active0 = nuke.Boolean_Knob("p_active0", "", "1") 74 | self.addKnob(self.p_active0) 75 | self.p_active0.clearFlag(nuke.STARTLINE) 76 | self.p_active0.setEnabled(False) 77 | 78 | self.p_ext1 = nuke.Enumeration_Knob("p_ext1", "Hires", self.extensions) 79 | self.addKnob(self.p_ext1) 80 | self.p_ext1.setFlag(nuke.STARTLINE) 81 | self.p_ext1.setEnabled(False) 82 | 83 | self.p_cc1 = nuke.Enumeration_Knob("p_cc1", "", []) 84 | self.addKnob(self.p_cc1) 85 | self.p_cc1.clearFlag(nuke.STARTLINE) 86 | self.p_cc1.setEnabled(False) 87 | 88 | self.p_active1 = nuke.Boolean_Knob("p_active1", "", "1") 89 | self.addKnob(self.p_active1) 90 | self.p_active1.clearFlag(nuke.STARTLINE) 91 | self.p_active1.setEnabled(False) 92 | 93 | self.p_div1 = nuke.Text_Knob('', '', ' ') 94 | self.addKnob(self.p_div1) 95 | 96 | self.p_log = nuke.Multiline_Eval_String_Knob("p_log", "Prerender folder files:", "") 97 | self.addKnob(self.p_log) 98 | self.p_log.setFlag(nuke.STARTLINE) 99 | 100 | self.setMinimumSize(500, 500) 101 | 102 | def knobChanged(self, knob): 103 | if knob is self.p_name: 104 | self.setEnabledDisabled() 105 | if knob is self.p_active0 or knob is self.p_active1: 106 | self.setEnabledDisabledActive() 107 | if knob is self.p_log: 108 | self.setLogKnobValues() 109 | if knob is self.p_ok: 110 | self.setWriteValues() 111 | 112 | def setEnabledDisabledActive(self): 113 | if self.p_active0.value(): 114 | self.p_ext0.setEnabled(True) 115 | self.p_cc0.setEnabled(True) 116 | else: 117 | self.p_ext0.setEnabled(False) 118 | self.p_cc0.setEnabled(False) 119 | 120 | if self.p_active1.value(): 121 | self.p_ext1.setEnabled(True) 122 | self.p_cc1.setEnabled(True) 123 | else: 124 | self.p_ext1.setEnabled(False) 125 | self.p_cc1.setEnabled(False) 126 | 127 | if not self.p_active0.value() and not self.p_active1.value(): 128 | self.p_ok.setEnabled(False) 129 | else: 130 | self.p_ok.setEnabled(True) 131 | 132 | def setEnabledDisabled(self): 133 | if self.p_name.value() == "": 134 | bool_val = False 135 | else: 136 | bool_val = True 137 | 138 | knobs = [self.p_frame, self.p_ok, self.p_ext0, self.p_cc0, self.p_active0, 139 | self.p_ext1, self.p_cc1, self.p_active1, self.p_use_frame_in_name] 140 | for knob in knobs: 141 | knob.setEnabled(bool_val) 142 | 143 | if not self.p_active0.value(): 144 | self.p_ext0.setEnabled(False) 145 | self.p_cc0.setEnabled(False) 146 | if not self.p_active1.value(): 147 | self.p_ext1.setEnabled(False) 148 | self.p_cc1.setEnabled(False) 149 | 150 | 151 | def getReadValues(self): 152 | topnode_file = nuke.tcl("value [topnode %s].file" % self.write.name()) 153 | topnode_endswith = topnode_file.split(".")[-1] 154 | topnode_colorspace = nuke.tcl("value [topnode %s].colorspace" % self.write.name()) 155 | topnode_colorspace = topnode_colorspace.replace("default (", "").replace(")", "") 156 | 157 | return topnode_file, topnode_endswith, topnode_colorspace 158 | 159 | def setPanelKnobValues(self): 160 | 161 | # Set frame 162 | self.p_frame.setValue(int(nuke.frame())) 163 | 164 | # Set extension 165 | self.p_ext0.setValue("png") 166 | if self.read_ext == "mov" or self.read_ext == "mp4": 167 | self.p_ext1.setValue("exr") 168 | else: 169 | self.p_ext1.setValue(self.read_ext) 170 | 171 | # Set colospace 172 | tempWrite = nuke.nodes.Write() 173 | colospaces = tempWrite['colorspace'].values() 174 | for cc in colospaces: 175 | if "sRGB" in cc: 176 | srgb_name = cc 177 | break 178 | else: 179 | srgb_name = "sRGB" 180 | nuke.delete(tempWrite) 181 | self.p_cc0.setValues(colospaces) 182 | self.p_cc1.setValues(colospaces) 183 | 184 | self.p_cc0.setValue(srgb_name) 185 | self.p_cc1.setValue(self.read_cc) 186 | 187 | # Set log 188 | self.setLogKnobValues() 189 | 190 | def setLogKnobValues(self): 191 | path = os.path.join(self.root, self.var1) 192 | if os.path.exists(path): 193 | files = os.listdir(path) 194 | self.p_log.setValue(str("\n".join(files))) 195 | else: 196 | self.p_log.setValue("Prerender directory not created.") 197 | 198 | def setWriteValues(self): 199 | single_frame_path = os.path.join(self.root, self.var1) 200 | file_subpath = os.path.join(single_frame_path, self.p_name.value()) 201 | if self.p_use_frame_in_name.value(): 202 | file_path0 = os.path.join(file_subpath, self.p_name.value() + "_prv.####." + self.p_ext0.value()) 203 | file_path1 = os.path.join(file_subpath, self.p_name.value() + "_hires.####." + self.p_ext1.value()) 204 | else: 205 | file_path0 = os.path.join(file_subpath, self.p_name.value() + "_prv." + self.p_ext0.value()) 206 | file_path1 = os.path.join(file_subpath, self.p_name.value() + "_hires." + self.p_ext1.value()) 207 | 208 | if not self.checkFileExists(file_subpath) and nuke.ask("Start render?"): 209 | write0 = self.write 210 | write0_input = write0.dependencies()[0] 211 | 212 | write1 = nuke.nodes.Write(name=unique_write_name) 213 | write1.setInput(0, write0_input) 214 | 215 | write0.resetKnobsToDefault() 216 | 217 | write0["file"].setValue(file_path0.replace("\\", "/")) 218 | write1["file"].setValue(file_path1.replace("\\", "/")) 219 | 220 | write0["file_type"].setValue(self.p_ext0.value()) 221 | write1["file_type"].setValue(self.p_ext1.value()) 222 | 223 | write0["colorspace"].setValue(self.p_cc0.value()) 224 | write1["colorspace"].setValue(self.p_cc1.value()) 225 | 226 | write0['create_directories'].setValue("1") 227 | write1['create_directories'].setValue("1") 228 | 229 | write0['first'].setValue(self.p_frame.value()) 230 | write0['last'].setValue(self.p_frame.value()) 231 | write1['first'].setValue(self.p_frame.value()) 232 | write1['last'].setValue(self.p_frame.value()) 233 | 234 | if self.p_active0.value(): 235 | self.can_I_render0 = True 236 | if self.p_active1.value(): 237 | self.can_I_render1 = True 238 | self.finishModalDialog(True) 239 | 240 | def checkFileExists(self, path_to_file): 241 | if os.path.exists(path_to_file): 242 | if nuke.ask('Prerender with name ' + self.p_name.value() + ' already exists! Rewrite?'): 243 | shutil.rmtree(path_to_file) 244 | return False 245 | else: 246 | return True 247 | else: 248 | return False 249 | 250 | 251 | ### CHECK BEFORE START QT ### 252 | 253 | 254 | writes = [] 255 | for write in nuke.selectedNodes(): 256 | writes.append(write) 257 | 258 | check = 0 259 | if check == 0: 260 | if len(writes) == 1: 261 | check += 1 262 | write = writes[0] 263 | else: 264 | nuke.message("Please select only one Write node!") 265 | 266 | if check == 1: 267 | if nuke.root().name() != 'Root': 268 | check += 1 269 | else: 270 | nuke.message("Please save project first!") 271 | 272 | if check == 2: 273 | if write.inputs() == 1: 274 | check += 1 275 | else: 276 | nuke.message("Please connect input to write!") 277 | 278 | if check == 3: 279 | topnode_name = nuke.tcl("value [topnode %s].name" % write.name()) 280 | if nuke.toNode(topnode_name).Class() == "Read": 281 | check += 1 282 | else: 283 | nuke.message("Topnode is not Read!") 284 | 285 | 286 | ### START ### 287 | 288 | 289 | if check == 4: 290 | p = Panel(writes[0]) 291 | ok0, ok1 = p.start() 292 | write1 = nuke.toNode(unique_write_name) 293 | if ok0: 294 | nuke.execute(write, int(write.knob('first').value()), int(write.knob('last').value())) 295 | if ok1: 296 | nuke.execute(write1, int(write1.knob('first').value()), int(write1.knob('last').value())) 297 | nuke.delete(write1) 298 | if ok0 or ok1: 299 | nuke.message("Render finished!") 300 | -------------------------------------------------------------------------------- /my_whotbox_scripts/All/Merge Stack.py: -------------------------------------------------------------------------------- 1 | # get next node down tree (if node has multiple outputs, get first one found) 2 | def getOutNode(n): 3 | 4 | # this sometimes fails on first try, just do it again 5 | listDotOut = n.dependent() 6 | dotOut = None 7 | 8 | # go through dependent nodes and see if they are connected with hidden pipes or if they are viewers 9 | for outNode in listDotOut: 10 | 11 | #if not, make this the node to make a corner with 12 | if (not outNode.Class() == "Viewer") and (not outNode['hide_input'].getValue()): 13 | 14 | dotOut = outNode 15 | break 16 | 17 | 18 | 19 | # return single node 20 | return dotOut 21 | 22 | 23 | 24 | 25 | def PlaceInCorner(dotsToAlign, forceXpos=-.1): 26 | 27 | # get list of dots only 28 | dots = [] 29 | 30 | # if all dots connect to same node, do not make corner dots 31 | SameDotOut = True if len(dotsToAlign) > 1 else False 32 | lastDotOut = None 33 | nodeClosestYPos = float("inf") 34 | multInputXPos = 0 35 | 36 | 37 | # for each selected node with 'Dot' as its class 38 | for n in dotsToAlign: 39 | 40 | if n.Class() == "Dot": 41 | 42 | # populate list 43 | dots.append(n) 44 | 45 | 46 | # only check if there's still a chance they're all the same 47 | if(SameDotOut): 48 | 49 | dotOut = getOutNode(n) 50 | 51 | if((dotOut == lastDotOut or lastDotOut == None) and not (dotOut == None) ): 52 | 53 | # update store 54 | lastDotOut = dotOut 55 | 56 | # get the closest Ypos of input nodes to this output node 57 | nodeClosestYPos = min( abs(dotOut.ypos() - n.input(0).ypos()), nodeClosestYPos ) 58 | 59 | # found a difference 60 | else: 61 | 62 | SameDotOut = False 63 | 64 | 65 | # go through all dots 66 | for dot in dots: 67 | 68 | # if knobs don't exist or something else is wrong, do not bother user 69 | try: 70 | 71 | # get the input and output nodes 72 | dotIn = dot.input(0) 73 | dotOut = getOutNode(dot) 74 | 75 | 76 | # get the input and output node position center (which is their position + half of their width and half of their height, as they are positioned by their corners) 77 | dotInX = dotIn.xpos() + (dotIn.screenWidth() // 2) 78 | dotInY = dotIn.ypos() + (dotIn.screenHeight() // 2) 79 | dotInP = [dotInX, dotInY] 80 | 81 | dotOutX = dotOut.xpos() + (dotOut.screenWidth() // 2) 82 | dotOutY = dotOut.ypos() + (dotOut.screenHeight() // 2) 83 | dotOutP = [dotOutX, dotOutY] 84 | 85 | # get the current dot position center 86 | dotX = dot.xpos() + (dot.screenWidth() // 2) 87 | dotY = dot.ypos() + (dot.screenHeight() // 2) 88 | dotP = [dotX, dotY] 89 | 90 | # determine where the dot should be 91 | goX = dotInX 92 | goY = dotOutY 93 | goP = [goX, goY] 94 | 95 | # check if the dot is already where it should be, and do also forceXpos check 96 | AlreadyThere = False 97 | if ((dotX == goX and dotY == goY) or (forceXpos != -.1 and forceXpos != goX)): 98 | AlreadyThere = True 99 | 100 | # if it is, or of the node is at the same position as its input or output node, do the following 101 | if (AlreadyThere or goP == dotInP or goP == dotOutP): 102 | 103 | # check if the dot is further away from the input than from the output node in X 104 | FarOut = False 105 | if (abs(dotX - dotInX) > abs(dotX - dotOutX)): 106 | FarOut = True 107 | 108 | # check if the dot is further away from the input than from the output node in Y or if it is already where it should be 109 | if ((abs(dotY - dotInY) < abs(dotY - dotOutY)) or AlreadyThere): 110 | 111 | # set the desired position to the output node X and the input node Y 112 | goX = dotOutX 113 | goY = dotInY 114 | 115 | # but if that means the dot will be at the same position as it currently is, set it to the input node X and output node Y 116 | if (dotX == goX and dotY == goY): 117 | goX = dotInX 118 | goY = dotOutY 119 | else: 120 | 121 | if (FarOut or AlreadyThere): 122 | goX = dotInX 123 | goY = dotOutY 124 | 125 | 126 | # set dot position X 127 | dot.setXpos(goX - (dot.screenWidth() // 2)) 128 | 129 | # set dot position Y 130 | if SameDotOut: 131 | dot.setYpos(lastDotOut.ypos() - nodeClosestYPos//3) 132 | else: 133 | dot.setYpos(goY - (dot.screenHeight() // 2)) 134 | 135 | 136 | 137 | # on error, ignore 138 | except Exception as e: 139 | pass 140 | 141 | 142 | 143 | 144 | # overall function that decides what needs to happen 145 | def AlignDots(nodes = []): 146 | 147 | # list nodes to work with 148 | dotsToAlign = [] 149 | if nodes == []: 150 | dotsToAlign = nuke.selectedNodes() 151 | else: 152 | dotsToAlign = nodes 153 | 154 | 155 | 156 | # force dots to be on same vertical line (for sidestreams), -.1 means ignore 157 | forceXpos = -.1 158 | 159 | 160 | 161 | # exceptions first: if there is one non-dot node selected, give all of its inputs dots 162 | if len(dotsToAlign) == 1: 163 | 164 | selNode = dotsToAlign[0] 165 | if not selNode.Class() == 'Dot': 166 | 167 | # make list of dots 168 | dots = [] 169 | 170 | # temp list to go through first, then go to dots[] - for nodes that have multiple inputs but still only need 90-degree angles 171 | dotList = [] 172 | 173 | 174 | 175 | # check if input and output are both connected to nodes in the same stream (to make dots on top and bottom of node) 176 | nIn = selNode.dependencies() 177 | nOut = selNode.dependent() 178 | sideStream = False 179 | 180 | if len(nIn) == 1 and len(nOut) == 1: 181 | if nIn[0].xpos() + nIn[0].screenWidth()//2 == nOut[0].xpos() + nOut[0].screenWidth()//2: 182 | sideStream = True 183 | 184 | if sideStream: 185 | 186 | # make dots 187 | newDotIn = nuke.nodes.Dot() 188 | newDotOut = nuke.nodes.Dot() 189 | 190 | # connect 191 | newDotIn.setInput(0, nIn[0]) 192 | selNode.setInput(0, newDotIn) 193 | 194 | newDotOut.setInput(0, selNode) 195 | 196 | # check which input of nOut is connected to this node 197 | for eachIn in range(nOut[0].inputs()): 198 | if(nOut[0].input(eachIn) == selNode): 199 | inputI = eachIn 200 | nOut[0].setInput(eachIn, newDotOut) 201 | 202 | 203 | dots.append(newDotIn) 204 | dots.append(newDotOut) 205 | 206 | # select new dot 207 | newDotIn['selected'].setValue(True) 208 | newDotOut['selected'].setValue(True) 209 | 210 | forceXpos = selNode.xpos() + selNode.screenWidth()//2 211 | 212 | 213 | 214 | # if not a sidestream, do a per-input dot connect 215 | else: 216 | 217 | # get all of its inputs 218 | for inp in range(selNode.inputs()): 219 | 220 | currInput = selNode.input(inp) 221 | 222 | # only proceed if input is connected (for instance, Merge nodes can have A3 empty but A4 connected) 223 | if currInput is not None: 224 | 225 | # only proceed if node is not already at a 90-degree angle 226 | if (currInput.ypos() + currInput.screenHeight()//2) != (dotsToAlign[0].ypos() + dotsToAlign[0].screenHeight()//2): 227 | 228 | # add to temp list 229 | dotList.append([inp, selNode.input(inp)]) 230 | 231 | 232 | 233 | # check if only one dot can be put in 90-degree angle instead, for instance when merging with main stream 234 | if len(dotList) == 2: 235 | 236 | first = False 237 | second = False 238 | 239 | # check first input 240 | if (selNode.input(dotList[0][0]).xpos() + selNode.input(dotList[0][0]).screenWidth()//2) == (selNode.xpos() + selNode.screenWidth()//2): 241 | first = True 242 | 243 | if (selNode.input(dotList[1][0]).xpos() + selNode.input(dotList[1][0]).screenWidth()//2) == (selNode.xpos() + selNode.screenWidth()//2): 244 | second = True 245 | 246 | 247 | # only allow the second dot to be made 248 | if first and not second: 249 | dotList = [dotList[1]] 250 | 251 | # only allow the first dot to be made 252 | if second and not first: 253 | dotList = [dotList[0]] 254 | 255 | 256 | 257 | for newDots in dotList: 258 | 259 | # make dot 260 | newDot = nuke.nodes.Dot() 261 | 262 | # connect 263 | newDot.setInput(0, newDots[1]) 264 | selNode.setInput(newDots[0], newDot) 265 | 266 | dots.append(newDot) 267 | 268 | # select new dot 269 | newDot['selected'].setValue(True) 270 | 271 | 272 | 273 | 274 | # select new dot, deselect originally selected node 275 | selNode['selected'].setValue(False) 276 | 277 | # place all in corner 278 | PlaceInCorner(dots, forceXpos) 279 | 280 | 281 | 282 | # one node selected, but it's a dot 283 | else: 284 | PlaceInCorner(dotsToAlign) 285 | 286 | 287 | 288 | # if not, go through all selected nodes and place dots in corner 289 | else: 290 | PlaceInCorner(dotsToAlign) 291 | 292 | def setNodePosition(toNode, aboutNode, pos='bot', dist=6, offset=[0, 0]): 293 | x1, y1 = toNode.xpos(), toNode.ypos() 294 | w1, h1 = toNode.screenWidth(), toNode.screenHeight() 295 | 296 | x2, y2 = aboutNode.xpos(), aboutNode.ypos() 297 | w2, h2 = aboutNode.screenWidth(), aboutNode.screenHeight() 298 | 299 | if pos == "bot": 300 | toNode.setXpos(x2 + w2//2 - w1//2 + offset[0]) 301 | toNode.setYpos(y2 + h2 + dist + offset[1]) 302 | elif pos == 'right': 303 | toNode.setXpos(x2 + w2 + dist + offset[0]) 304 | toNode.setYpos(y2 + h2//2 - h1//2 + offset[1]) 305 | elif pos == 'left': 306 | toNode.setXpos(x2 - w2 - dist + offset[0]) 307 | toNode.setYpos(y2 + h2//2 - h1//2 + offset[1]) 308 | elif pos == 'top': 309 | toNode.setXpos(x2 + w2//2 - w1//2 + offset[0]) 310 | toNode.setYpos(y2 - h1 - dist + offset[1]) 311 | elif pos == 'center': 312 | toNode.setXpos(x2 + w2//2 - w1//2 + offset[0]) 313 | toNode.setYpos(y2 + h2//2 - h1//2 + offset[1]) 314 | elif pos == 'default': 315 | toNode.setXpos(x2 + offset) 316 | toNode.setYpos(y2 + offset) 317 | 318 | def get_list_of_nodes_in_right_order(): 319 | temp_dict = {} 320 | for node in nuke.selectedNodes(): 321 | temp_dict[node] = node.xpos() 322 | temp_dict = {k: v for k, v in sorted(temp_dict.items(), key=lambda item: item[1])} 323 | return [k for k in temp_dict] 324 | 325 | def set_nodes_position(nodes): 326 | start_x = nodes[0].xpos() 327 | start_y = nodes[0].ypos() 328 | temp_x = start_x 329 | for node in nodes: 330 | if node == nodes[0]: continue 331 | node.setXpos(temp_x + 200) 332 | node.setYpos(start_y) 333 | temp_x += 200 334 | 335 | def create_channel_merges(nodes): 336 | # reverse read list 337 | final_read = nodes[::-1] 338 | 339 | # create ChannelMerges list 340 | cms = [] 341 | # create Dots list 342 | dots = [] 343 | # position var 344 | p = 200 345 | # counter for ChannelMerges 346 | i = 0 347 | # counter for Dots 348 | d = 0 349 | 350 | for n in range(0, len(final_read)-1): 351 | # Create ChannelMerge and Dot 352 | cm = nuke.nodes.Merge2() 353 | dot = nuke.nodes.Dot() 354 | 355 | # Set positions 356 | cm.setXYpos(final_read[0].xpos(), final_read[0].ypos() + p) 357 | setNodePosition(dot, final_read[d+1], 'bot') 358 | 359 | # Set inputs 360 | if len(cms) == 0: 361 | cm.setInput(0, final_read[0]) 362 | cm.setInput(1, dot) 363 | dot.setInput(0, final_read[1]) 364 | else: 365 | cm.setInput(0, cms[i]) 366 | cm.setInput(1, dot) 367 | dot.setInput(0, final_read[i+2]) 368 | i += 1 369 | 370 | # Append to list CM and Dot 371 | cms.append(cm) 372 | dots.append(dot) 373 | 374 | # Up 375 | p += 50 376 | d += 1 377 | 378 | for x in nuke.selectedNodes(): 379 | x.setSelected(False) 380 | 381 | for d in dots: 382 | d.setSelected(True) 383 | AlignDots() 384 | 385 | nodes = get_list_of_nodes_in_right_order() 386 | set_nodes_position(nodes) 387 | create_channel_merges(nodes) 388 | --------------------------------------------------------------------------------