No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ChannelSelect.py 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. import fnmatch
  2. import nuke
  3. # martin@keller.io
  4. __version__ = '1.0'
  5. MODES = ['MergeBackIntoStream','SelectOnly', 'ContactSheet']
  6. PATTERNDEFAULT = "*direct* !*indirect* !*default"
  7. INIT_DONE = False
  8. class ChannelSelect(KellerNukePlugin):
  9. def configurePlugin(self):
  10. self.menu = nuke.menu('Nodes')
  11. m = self.menu.addMenu('Workgroup','Toolbar_Workgroup.png')
  12. m.addCommand('ChannelSelect', 'import ChannelSelect; ChannelSelect.createChannelSelect()', icon=':qrc/images/ToolbarChannel.png')
  13. nuke.addKnobChanged(onKnobChanged)
  14. def unconfigurePlugin(self):
  15. self.menu.removeItem('ChannelSelect')
  16. nuke.removeKnobChanged(onKnobChanged)
  17. pass
  18. # events
  19. def onKnobChanged():
  20. global INIT_DONE
  21. if not INIT_DONE:
  22. # not ready
  23. return
  24. k = nuke.thisKnob()
  25. # do a refresh on these knobs
  26. refresh_resolved = ['pattern','update']
  27. if k.name() in refresh_resolved:
  28. print('ChannelSelect: Info. Event refresh triggered.')
  29. # Config changed, loading new tasks
  30. n = nuke.thisNode()
  31. pattern = n['pattern'].value()
  32. resolved = resolvePattern(n, pattern)
  33. if resolved:
  34. resString = '\n'.join(resolved)
  35. if not resolved:
  36. n['resolved'].setValue('NO MATCH')
  37. else:
  38. n['resolved'].setValue(resString)
  39. pass
  40. def createChannelSelect():
  41. # get selected Node (for connecting our node below)
  42. try:
  43. s = nuke.selectedNode()
  44. except:
  45. s = None
  46. # deselect all Nodes
  47. for a in nuke.allNodes():
  48. a.knob('selected').setValue(False)
  49. # create Group
  50. n = nuke.collapseToGroup(show = False)
  51. n.setName('ChannelSelect')
  52. # % (r * 255, g * 255, b * 255, 1), 16): change r g and b to your liking
  53. hexColour = int('%02x%02x%02x%02x' % (0 * 255, 0 * 255, 0 * 255, 1), 16)
  54. n['tile_color'].setValue(hexColour)
  55. if s is not None:
  56. n.setInput(0, s)
  57. n.setXYpos(s.xpos(), s.ypos() + 100)
  58. # tab ChannelSelect
  59. k = nuke.Tab_Knob('select', 'Select')
  60. n.addKnob(k)
  61. # Pattern
  62. k = nuke.EvalString_Knob('pattern', 'Pattern')
  63. n.addKnob(k)
  64. n.knob('pattern').setTooltip('*diffuse* *SSS*\nwith exclude (! or ^):\n*direct* !*indirect*')
  65. n.knob('pattern').setValue(PATTERNDEFAULT)
  66. # Update
  67. k = nuke.PyScript_Knob('update', 'Set', 'ChannelSelect.updatePattern(nuke.thisNode())')
  68. n.addKnob(k)
  69. n.knob('update').setTooltip('Creates Nodes in Group based on Search Pattern')
  70. # Resolved Channels
  71. k = nuke.Multiline_Eval_String_Knob('resolved', 'Resolved')
  72. n.addKnob(k)
  73. n.knob('resolved').setTooltip('These AOVs are found based on your search Pattern above')
  74. # Divide and Conquer
  75. k = nuke.Text_Knob('divider', '')
  76. n.addKnob(k)
  77. # Exposure
  78. k = nuke.Double_Knob('exposure', 'Exposure')
  79. n.addKnob(k)
  80. n.knob('exposure').setRange(-2,2)
  81. # Multiply
  82. k = nuke.Color_Knob('multiply', 'Multiply')
  83. n.addKnob(k)
  84. n.knob('multiply').setValue([1, 1, 1])
  85. # Gamma
  86. k = nuke.Double_Knob('gamma', 'Gamma')
  87. n.addKnob(k)
  88. n.knob('gamma').setValue(1)
  89. n.knob('gamma').setRange(0.2, 2)
  90. # Compensate Mult
  91. k = nuke.Boolean_Knob('compensate', 'Compensate Mult')
  92. n.addKnob(k)
  93. n.knob('compensate').setValue(True)
  94. n.knob('compensate').setFlag(nuke.STARTLINE)
  95. # Reset Values
  96. k = nuke.PyScript_Knob('reset', 'Reset', 'ChannelSelect.resetValues(nuke.thisNode())')
  97. n.addKnob(k)
  98. n.knob('reset').setTooltip('Reset Color Correct values')
  99. n.knob('reset').setFlag(nuke.STARTLINE)
  100. # Divide and Conquer
  101. k = nuke.Text_Knob('divider', '')
  102. n.addKnob(k)
  103. # Mode
  104. k = nuke.Enumeration_Knob('mode', 'Mode', MODES)
  105. n.addKnob(k)
  106. k.setTooltip('MergeBackIntoStream: Shuffles the resolved aovs, applies the grading options and merges the result back to main comp stream\n\nSelectOnly: Just shuffles the resolved aovs and adds them together.\n\nLayerContactSheet: Displays the LayerContactSheet with layer names. Note. You need to Press Set in order for this to work. An empty Pattern is possible')
  107. n.knob('mode').clearFlag(nuke.STARTLINE)
  108. # refresh again
  109. n.knob('pattern').setValue('*key*')
  110. n.knob('pattern').setValue(PATTERNDEFAULT)
  111. global INIT_DONE
  112. INIT_DONE = True
  113. return None
  114. def resetValues(n):
  115. n['exposure'].setValue(0)
  116. n['multiply'].setValue([1, 1, 1])
  117. n['gamma'].setValue(1)
  118. n['compensate'].setValue(True)
  119. def resolvePattern(n, pattern):
  120. if pattern == "":
  121. return None
  122. channels = n.channels()
  123. layers = list(set([c.split('.')[0] for c in channels]))
  124. layers.sort()
  125. matchChannels = []
  126. ignoreChannels = []
  127. for p in pattern.split(' '):
  128. matchChannels += (fnmatch.filter(layers, p))
  129. # excludes
  130. if p[0] == '!' or p[0] == '^':
  131. ignoreChannels += (fnmatch.filter(layers, p[1:]))
  132. matchChannels = list(set(matchChannels) - set(ignoreChannels))
  133. matchChannels.sort()
  134. return matchChannels
  135. def updatePattern(n):
  136. V_OFFSET = 250
  137. # n = node
  138. pattern = n['pattern'].value()
  139. resolved = resolvePattern(n, pattern)
  140. # create nodes
  141. # input and output of Group
  142. input = nuke.toNode('Input1')
  143. output = nuke.toNode('Output1')
  144. # delete old nodes
  145. g = nuke.toNode(n.name())
  146. oldNodes = [i for i in g.nodes() if '__' in i['name'].value()]
  147. for node in oldNodes:
  148. nuke.delete(node)
  149. # dot input
  150. dot_input = nuke.nodes.Dot(xpos=input.xpos() , ypos=input.ypos()+100)
  151. dot_input['name'].setValue('dot_input__')
  152. dot_input['label'].setValue('[value name]')
  153. #dot_input['note_font_size'].setValue(25)
  154. # connect to the input1 node
  155. # dot input 2
  156. dot_input2 = nuke.nodes.Dot(xpos=dot_input.xpos()+1500 , ypos=dot_input.ypos())
  157. dot_input2['name'].setValue('dot_input2__')
  158. dot_input2['label'].setValue('[value name]')
  159. #dot_input2['note_font_size'].setValue(25)
  160. # connect to the input1 node
  161. # dot resolved
  162. dot_resolved = nuke.nodes.Dot(xpos=dot_input.xpos() , ypos=dot_input.ypos() + V_OFFSET)
  163. dot_resolved['name'].setValue('dot_resolved__')
  164. dot_resolved['label'].setValue('[value name]')
  165. #dot_resolved['note_font_size'].setValue(25)
  166. # dot resolved2
  167. dot_resolved2 = nuke.nodes.Dot(xpos=dot_resolved.xpos() - 100, ypos=dot_resolved.ypos())
  168. dot_resolved2['name'].setValue('dot_resolved2__')
  169. dot_resolved2['label'].setValue('[value name]')
  170. #dot_resolved2['note_font_size'].setValue(25)
  171. # dot resolved3
  172. dot_resolved3 = nuke.nodes.Dot(xpos=dot_resolved2.xpos(), ypos=dot_resolved.ypos() + V_OFFSET)
  173. dot_resolved3['name'].setValue('dot_resolved3__')
  174. dot_resolved3['label'].setValue('[value name]')
  175. #dot_resolved3['note_font_size'].setValue(25)
  176. # merge from
  177. merge_from = nuke.nodes.Merge2(xpos=dot_input.xpos()+500 , ypos=dot_input.ypos() )
  178. merge_from['name'].setValue('merge_from__')
  179. merge_from['operation'].setValue("from")
  180. # exposure
  181. exposure = nuke.nodes.EXPTool(xpos=dot_resolved.xpos() , ypos=dot_resolved.ypos() + V_OFFSET)
  182. exposure['name'].setValue('exposure__')
  183. # grade
  184. grade = nuke.nodes.Grade(xpos=exposure.xpos() , ypos=exposure.ypos() + V_OFFSET)
  185. grade['name'].setValue('grade__')
  186. # merge plus
  187. merge_plus = nuke.nodes.Merge2(xpos=grade.xpos() , ypos=grade.ypos() + V_OFFSET)
  188. merge_plus['operation'].setValue("plus")
  189. merge_plus['name'].setValue('merge_plus__')
  190. # dot input From
  191. dot_input_from = nuke.nodes.Dot(xpos=merge_from.xpos() , ypos=merge_plus.ypos())
  192. dot_input_from['name'].setValue('dot_input_from__')
  193. dot_input_from['label'].setValue('[value name]')
  194. #dot_input_from['note_font_size'].setValue(25)
  195. # contact_sheet_all
  196. contact_sheet_all = nuke.nodes.LayerContactSheet(xpos=merge_plus.xpos() +250 , ypos=merge_plus.ypos() + 200)
  197. contact_sheet_all['name'].setValue('contact_sheet__')
  198. # switch
  199. switch = nuke.nodes.Switch(xpos=merge_plus.xpos() , ypos=merge_plus.ypos() + V_OFFSET)
  200. switch['name'].setValue('switch__')
  201. # dot output
  202. dot_output = nuke.nodes.Dot(xpos=dot_input.xpos() , ypos=dot_input.ypos() + V_OFFSET)
  203. dot_output['name'].setValue('dot_output__')
  204. dot_output['label'].setValue('[value name]')
  205. #dot_output['note_font_size'].setValue(25)
  206. # create new nodes
  207. i = 1
  208. j = 0
  209. offset = 100
  210. merge_resolved = None
  211. if resolved:
  212. if len(resolved) > 0:
  213. for r in resolved:
  214. # shuffle
  215. shuffle = nuke.nodes.Shuffle(xpos=dot_input.xpos() - (len(resolved)/2)*offset + (i * offset), ypos=dot_input.ypos() + offset)
  216. shuffle['in'].setValue(resolved[i - 1])
  217. shuffle['in2'].setValue('rgba')
  218. shuffle['out'].setValue('rgb')
  219. shuffle['name'].setValue('shuffle__' + str(i))
  220. # connect to the dot dot_input
  221. shuffle.setInput(0, dot_input)
  222. # create plus
  223. if i == 1:
  224. merge_resolved = nuke.nodes.Merge2(xpos=dot_input.xpos(), ypos=dot_output.ypos() + 50)
  225. merge_resolved['operation'].setValue("plus")
  226. merge_resolved['name'].setValue("merge_resolved__")
  227. # connect plus
  228. # skip Mask Input
  229. if j==2:
  230. j+=1
  231. # connect input
  232. merge_resolved.setInput(j, shuffle)
  233. # next please
  234. i += 1
  235. j += 1
  236. # connect to the input1 node
  237. dot_resolved.setInput(0, merge_resolved)
  238. else:
  239. # shuffle
  240. shuffle = nuke.nodes.Shuffle(xpos=dot_input.xpos() + (i * offset), ypos=dot_input.ypos() + offset)
  241. # create black in rgb and a
  242. shuffle['in'].setValue('none')
  243. shuffle['in2'].setValue('none')
  244. shuffle['out'].setValue('rgb')
  245. shuffle['name'].setValue('shuffle_empty__')
  246. shuffle.setInput(0, dot_input)
  247. # remove old input connections
  248. #for r in range(output.inputs()):
  249. # output.setInput(r, None)
  250. # connect to the input1 node
  251. dot_resolved.setInput(0, shuffle)
  252. # connect the nodes
  253. dot_input.setInput(0, input)
  254. dot_input2.setInput(0, dot_input)
  255. dot_input_from.setInput(0, merge_from)
  256. dot_resolved2.setInput(0, dot_resolved)
  257. dot_resolved3.setInput(0, dot_resolved2)
  258. merge_plus.setInput(1, grade)
  259. merge_plus.setInput(0, dot_input_from)
  260. grade.setInput(0, exposure)
  261. exposure.setInput(0, dot_resolved)
  262. merge_from.setInput(0, dot_input2)
  263. merge_from.setInput(1, dot_resolved)
  264. contact_sheet_all.setInput(0, dot_input2)
  265. switch.setInput(0, merge_plus)
  266. switch.setInput(1, contact_sheet_all)
  267. switch.setInput(2, dot_resolved3)
  268. dot_output.setInput(0,switch)
  269. output.setInput(0, dot_output)
  270. # link the nodes
  271. exposure['mode'].setValue('Stops')
  272. exposure['gang'].setValue(0)
  273. exposure['red'].setExpression('parent.exposure')
  274. exposure['green'].setExpression('parent.exposure')
  275. exposure['blue'].setExpression('parent.exposure')
  276. # init
  277. grade['multiply'].setValue([1,1,1,1])
  278. grade['multiply'].setExpression('parent.multiply.r',0)
  279. grade['multiply'].setExpression('parent.multiply.g',1)
  280. grade['multiply'].setExpression('parent.multiply.b',2)
  281. grade['multiply'].setValue(1, 3)
  282. # enable Compensate Mult by default
  283. grade['white'].setExpression('parent.compensate == 1 ? 1/((parent.multiply.r+parent.multiply.g+parent.multiply.b)/3) : 1')
  284. grade['gamma'].setExpression('parent.gamma')
  285. contact_sheet_all['width'].setExpression('parent.width')
  286. contact_sheet_all['height'].setExpression('parent.height')
  287. contact_sheet_all['showLayerNames'].setValue(1)
  288. # again. Weird Update Issues
  289. contact_sheet_all['showLayerNames'].setExpression('parent.mode == 0 ? 0 :1')
  290. switch['which'].setExpression('parent.mode == 0 ? 0 :(parent.mode == 1 ? 2 : 1)')
  291. # arrange the nodes
  292. weird_dot_offset = 0
  293. dot_input.setXYpos(input.xpos()+weird_dot_offset, input.ypos() + 100)
  294. if merge_resolved:
  295. merge_resolved.setXYpos(input.xpos(), input.ypos() + 350)
  296. dot_resolved.setXYpos(input.xpos()+weird_dot_offset, input.ypos() + 500)
  297. dot_resolved2.setXYpos(dot_resolved.xpos()-250+weird_dot_offset, dot_resolved.ypos())
  298. dot_resolved3.setXYpos(dot_resolved2.xpos()+weird_dot_offset, dot_resolved2.ypos() + 500)
  299. exposure.setXYpos(dot_resolved.xpos(), dot_resolved.ypos()+150)
  300. grade.setXYpos(exposure.xpos(), exposure.ypos() + 150)
  301. merge_plus.setXYpos(grade.xpos(), grade.ypos() + 150)
  302. switch.setXYpos(merge_plus.xpos(), merge_plus.ypos() + 150)
  303. dot_output.setXYpos(switch.xpos()+weird_dot_offset, switch.ypos() + 150)
  304. output.setXYpos(dot_output.xpos(), dot_output.ypos() + 150)
  305. merge_from.setXYpos(dot_input2.xpos(), dot_resolved.ypos())
  306. dot_input_from.setXYpos(merge_from.xpos()+weird_dot_offset, merge_plus.ypos())
  307. n['label'].setValue('[value pattern]')
  308. return None