def getFrameList(fileKnob, existingFilePaths): ''' Return a list of frames that are part of the sequence that fileKnob is pointing to. If the file path is already in existingFilePaths it will not be included. ''' node = fileKnob.node() originalCacheMode = node['cacheLocal'].value() node['cacheLocal'].setValue('never') frameRange = nuke.FrameRange(node.firstFrame(), node.lastFrame(), 1) outputContext = nuke.OutputContext() frameList = [] # Cycle over views for viewNumber in xrange(outputContext.viewcount()): viewName = outputContext.viewname(viewNumber) # Skip "default" view if viewName not in nuke.views(): continue # Set context to viewNumber outputContext.setView(viewNumber) # Cycle over frame range for frameNumber in frameRange: outputContext.setFrame(frameNumber) filePath = fileKnob.getEvaluatedValue(outputContext) if filePath not in existingFilePaths: frameList.append(filePath) node['cacheLocal'].setValue("always") #########node['cacheLocal'].setValue(originalCacheMode) my fix return frameList
def _addViewKnob(self): oc = nuke.OutputContext() self._views = [oc.viewname(i) for i in xrange(1, oc.viewcount())] if (oc.viewcount() > 2): supportedViews = self._selectedFlipbook().capabilities( )["maximumViews"] if (int(supportedViews) > 1): self._viewSelection = nuke.MultiView_Knob("views", "Views") else: self._viewSelection = nuke.OneView_Knob( "views", "View", self._views) activeView = nuke.activeViewer().view() if activeView == "": activeView = self._views[0] # Retrieve previous view selection or default to selecting all available views previousViews = self._state.getValue( self._viewSelection.name(), " ".join(self._views)).split() # Get the intersection of the previous selection and the available views viewsToRestore = set(self._views).intersection(previousViews) if viewsToRestore: self._viewSelection.setValue(" ".join(viewsToRestore)) else: self._viewSelection.setValue(activeView) self.addKnob(self._viewSelection) self._viewSelection.clearFlag(nuke.NO_MULTIVIEW)
def _addViewKnob(self): """Add knobs for view selection.""" oc = nuke.OutputContext() if (oc.viewcount() > 2): self._viewSelection = nuke.MultiView_Knob("multi_view", "Views") self._viewSelection.fromScript( self._state.get(self._viewSelection, self._getDefaultViews())) self.addKnob(self._viewSelection) self._viewSelection.clearFlag(nuke.NO_MULTIVIEW)
def _performCleanup(self): """ Remove temporary files created by a previous capture. """ outputContext = nuke.OutputContext() fileKnob = self._viewer['file'] frameList = self._frameRange.toFrameList() for frame in frameList: outputContext.setFrame(frame) fileName = fileKnob.getEvaluatedValue(outputContext) if os.access(fileName, os.F_OK): os.remove(fileName)
def get_matrix_at_frame(node, frame): """ Calculate a matrix for a Transform, Tracker4 or CornerPin2D node at a given frame :param nuke.Node node: Node to extract the matrix from :param int frame: Frame number :return: a 4x4 matrix """ matrix = None if node.Class() == 'Transform' or node.Class() == 'Tracker4': k = node.knob('matrix') context = nuke.OutputContext() context.setFrame(frame) matrix = k.value(context) elif node.Class() == 'CornerPin2D': # Calculate 'to' matrix to_matrix = nuke.math.Matrix4() to1x = node['to1'].getValueAt(frame)[0] to1y = node['to1'].getValueAt(frame)[1] to2x = node['to2'].getValueAt(frame)[0] to2y = node['to2'].getValueAt(frame)[1] to3x = node['to3'].getValueAt(frame)[0] to3y = node['to3'].getValueAt(frame)[1] to4x = node['to4'].getValueAt(frame)[0] to4y = node['to4'].getValueAt(frame)[1] to_matrix.mapUnitSquareToQuad(to1x, to1y, to2x, to2y, to3x, to3y, to4x, to4y) # Calculate 'from' matrix from_matrix = nuke.math.Matrix4() from1x = node['from1'].getValueAt(frame)[0] from1y = node['from1'].getValueAt(frame)[1] from2x = node['from2'].getValueAt(frame)[0] from2y = node['from2'].getValueAt(frame)[1] from3x = node['from3'].getValueAt(frame)[0] from3y = node['from3'].getValueAt(frame)[1] from4x = node['from4'].getValueAt(frame)[0] from4y = node['from4'].getValueAt(frame)[1] from_matrix.mapUnitSquareToQuad(from1x, from1y, from2x, from2y, from3x, from3y, from4x, from4y) # Calculate the extra matrix k = node.knob('transform_matrix') values = k.getValueAt(frame) extra_matrix = nuke.math.Matrix4() for index in range(len(values)): extra_matrix[index] = values[index] extra_matrix.transpose() matrix = extra_matrix * (to_matrix * from_matrix.inverse()) if node['invert'].getValueAt(frame): matrix = matrix.inverse() return matrix
def _addViewKnob(self): oc = nuke.OutputContext() self._views = [oc.viewname(i) for i in xrange(1, oc.viewcount())] if (oc.viewcount() > 2): supportedViews = self._selectedFlipbook().capabilities( )["maximumViews"] if (int(supportedViews) > 1): self._viewSelection = nuke.MultiView_Knob("views", "Views") else: self._viewSelection = nuke.OneView_Knob( "views", "View", self._views) activeView = nuke.activeViewer().view() if activeView == "": activeView = self._views[0] self._state.setKnob(self._viewSelection, activeView) self.addKnob(self._viewSelection) self._viewSelection.clearFlag(nuke.NO_MULTIVIEW)
def get_matrix_at_frame(node, frame): matrix = None if node.Class() == 'Transform' or node.Class() == 'Tracker4': k = node.knob('matrix') context = nuke.OutputContext() context.setFrame(frame) matrix = k.value(context) elif node.Class() == 'CornerPin2D': # Calculate 'to' matrix to_matrix = nuke.math.Matrix4() to1x = node['to1'].getValueAt(frame)[0] to1y = node['to1'].getValueAt(frame)[1] to2x = node['to2'].getValueAt(frame)[0] to2y = node['to2'].getValueAt(frame)[1] to3x = node['to3'].getValueAt(frame)[0] to3y = node['to3'].getValueAt(frame)[1] to4x = node['to4'].getValueAt(frame)[0] to4y = node['to4'].getValueAt(frame)[1] to_matrix.mapUnitSquareToQuad(to1x, to1y, to2x, to2y, to3x, to3y, to4x, to4y) # Calculate 'to' matrix from_matrix = nuke.math.Matrix4() from1x = node['from1'].getValueAt(frame)[0] from1y = node['from1'].getValueAt(frame)[1] from2x = node['from2'].getValueAt(frame)[0] from2y = node['from2'].getValueAt(frame)[1] from3x = node['from3'].getValueAt(frame)[0] from3y = node['from3'].getValueAt(frame)[1] from4x = node['from4'].getValueAt(frame)[0] from4y = node['from4'].getValueAt(frame)[1] from_matrix.mapUnitSquareToQuad(from1x, from1y, from2x, from2y, from3x, from3y, from4x, from4y) # Calculate the extra matrix k = node.knob('transform_matrix') values = k.getValueAt(frame) extra_matrix = nuke.math.Matrix4() for i in xrange(len(values)): extra_matrix[i] = values[i] extra_matrix.transpose() matrix = extra_matrix * (to_matrix * from_matrix.inverse()) if node['invert'].getValueAt(frame): matrix = matrix.inverse() return matrix
def _selectedViews(self): try: return self._viewSelection.value().split() except AttributeError: # If we didn't add the view selection knob, there should be just the one view. return [nuke.OutputContext().viewname(1)]
def _getDefaultViews(self): oc = nuke.OutputContext() allViews = [oc.viewname(i) for i in xrange(1, oc.viewcount())] return " ".join(allViews)
def __init__(self, afnode, wnode, subblock, prefix, fparams): if VERBOSE == 2: print('Initializing block parameters for "%s"' % wnode.name()) self.wnode = wnode self.valid = True self.subblock = subblock self.prefix = prefix self.framefirst = nuke.root().firstFrame() self.framelast = nuke.root().lastFrame() self.frameinc = 1 self.framespertask = 1 self.framesequential = 1 self.skipexisting = 0 self.maxhosts = -1 self.capacity = -1 self.maxperhost = -1 self.maxruntime = -1 self.hostsmask = None self.hostsmaskexclude = None self.fullrangedepend = 0 self.tmpimage = 1 self.pathsmap = 1 self.imgfiles = [] if afnode is not None: self.framefirst = int(afnode.knob('framefirst').value()) self.framelast = int(afnode.knob('framelast').value()) self.frameinc = int(afnode.knob('frameinc').value()) self.framespertask = int(afnode.knob('framespertask').value()) self.framesequential = int(afnode.knob('framesequential').value()) self.skipexisting = int(afnode.knob('skipexisting').value()) self.maxhosts = int(afnode.knob('maxhosts').value()) self.capacity = int(afnode.knob('capacity').value()) self.maxperhost = int(afnode.knob('maxperhost').value()) self.maxruntime = int(afnode.knob('maxruntime').value()) self.tmpimage = int(afnode.knob('tmpimage').value()) self.pathsmap = int(afnode.knob('pathsmap').value()) self.hostsmask = afnode.knob('hostsmask').value() self.hostsmaskexclude = afnode.knob('hostsmaskexcl').value() if self.skipexisting: self.framespertask = 1 self.writename = str(wnode.fullName()) if wnode.Class() == RenderNodeClassName: afcommon = __import__('afcommon', globals(), locals(), []) # Get images files: if nuke.toNode('root').knob('proxy').value(): fileknob = wnode.knob('proxy') else: fileknob = wnode.knob('file') # Get views: views = wnode.knob('views') if views is not None: views = views.value() if views is None or views == '': views = nuke.views() else: views = views.split(' ') else: views = nuke.views() # Iterate views: for view in views: view = view.strip() if not len(view): continue # skip empty view, may be after split(' ') # Check view exists: if not view in nuke.views(): print('Error: Skipping invalid view: "%s"' % view) continue # if len( self.imgfiles): # self.imgfiles += ';' # Get show files for current view and first and last frames: octx = nuke.OutputContext() octx.setView(1 + nuke.views().index(view)) octx_framefirst = self.framefirst octx_framelast = self.framelast if octx_framefirst < 0: octx_framefirst = 0 if octx_framelast < 0: octx_framelast = 0 # If frame first and frame last are equal no sequence needed if octx_framefirst == octx_framelast: octx.setFrame(octx_framefirst) self.imgfiles.append(fileknob.getEvaluatedValue(octx)) else: # Get files from first and last frames # to calculate frames pattern: octx.setFrame(octx_framefirst) images1 = fileknob.getEvaluatedValue(octx) if images1 is None or images1 == '': nuke.message( 'Error:\n' '%s\n' 'Files are empty.\n' 'View "%s", frame %d.' % (self.writename, view, self.framefirst) ) self.valid = False return octx.setFrame(octx_framelast) images2 = fileknob.getEvaluatedValue(octx) if images2 is None or images2 == '': nuke.message( 'Error:\n' '%s\n' 'Files are empty.\n' 'View "%s", frame %d.' % (self.writename, view, self.framelast) ) self.valid = False return part1, padding, part2 = \ afcommon.splitPathsDifference(images1, images2) if padding < 1: nuke.message( 'Error:\n' '%s\n' 'Invalid files pattern.\n' 'View "%s".' % (self.writename, view) ) self.valid = False return self.imgfiles.append( '%s@%s@%s' % (part1, '#' * padding, part2) ) # Check images folders: for imgfile in self.imgfiles: folder = os.path.dirname(imgfile) if folder != '': if not os.path.isdir(folder): result = nuke.ask( 'Write Node "%s" Directory\n' '%s\n' 'Does not exist.\n' 'Create it?' % (self.writename, folder) ) if result: os.makedirs(folder) if not os.path.isdir(folder): nuke.message( "Can't create folder:\n%s" % folder ) self.valid = False else: self.valid = False elif wnode.Class() == DailiesNodeClassName: if VERBOSE: print('Generating dailies "%s"' % self.writename) else: nuke.message('Node type\n"%s"\nis unsendable.' % self.writename) self.valid = False for par in fparams: if fparams[par] is not None: if hasattr(self, par): setattr(self, par, fparams[par]) self.name = self.writename if subblock: if self.prefix is not None: if self.prefix != '': self.name = self.prefix + self.name self.dependmask = '' self.tasksdependmask = ''
def dailiesGenCmd(node): # Process Input Node: inputnode = None for i in range(node.inputs()): inputnode = node.input(i) if inputnode is None: nuke.message('Error:\n' '%s\n' 'Not connected to Read or Write node.' % node.name()) return if not inputnode.Class() in ['Read', 'Write']: nuke.message('Error:\n' '%s\n' 'Connected not to Read or Write node.' % node.name()) return # Process Images: images = '' root_frame_first = nuke.Root().firstFrame() root_frame_last = nuke.Root().lastFrame() if root_frame_first == root_frame_last: root_frame_last += 100 # Get needed views from dailies node if forced: if node.knob('forceviews').value(): views = node.knob('viewsnames').value().split(' ') else: # Get needed views write node: views_knob = inputnode.knob('views') if views_knob is not None: views = inputnode.knob('views').value().split(' ') else: # Get all scene views: views = nuke.views() # Generate input pattern from each view: for view in views: if not len(view): continue # skip empty view, may be after split(' ') if not view in nuke.views(): print('Error: Skipping invalid view: "%s"' % view) continue octx = nuke.OutputContext() octx.setView(1 + nuke.views().index(view)) octx.setFrame(root_frame_first) images1 = inputnode.knob('file').getEvaluatedValue(octx) if images1 is None or images1 == '': nuke.message('Error:\n' '%s\n' 'Files are empty.\n' 'View "%s", frame %d.' % (inputnode.name(), view, root_frame_first)) return octx.setFrame(root_frame_last) images2 = inputnode.knob('file').getEvaluatedValue(octx) if images2 is None or images2 == '': nuke.message('Error:\n' '%s\n' 'Files are empty.\n' 'View "%s", frame %d.' % (inputnode.name(), view, root_frame_last)) return part1, padding, part2 = afcommon.splitPathsDifference(images1, images2) if padding < 1: nuke.message('Error:\n' '%s\Invalid files pattern.\n' 'View "%s".' % (inputnode.name(), view)) return if len(images): images += ' ' images += '%s%s%s' % (part1, '#' * padding, part2) if images == '': nuke.message('Error:\n%s\No valid views found.' % inputnode.name()) return # Get Movie Name: movname = node.knob('movname').value() if movname is None or movname == '': nuke.message('Error:\n%s\nMovie name is not set.' % node.name()) return # Get Movie Folder: movfolder = node.knob('movfolder').getEvaluatedValue() if movfolder is None or movfolder == '': nuke.message('Error:\n%s\nMovie folder is not set.' % node.name()) return # Get Parameters: format = node.knob('format').value() fps = node.knob('fps').value() codec = node.knob('codec').value() template = node.knob('template').getEvaluatedValue() slate = node.knob('slate').getEvaluatedValue() company = node.knob('company').value() project = node.knob('project').value() shot = node.knob('shot').value() version = node.knob('version').value() artist = node.knob('artist').value() activity = node.knob('activity').value() comments = node.knob('comments').value() cach_op = node.knob('cach_op').value() line_clr = node.knob('line_clr').value() draw169 = node.knob('draw169').value() draw235 = node.knob('draw235').value() line169 = node.knob('line169').value() line235 = node.knob('line235').value() lgspath = node.knob('lgspath').getEvaluatedValue() lgfpath = node.knob('lgfpath').getEvaluatedValue() lgsgrav = node.knob('lgsgrav').value() lgfgrav = node.knob('lgfgrav').value() lgssize = int(node.knob('lgssize').value()) lgfsize = int(node.knob('lgfsize').value()) fstart = int(node.knob('fstart').value()) fend = int(node.knob('fend').value()) fffirst = int(node.knob('fffirst').value()) faketime_on = int(node.knob('faketime_on').value()) faketime_str = node.knob('faketime_str').value() encodeonly = node.knob('encodeonly').value() tmpformat = node.knob('tmpformat').value() tmpquality = node.knob('tmpquality').value() autocolorspace = int(node.knob('autocolorspace').value()) asp_in = float(node.knob('asp_in').value()) gamma = float(node.knob('gamma').value()) cach_as = float(node.knob('cach_as').value()) line_as = float(node.knob('line_as').value()) # Command Construction: cmd = os.environ['CGRU_LOCATION'] cmd = os.path.join(cmd, 'utilities') cmd = os.path.join(cmd, 'moviemaker') cmd = os.path.join(cmd, 'makemovie.py') cmd = 'python ' + cmd cmd += ' -f "%s"' % fps cmd += ' -c "%s"' % codec if faketime_on and faketime_str is not None and faketime_str != '': cmd += ' --faketime %d' % \ int(time.mktime(time.strptime(faketime_str, TimeFromat))) if tmpformat is not None and tmpformat != '': cmd += ' --tmpformat "%s"' % tmpformat if tmpquality is not None and tmpquality != '': cmd += ' --tmpquality "%s"' % tmpquality if not autocolorspace: cmd += ' --noautocorr' if gamma != 1.0: cmd += ' -g %03f' % gamma if asp_in > 0.0: cmd += ' --aspect_in %f' % asp_in if fstart != -1: cmd += ' --fs %d' % fstart if fend != -1: cmd += ' --fe %d' % fend if fffirst: cmd += ' --fff' if not encodeonly: cmd += ' -r "%s"' % format if template is not None and template != '': cmd += ' -t "%s"' % template if slate is not None and slate != '': cmd += ' -s "%s"' % slate if company is not None and company != '': cmd += ' --company "%s"' % company if project is not None and project != '': cmd += ' --project "%s"' % project if shot is not None and shot != '': cmd += ' --shot "%s"' % shot if version is not None and version != '': cmd += ' --ver "%s"' % version if artist is not None and artist != '': cmd += ' --artist "%s"' % artist if activity is not None and activity != '': cmd += ' --activity "%s"' % activity if comments is not None and comments != '': cmd += ' --comments "%s"' % comments if draw169 is not None and draw169 != '': cmd += ' --draw169 "%s"' % draw169 if draw235 is not None and draw235 != '': cmd += ' --draw235 "%s"' % draw235 if line169 is not None and line169 != '': cmd += ' --line169 "%s"' % line169 if line235 is not None and line235 != '': cmd += ' --line235 "%s"' % line235 if line_clr is not None and line_clr != '': cmd += ' --line_aspect %f' % line_as cmd += ' --line_color "%s"' % line_clr if cach_op is not None and cach_op != '': cmd += ' --cacher_aspect %f' % cach_as cmd += ' --cacher_opacity "%s"' % cach_op if lgspath is not None and lgspath != '': cmd += ' --lgspath "%s"' % lgspath cmd += ' --lgssize %d' % lgssize cmd += ' --lgsgrav %s' % lgsgrav if lgfpath is not None and lgfpath != '': cmd += ' --lgfpath "%s"' % lgfpath cmd += ' --lgfsize %d' % lgfsize cmd += ' --lgfgrav %s' % lgfgrav if node.knob('stereodub').value(): cmd += ' --stereo' cmd += ' ' + images cmd += ' ' + os.path.join(os.path.abspath(movfolder), movname) return cmd
views_str = None views = [] views_num = 0 try: views_str = writenode['views'].value() print('Views = "%s"' % views_str) for view in views_str.split(' '): view = view.strip() if view != '': if not view in nuke.views(): print('Warning: Skipping invalid view: "%s"' % view) print(parser.str_warning) continue views_num += 1 views.append(view) octx = nuke.OutputContext() octx.setView(1 + nuke.views().index(view)) filename = fileknob.getEvaluatedValue(octx) imagesdirs.append(os.path.dirname(filename)) filenames.append(filename) except: errorExit( 'Can`t process views on "%s" write node:\n' % xnode + str(sys.exc_info()[1]), True) # Check for valid view founded: if views_num < 1: errorExit('Can`t find valid views on "%s" write node.' % xnode, True) # Check for multiview file (stereo EXR) multiview_file = False if views_num > 1:
def _createIntermediateNode(self): """Create a write node to render out the current node so that output may be used for flipbooking.""" flipbooktmp = self._getIntermediatePath() fieldname = "file" if self._useProxy.value(): fieldname = "proxy" fixup = nuke.createNode("Group", "tile_color 0xff000000", inpanel=False) with fixup: fixup.setName("Flipbook") inputNode = nuke.createNode("Input", inpanel=False) shuffle = nuke.createNode("Shuffle", inpanel=False) shuffle.knob("in").setValue(self._channels.value()) if self._useRoi.value(): crop = nuke.createNode("Crop", inpanel=False) crop['box'].fromScript(self._roi.toScript()) write = nuke.createNode("Write", fieldname + " {" + flipbooktmp + "}", inpanel=False) write.knob('file_type').setValue(self._getIntermediateFileType()) selectedViews = self._selectedViews() write.knob('views').fromScript(" ".join(selectedViews)) if self._getIntermediateFileType() == "exr": write.knob('compression').setValue("B44") # Set the 'heroview' to be the first of the selected views. If we don't # do this then then 'heroview' is by default set to be 1 which may not # be a valid view for this clip. The 'heroview' is used as a fallback if # no view has been set on the reader. This assumes the user has selected # sensible views if they haven't then the write may still fail. if len(selectedViews) > 0: firstView = nuke.OutputContext().viewFromName( selectedViews[0]) write.knob('heroview').setValue(firstView) writeColorspace = "" if self._burnInLUT.value(): # The user has chosen to burn the viewer transform into the intermedate render so set the colorspace # on the Write node appropriately. writeColorspace = self._getBurninWriteColorspace() else: # The viewer transform is not being burnt into the intermediate render, set the Write node's colorspace # to whatever the current working space is - when reading the file back in the flipbook we'll ssume # the media was written out in the working space. rootNode = nuke.root() if rootNode: workingSpaceKnob = rootNode.knob("workingSpaceLUT") if workingSpaceKnob: writeColorspace = workingSpaceKnob.value() if writeColorspace: write.knob('colorspace').setValue(writeColorspace) outputNode = nuke.createNode("Output", inpanel=False) #If called on a Viewer connect fixup node to the one immediately above if exists. if self._node.Class() == "Viewer": fixup.setInput( 0, self._node.input( int(nuke.knob(self._node.fullName() + ".input_number")))) else: fixup.setInput(0, self._node) try: # Throws exception on render failure if (self.isBackgrounded()): nuke.executeBackgroundNuke( nuke.EXE_PATH, [write], nuke.FrameRanges(self._frameRange.value().split(',')), self._selectedViews(), self._getBackgroundLimits(), self._continueOnError.value(), self._flipbookEnum.value(), self._getOptions(write)) else: nuke.executeMultiple( (write, ), nuke.FrameRanges(self._frameRange.value().split(',')), self._selectedViews(), self._continueOnError.value()) except RuntimeError, msg: if msg.args[0][0:9] == "Cancelled": splitMsg = string.split(msg.args[0]) msg = """Render did not complete, do you want to show the completed range? Frame range %s contains %s frames but only %s finished.""" % ( self._frameRange.value(), splitMsg[3], splitMsg[1]) if nuke.ask(msg) == False: nuke.delete(fixup) fixup = None else: nuke.delete(fixup) fixup = None nuke.message("Flipbook render failed:\n%s" % (msg.args[0], ))