暫無描述
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 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  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. PATTERNDEFAULT = ""
  8. PATTERNIGNORE = "*variance *denoise* *matte* P N Z rgba albedo"
  9. INIT_DONE = False
  10. class ChannelSelect(KellerNukePlugin):
  11. def configurePlugin(self):
  12. self.menu = nuke.menu('Nodes')
  13. m = self.menu.addMenu('Workgroup','Toolbar_Workgroup.png')
  14. m.addCommand('ChannelSelect', 'import ChannelSelect; ChannelSelect.createChannelSelect()', icon=':qrc/images/ToolbarChannel.png')
  15. nuke.addKnobChanged(onKnobChanged)
  16. nuke.addOnCreate(onCreate, nodeClass=('Group'))
  17. def unconfigurePlugin(self):
  18. self.menu.removeItem('ChannelSelect')
  19. nuke.removeKnobChanged(onKnobChanged)
  20. nuke.removeOnCreate(onCreate)
  21. pass
  22. # events
  23. def onKnobChanged():
  24. global INIT_DONE
  25. if not INIT_DONE:
  26. # not ready
  27. return
  28. k = nuke.thisKnob()
  29. # do a refresh on these knobs
  30. refresh_resolved = ['pattern', 'pattern_exclude', 'update']
  31. if k.name() in refresh_resolved:
  32. print('ChannelSelect: Info. Event refresh triggered.')
  33. # Config changed, loading new tasks
  34. n = nuke.thisNode()
  35. pattern = n['pattern'].value()
  36. pattern_exclude = n['pattern_exclude'].value()
  37. resolved = resolvePattern(n, pattern, pattern_exclude)
  38. if resolved:
  39. resString = '\n'.join(resolved)
  40. if not resolved:
  41. n['resolved'].setValue('NO MATCH')
  42. else:
  43. n['resolved'].setValue(resString)
  44. pass
  45. def onCreate():
  46. print('ChannelSelect: Info. On Create refresh triggered.')
  47. n = nuke.thisNode()
  48. # % (r * 255, g * 255, b * 255, 1), 16): change r g and b to your liking
  49. hexColour = int('%02x%02x%02x%02x' % (0 * 255, 0 * 255, 0 * 255, 1), 16)
  50. n['tile_color'].setValue(hexColour)
  51. def createChannelSelect():
  52. # get selected Node (for connecting our node below)
  53. try:
  54. s = nuke.selectedNode()
  55. except:
  56. s = None
  57. # deselect all Nodes
  58. for a in nuke.allNodes():
  59. a.knob('selected').setValue(False)
  60. # create Group
  61. n = nuke.collapseToGroup(show = False)
  62. n.setName('ChannelSelect')
  63. # % (r * 255, g * 255, b * 255, 1), 16): change r g and b to your liking
  64. hexColour = int('%02x%02x%02x%02x' % (0 * 255, 0 * 255, 0 * 255, 1), 16)
  65. n['tile_color'].setValue(hexColour)
  66. if s is not None:
  67. n.setInput(0, s)
  68. n.setXYpos(s.xpos(), s.ypos() + 100)
  69. # tab ChannelSelect
  70. k = nuke.Tab_Knob('select', 'select')
  71. n.addKnob(k)
  72. # Pattern
  73. k = nuke.EvalString_Knob('pattern', 'pattern')
  74. n.addKnob(k)
  75. n.knob('pattern').setTooltip('*diffuse* *SSS*\nwith exclude (! or ^):\n*direct* !*indirect*')
  76. n.knob('pattern').setValue(PATTERNDEFAULT)
  77. # Update
  78. k = nuke.PyScript_Knob('update', 'Set', 'ChannelSelect.updatePattern(nuke.thisNode())')
  79. n.addKnob(k)
  80. n.knob('update').setTooltip('Creates Nodes in Group based on Search Pattern')
  81. # Pattern
  82. k = nuke.EvalString_Knob('pattern_exclude', 'exclude')
  83. n.addKnob(k)
  84. n.knob('pattern_exclude').setTooltip('always exclude this pattern')
  85. n.knob('pattern_exclude').setValue(PATTERNIGNORE)
  86. # Resolved Channels
  87. k = nuke.Multiline_Eval_String_Knob('resolved', 'preview')
  88. n.addKnob(k)
  89. n.knob('resolved').setTooltip('These AOVs are found based on your search Pattern above. Press Set to use these aovs.')
  90. # Divide and Conquer
  91. k = nuke.Text_Knob('divider1', '')
  92. n.addKnob(k)
  93. # unpremult
  94. k = nuke.Boolean_Knob('unpremult', 'unpremult')
  95. n.addKnob(k)
  96. n.knob('unpremult').setValue(True)
  97. n.knob('unpremult').setFlag(nuke.STARTLINE)
  98. # Divide and Conquer
  99. k = nuke.Text_Knob('divider2', '')
  100. n.addKnob(k)
  101. # Saturation
  102. k = nuke.Double_Knob('saturation', 'saturation')
  103. n.addKnob(k)
  104. n.knob('saturation').setRange(0,1)
  105. n.knob('saturation').setValue(1)
  106. # Divide and Conquer
  107. k = nuke.Text_Knob('divider3', '')
  108. n.addKnob(k)
  109. # Exposure
  110. k = nuke.Double_Knob('exposure', 'exposure')
  111. n.addKnob(k)
  112. n.knob('exposure').setRange(-2,2)
  113. # Divide and Conquer
  114. k = nuke.Text_Knob('divider', '')
  115. n.addKnob(k)
  116. # Blackpoint
  117. k = nuke.Color_Knob('blackpoint', 'blackpoint')
  118. n.addKnob(k)
  119. n.knob('blackpoint').setRange(-1,1)
  120. n.knob('blackpoint').setValue([0, 0, 0])
  121. # Whitepoint
  122. k = nuke.Color_Knob('whitepoint', 'whitepoint')
  123. n.addKnob(k)
  124. n.knob('whitepoint').setRange(0,4)
  125. n.knob('whitepoint').setValue(1)
  126. n.knob('whitepoint').setValue([1, 1, 1])
  127. # Lift
  128. k = nuke.Color_Knob('black', 'lift')
  129. n.addKnob(k)
  130. n.knob('black').setRange(-1,1)
  131. n.knob('black').setValue([0, 0, 0])
  132. # Multiply
  133. k = nuke.Color_Knob('multiply', 'multiply')
  134. n.addKnob(k)
  135. n.knob('multiply').setValue([1, 1, 1])
  136. n.knob('multiply').setRange(0, 4)
  137. # Gamma
  138. k = nuke.Double_Knob('gamma', 'gamma')
  139. n.addKnob(k)
  140. n.knob('gamma').setValue(1)
  141. n.knob('gamma').setRange(0.2, 2)
  142. # Compensate Mult
  143. k = nuke.Boolean_Knob('compensate', 'compensate mult')
  144. n.addKnob(k)
  145. n.knob('compensate').setValue(True)
  146. n.knob('compensate').setFlag(nuke.STARTLINE)
  147. # Reset Values
  148. k = nuke.PyScript_Knob('reset', 'reset', 'ChannelSelect.resetValues(nuke.thisNode())')
  149. n.addKnob(k)
  150. n.knob('reset').setTooltip('Reset Color Correct values')
  151. n.knob('reset').setFlag(nuke.STARTLINE)
  152. # Divide and Conquer
  153. k = nuke.Text_Knob('divider4', '')
  154. n.addKnob(k)
  155. # Mode
  156. k = nuke.Enumeration_Knob('mode', 'mode', MODES)
  157. n.addKnob(k)
  158. 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')
  159. n.knob('mode').clearFlag(nuke.STARTLINE)
  160. # refresh again
  161. n.knob('pattern').setValue('*key*')
  162. n.knob('pattern').setValue(PATTERNDEFAULT)
  163. tmp = n.knob('resolved').getValue()
  164. global INIT_DONE
  165. INIT_DONE = True
  166. return None
  167. def resetValues(n):
  168. n['exposure'].setValue(0)
  169. n['blackpoint'].setValue(0)
  170. n['whitepoint'].setValue(1)
  171. n['saturation'].setValue(1)
  172. n['black'].setValue(0)
  173. n['multiply'].setValue([1, 1, 1])
  174. n['gamma'].setValue(1)
  175. n['compensate'].setValue(True)
  176. def resolvePattern(n, pattern, pattern_exclude):
  177. if pattern == "":
  178. return None
  179. channels = n.channels()
  180. layers = list(set([c.split('.')[0] for c in channels]))
  181. layers.sort()
  182. matchChannels = []
  183. ignoreChannels = []
  184. ignoreChannels2 = []
  185. # pattern
  186. for p in pattern.split(' '):
  187. matchChannels += (fnmatch.filter(layers, p))
  188. # excludes
  189. if p[0] == '!' or p[0] == '^':
  190. ignoreChannels += (fnmatch.filter(layers, p[1:]))
  191. # pattern exclude
  192. for p in pattern_exclude.split(' '):
  193. ignoreChannels2 += (fnmatch.filter(layers, p))
  194. matchChannels = list(set(matchChannels) - set(ignoreChannels) - set(ignoreChannels2))
  195. matchChannels.sort()
  196. return matchChannels
  197. def updatePattern(n):
  198. V_OFFSET = 250
  199. # n = node
  200. pattern = n['pattern'].value()
  201. pattern_exclude = n['pattern_exclude'].value()
  202. resolved = resolvePattern(n, pattern,pattern_exclude)
  203. # create nodes
  204. # input and output of Group
  205. input = nuke.toNode('Input1')
  206. output = nuke.toNode('Output1')
  207. # delete old nodes
  208. g = nuke.toNode(n.name())
  209. #oldNodes = [i for i in g.nodes() if '__' in i['name'].value()]
  210. oldNodes = [i for i in g.nodes() if '__' in i['label'].value()]
  211. for node in oldNodes:
  212. nuke.delete(node)
  213. # dot input
  214. dot_input = nuke.nodes.Dot(xpos=input.xpos() , ypos=input.ypos()+100)
  215. dot_input['name'].setValue('dot_input__')
  216. dot_input['label'].setValue('dot_input__')
  217. #dot_input['note_font_size'].setValue(25)
  218. # connect to the input1 node
  219. # dot input 2
  220. dot_input2 = nuke.nodes.Dot(xpos=dot_input.xpos()+1500 , ypos=dot_input.ypos())
  221. dot_input2['name'].setValue('dot_input2__')
  222. dot_input2['label'].setValue('dot_input2__')
  223. #dot_input2['note_font_size'].setValue(25)
  224. # connect to the input1 node
  225. # unpremult
  226. unpremult = nuke.nodes.Unpremult(xpos=dot_input.xpos()+700 , ypos=dot_input.ypos() )
  227. #unpremult['name'].setValue('unpremult_node__')
  228. unpremult['label'].setValue('unpremult__')
  229. # dot resolved
  230. dot_resolved = nuke.nodes.Dot(xpos=dot_input.xpos() , ypos=dot_input.ypos() + V_OFFSET)
  231. dot_resolved['name'].setValue('dot_resolved__')
  232. dot_resolved['label'].setValue('dot_resolved__')
  233. #dot_resolved['note_font_size'].setValue(25)
  234. # dot resolved2
  235. dot_resolved2 = nuke.nodes.Dot(xpos=dot_resolved.xpos() - 100, ypos=dot_resolved.ypos())
  236. dot_resolved2['name'].setValue('dot_resolved2__')
  237. dot_resolved2['label'].setValue('dot_resolved2__')
  238. #dot_resolved2['note_font_size'].setValue(25)
  239. # dot resolved3
  240. dot_resolved3 = nuke.nodes.Dot(xpos=dot_resolved2.xpos(), ypos=dot_resolved.ypos() + V_OFFSET)
  241. dot_resolved3['name'].setValue('dot_resolved3__')
  242. dot_resolved3['label'].setValue('dot_resolved3__')
  243. #dot_resolved3['note_font_size'].setValue(25)
  244. # merge from
  245. merge_from = nuke.nodes.Merge2(xpos=dot_input.xpos()+500 , ypos=dot_input.ypos() )
  246. merge_from['operation'].setValue('from')
  247. merge_from['name'].setValue('merge_from__')
  248. merge_from['label'].setValue('merge_from__')
  249. # exposure
  250. exposure = nuke.nodes.EXPTool(xpos=dot_resolved.xpos() , ypos=dot_resolved.ypos() + V_OFFSET)
  251. exposure['name'].setValue('exposure__')
  252. exposure['label'].setValue('exposure__')
  253. # grade
  254. grade = nuke.nodes.Grade(xpos=exposure.xpos() , ypos=exposure.ypos() + V_OFFSET)
  255. grade['name'].setValue('grade__')
  256. grade['label'].setValue('grade__')
  257. # saturation
  258. saturation = nuke.nodes.Saturation(xpos=grade.xpos() , ypos=exposure.ypos() + V_OFFSET)
  259. saturation['name'].setValue('saturation__')
  260. saturation['label'].setValue('saturation__')
  261. # merge plus
  262. merge_plus = nuke.nodes.Merge2(xpos=saturation.xpos() , ypos=saturation.ypos() + V_OFFSET)
  263. merge_plus['operation'].setValue("plus")
  264. merge_plus['name'].setValue('merge_plus__')
  265. merge_plus['label'].setValue('merge_plus__')
  266. # dot input From
  267. dot_input_from = nuke.nodes.Dot(xpos=merge_from.xpos() , ypos=merge_plus.ypos())
  268. dot_input_from['name'].setValue('dot_input_from__')
  269. dot_input_from['label'].setValue('dot_input_from__')
  270. #dot_input_from['note_font_size'].setValue(25)
  271. # contact_sheet_all
  272. contact_sheet_all = nuke.nodes.LayerContactSheet(xpos=merge_plus.xpos() +250 , ypos=merge_plus.ypos() + 200)
  273. contact_sheet_all['name'].setValue('contact_sheet__')
  274. contact_sheet_all['label'].setValue('contact_sheet__')
  275. # switch
  276. switch = nuke.nodes.Switch(xpos=merge_plus.xpos() , ypos=merge_plus.ypos() + V_OFFSET)
  277. switch['name'].setValue('switch__')
  278. switch['label'].setValue('switch__')
  279. # premult
  280. premult = nuke.nodes.Premult(xpos=switch.xpos()+50 , ypos=switch.ypos() )
  281. #premult['name'].setValue('premult_node__')
  282. premult['label'].setValue('premult_node__')
  283. # dot output
  284. dot_output = nuke.nodes.Dot(xpos=dot_input.xpos() , ypos=dot_input.ypos() + V_OFFSET)
  285. dot_output['name'].setValue('dot_output__')
  286. dot_output['label'].setValue('dot_output__')
  287. #dot_output['note_font_size'].setValue(25)
  288. # create new nodes
  289. i = 1
  290. j = 0
  291. offset = 100
  292. merge_resolved = None
  293. if resolved:
  294. if len(resolved) > 0:
  295. for r in resolved:
  296. # shuffle
  297. shuffle = nuke.nodes.Shuffle(xpos=dot_input.xpos() - (len(resolved)/2)*offset + (i * offset), ypos=dot_input.ypos() + offset)
  298. shuffle['in'].setValue(resolved[i - 1])
  299. shuffle['in2'].setValue('rgba')
  300. shuffle['out'].setValue('rgb')
  301. shuffle['name'].setValue('shuffle__' + str(i))
  302. # set label of aov
  303. shuffle['label'].setValue(resolved[i - 1] + '__')
  304. # connect to the dot dot_input
  305. shuffle.setInput(0, dot_input)
  306. # create plus
  307. if i == 1:
  308. merge_resolved = nuke.nodes.Merge2(xpos=dot_input.xpos(), ypos=dot_output.ypos() + 50)
  309. merge_resolved['operation'].setValue("plus")
  310. merge_resolved['name'].setValue("merge_resolved__")
  311. merge_resolved['label'].setValue("merge_resolved__")
  312. # connect plus
  313. # skip Mask Input
  314. if j==2:
  315. j+=1
  316. # connect input
  317. merge_resolved.setInput(j, shuffle)
  318. # next please
  319. i += 1
  320. j += 1
  321. # connect to the input1 node
  322. unpremult.setInput(0,merge_resolved)
  323. dot_resolved.setInput(0, unpremult)
  324. else:
  325. # shuffle
  326. shuffle = nuke.nodes.Shuffle(xpos=dot_input.xpos() + (i * offset), ypos=dot_input.ypos() + offset)
  327. # create black in rgb and a
  328. shuffle['in'].setValue('none')
  329. shuffle['in2'].setValue('none')
  330. shuffle['out'].setValue('rgb')
  331. shuffle['name'].setValue('shuffle_empty__')
  332. shuffle['label'].setValue('shuffle_empty__')
  333. shuffle.setInput(0, dot_input)
  334. # remove old input connections
  335. #for r in range(output.inputs()):
  336. # output.setInput(r, None)
  337. # connect to the input1 node
  338. dot_resolved.setInput(0, shuffle)
  339. # connect the nodes
  340. dot_input.setInput(0, input)
  341. dot_input2.setInput(0, dot_input)
  342. dot_input_from.setInput(0, merge_from)
  343. dot_resolved2.setInput(0, dot_resolved)
  344. dot_resolved3.setInput(0, dot_resolved2)
  345. merge_plus.setInput(1, saturation)
  346. merge_plus.setInput(0, dot_input_from)
  347. grade.setInput(0, exposure)
  348. saturation.setInput(0, grade)
  349. exposure.setInput(0, dot_resolved)
  350. merge_from.setInput(0, dot_input2)
  351. merge_from.setInput(1, dot_resolved)
  352. contact_sheet_all.setInput(0, dot_input2)
  353. switch.setInput(0, premult)
  354. switch.setInput(1, contact_sheet_all)
  355. switch.setInput(2, dot_resolved3)
  356. premult.setInput(0,merge_plus)
  357. dot_output.setInput(0,switch)
  358. output.setInput(0, dot_output)
  359. # link the nodes
  360. exposure['mode'].setValue('Stops')
  361. exposure['gang'].setValue(0)
  362. exposure['red'].setExpression('parent.exposure')
  363. exposure['green'].setExpression('parent.exposure')
  364. exposure['blue'].setExpression('parent.exposure')
  365. unpremult['disable'].setExpression('parent.unpremult == 1 ? 0 :1')
  366. premult['disable'].setExpression('parent.unpremult == 1 ? 0 :1')
  367. grade['multiply'].setValue([1,1,1,1])
  368. grade['multiply'].setExpression('parent.multiply.r',0)
  369. grade['multiply'].setExpression('parent.multiply.g',1)
  370. grade['multiply'].setExpression('parent.multiply.b',2)
  371. grade['blackpoint'].setValue([0,0,0,0])
  372. grade['blackpoint'].setExpression('parent.blackpoint.r',0)
  373. grade['blackpoint'].setExpression('parent.blackpoint.g',1)
  374. grade['blackpoint'].setExpression('parent.blackpoint.b',2)
  375. grade['whitepoint'].setValue([1,1,1,1])
  376. grade['whitepoint'].setExpression('parent.whitepoint.r',0)
  377. grade['whitepoint'].setExpression('parent.whitepoint.g',1)
  378. grade['whitepoint'].setExpression('parent.whitepoint.b',2)
  379. grade['black'].setValue([0,0,0,0])
  380. grade['black'].setExpression('parent.black.r',0)
  381. grade['black'].setExpression('parent.black.g',1)
  382. grade['black'].setExpression('parent.black.b',2)
  383. grade['white'].setValue([1, 1, 1, 1])
  384. grade['white'].setExpression('parent.compensate == 1 ? 1/((parent.multiply.r+parent.multiply.g+parent.multiply.b)/3) : 1')
  385. #grade['white'].setExpression(['parent.compensate == 1 ? 1/((parent.multiply.r+parent.multiply.g+parent.multiply.b)/3) : 1,parent.compensate == 1 ? 1/((parent.multiply.r+parent.multiply.g+parent.multiply.b)/3) : 1,parent.compensate == 1 ? 1/((parent.multiply.r+parent.multiply.g+parent.multiply.b)/3) : 1,1'])
  386. grade['gamma'].setExpression('parent.gamma')
  387. saturation['saturation'].setExpression('parent.saturation')
  388. contact_sheet_all['width'].setExpression('parent.width')
  389. contact_sheet_all['height'].setExpression('parent.height')
  390. contact_sheet_all['showLayerNames'].setValue(1)
  391. # again. Weird Update Issues
  392. contact_sheet_all['showLayerNames'].setExpression('parent.mode == 0 ? 0 :1')
  393. switch['which'].setExpression('parent.mode == 0 ? 0 :(parent.mode == 1 ? 2 : 1)')
  394. # arrange the nodes
  395. dot_input.setXYpos(input.xpos(), input.ypos() + 100)
  396. if merge_resolved:
  397. merge_resolved.setXYpos(input.xpos(), input.ypos() + 350)
  398. unpremult.setXYpos(merge_resolved.xpos(), merge_resolved.ypos() + 75)
  399. dot_resolved.setXYpos(input.xpos(), input.ypos() + 500)
  400. dot_resolved2.setXYpos(dot_resolved.xpos()-250, dot_resolved.ypos())
  401. dot_resolved3.setXYpos(dot_resolved2.xpos(), dot_resolved2.ypos() + 500)
  402. exposure.setXYpos(dot_resolved.xpos(), dot_resolved.ypos()+150)
  403. grade.setXYpos(exposure.xpos(), exposure.ypos() + 150)
  404. saturation.setXYpos(grade.xpos(), grade.ypos() + 150)
  405. merge_plus.setXYpos(saturation.xpos(), saturation.ypos() + 150)
  406. premult.setXYpos(merge_plus.xpos(), merge_plus.ypos() + 75)
  407. switch.setXYpos(premult.xpos(), premult.ypos() + 150)
  408. dot_output.setXYpos(switch.xpos(), switch.ypos() + 150)
  409. output.setXYpos(dot_output.xpos(), dot_output.ypos() + 150)
  410. merge_from.setXYpos(dot_input2.xpos(), dot_resolved.ypos())
  411. dot_input_from.setXYpos(merge_from.xpos(), merge_plus.ypos())
  412. n['label'].setValue('[value pattern]')
  413. return None