def holdFrames ( node, holdRange='all' ): """ Append frameHold node for each frame in range. if holdRange = 'all', the node's frame range is processed. if holdRange = valid frame range string, then range is processed if holdRange is not 'all', and not a valid frame range string, a panel is launched to get a valid range from the user. """ if holdRange == 'all': fr = node.frameRange() else: try: fr = nuke.FrameRange( holdRange ) except: str = nuke.getFramesAndViews( 'Hold Frames', '%s-%sx1' % (node['first'].value(), node['last'].value()) ) if not str: return fr = nuke.FrameRange( str[0] ) newNodes = [] for f in xrange( fr.first(), fr.last()+1, +fr.increment() ): fh = nuke.nodes.FrameHold( first_frame=f, postage_stamp = True ) fh.setInput( 0, node ) newNodes.append( fh ) node['postage_stamp'].setValue(False) return newNodes
def _get_frange(): """Open a dialog to request a Nuke-style frame range Args: N/A Returns: <nuke.FrameRange> Returns a FrameRange object if valid frange is entered, or none. Raises: N/A """ first_frame = int(nuke.numvalue('root.first_frame')) last_frame = int(nuke.numvalue('root.last_frame')) step = 1 default_frange = str(nuke.FrameRange(first_frame, last_frame, step)) frange = nuke.getInput('Enter Frame Range:', default_frange) if not frange: return None else: try: return nuke.FrameRange(frange) except: # TODO: Determine exact exception nuke.message('Invalid frame range') return None
def terminal_render(): parser = argparse.ArgumentParser(description='Render from Nuke to ffmpeg.') parser.add_argument("nuke_script", help="Nuke script to render.") parser.add_argument("-X", "--write", help="Name of the WriteFFMPEG node to render.") parser.add_argument("-F", "--framerange", help="framerange to render. Please specify <start>-<end>.", required=False) parser.add_argument("-o", "--output", help="Output qt to render to. Will use the value of the file knob on the WriteFFMPEG node if not specified.", required=False) args = parser.parse_args() nuke_script = args.nuke_script nuke.scriptOpen(nuke_script) node = nuke.toNode(args.write) node.begin() write = nuke.toNode('write_tmp') if args.framerange and "-" in args.framerange: fr = nuke.FrameRange() fr.setLast(int(args.framerange.split('-')[-1])) fr.setFirst(int(args.framerange.split('-')[0])) else: node_framerange = node['framerange'].getValue() if node_framerange and "-" in node_framerange: fr = nuke.FrameRange() fr.setLast(int(node_framerange.split('-')[-1])) fr.setFirst(int(node_framerange.split('-')[0])) else: fr = node.frameRange() tmpimg = tempfile.mkstemp('.tiff', "ffmpeg_temp_")[1] write['file'].setValue(tmpimg) framerate = node['framerate'].getValue() output = node['file'].getValue() tc = frames_to_tc(fr.first(), framerate) ffmpeg_args = "ffmpeg -hide_banner -loglevel info -y \ -f rawvideo -pixel_format rgb48le -video_size {0}x{1} \ -framerate {2} -i pipe:0 -timecode {3} {4} {5}".format( node.width(), node.height(), framerate, tc, node['ffmpeg_args'].getValue(), output) print(ffmpeg_args) ffproc = subprocess.Popen( shlex.split(ffmpeg_args), stdin=subprocess.PIPE, stdout=subprocess.PIPE ) for i, f in enumerate(fr): nuke.execute(write, f, f) print("Rendering frame \t{0} of {1}".format(i, fr.frames())) img = TIFF.open(tmpimg, mode='r') img = img.read_image() img.tofile(ffproc.stdin) os.remove(tmpimg) result, error = ffproc.communicate()
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 transformstoMatrix(nodes, mode=0): #mode 0 creates a cornerpin node with the extra-matrix on it #mode 1 returns a matrix based on all the transforms fRange = nuke.FrameRange( '%s-%s' % (nuke.root().firstFrame(), nuke.root().lastFrame())) for node in nodes: if node.Class() not in ('Transform', 'CornerPin2D', 'Tracker4', 'Tracker3'): if nuke.GUI: msg = 'Unsupported node type: ' + node.Class( ) + '.\n Selected Node must be Transform, CornerPin, Tracker' nuke.message(msg) else: raise TypeError, 'Unsupported node type.\n Selected Node must be Transform, CornerPin, Tracker' return node.knob('selected').setValue(False) nodes = checkOrdering(nodes) if mode == 0: newCpin = nuke.createNode('CornerPin2D') newCpin['transform_matrix'].setAnimated() frameProgressBar = nuke.ProgressTask('Iterating frames : ') frameProgress = 100.0 / max(1.0, nuke.root().lastFrame()) for f in fRange: if frameProgressBar.isCancelled(): frameProgressBar.setProgress(100) nuke.delete(newCpin) break frameProgressBar.setProgress(int(f * frameProgress)) frameProgressBar.setMessage( str(f) + '/' + str(nuke.root().lastFrame())) mainMatrix = nuke.math.Matrix4() mainMatrix.makeIdentity() f = float(f) for node in nodes: #[::-1]: if node.Class() in ('Transform', 'Tracker4', 'Tracker3'): mainMatrix = mainMatrix * transform2DtoMatrix(f, node) if node.Class() in ('CornerPin2D'): mainMatrix = mainMatrix * cpintomatrix(f, node) if mode == 0: for n in range(0, len(mainMatrix)): newCpin['transform_matrix'].setValueAt(mainMatrix[n], f, n) frameProgressBar.setProgress(int(f * frameProgress)) frameProgressBar.setMessage( str(f) + '/' + str(nuke.root().lastFrame())) if mode == 0: try: newCpin.knob('selected').setValue(True) except: pass if mode == 1: return mainMatrix
def Scan_for_missing_frames(): try: # node = nuke.toNode('_render') node = nuke.selectedNode() file = node.knob('file').getValue() filepath = os.path.dirname(nuke.root().name()) + os.sep + 'Prerenders' + os.sep arr = [] missing = [] i = 0 for img in os.listdir(filepath): n = int(img.split('.')[1]) # n = int(re.search(r'\d+', img).group(0)) arr.append(n) if len(arr) > 1: difference = arr[i] - arr[i-1] if difference > 1: #print(range(arr[i-1]+1, arr[i])) missing.append(range(arr[i-1]+1, arr[i])) i+=1 if len(missing) > 0: string = '' # hyphenate list... i = 1 for span in missing: if len(span) > 2: string = string + str(span[0]) + '-' + str(span[-1]) else: string = string + str(span[0]) if i < len(missing): string = string + ', ' i+=1 if nuke.ask('Found missing frames: ' + string + '\n' + 'Render these frames now?'): ranges = nuke.FrameRanges() for s in string.split(', '): fr = nuke.FrameRange(s) ranges.add(fr) if node.knob('use_limit').getValue == True: node.knob('use_limit').setValue(False) nuke.render(node, ranges) node.knob('use_limit').setValue(True) else: nuke.render(node, ranges) except: raise return nuke.message('Must have a write node selected!') # return nuke.message('Must have a write node named \'_render\' in your network!') # if type(node) == type(nuke.root()): # return nuke.message('Must have a write node selected!') # node.knob('Render').execute() # node.knob('frame_range_string').setValue(string) # tempNode = nuke.createNode('Write') # nuke.render(tempNode, ranges) return nuke.message( 'No Missing frame-ranges found!')
def bakeIt(): #FRAME RANGE timerange = nuke.getFramesAndViews( 'Get Frame Range', '%s-%s' % (nuke.root().firstFrame(), nuke.root().lastFrame())) frange = nuke.FrameRange(timerange[0]) #GETTING MAIN MATRIX for i in frange: knobValue = knob.valueAt(i) for each in range(0, 16): sourceMatrix[each] = knobValue[each] sourceMatrix.transpose() #SCALE MATRIX smatrix = nuke.math.Matrix4(sourceMatrix) smatrix.scaleOnly() #SCALE VALUES scaleX = smatrix[0] scaleY = smatrix[5] scaleZ = smatrix[10] #ROTATION MATRIX rmatrix = nuke.math.Matrix4(sourceMatrix) rmatrix.rotationOnly() rmatrixv = rmatrix.rotationsZXY() #ROTATION VALUES degreeX = math.degrees(rmatrixv[0]) degreeY = math.degrees(rmatrixv[1]) degreeZ = math.degrees(rmatrixv[2]) #TRANSLATION MATRIX tmatrix = nuke.math.Matrix4(sourceMatrix) tmatrix.translationOnly() #TRANSLATION VALUES translateX = tmatrix[12] translateY = tmatrix[13] translateZ = tmatrix[14] #PRINTING print '\ntranslateX: ', 'x=', translateX, '', 'Y=', translateY, '', 'Z=', translateZ print '\nrotate: ', 'x=', degreeX, '', 'y=', degreeY, '', 'z=', degreeZ print '\nscale: ', 'x=', scaleX, '', 'y=', scaleY, '', 'z=', scaleZ #SETTING VALUES for each in (target['translate'], target['rotate'], target['scaling']): each.setAnimated() target['translate'].setValueAt(translateX, i, 0) target['translate'].setValueAt(translateY, i, 1) target['translate'].setValueAt(translateZ, i, 2) target['rotate'].setValueAt(degreeX, i, 0) target['rotate'].setValueAt(degreeY, i, 1) target['rotate'].setValueAt(degreeZ, i, 2) target['scaling'].setValueAt(scaleX, i, 0) target['scaling'].setValueAt(scaleY, i, 1) target['scaling'].setValueAt(scaleZ, i, 2)
def getFrameRange(): '''Open a dialog to request a Nuke-style frame range @return: a frameRange object if a valid frame range is entered None if frame range is invalid or dialog is cancelled ''' firstFrame = int(nuke.numvalue('root.first_frame')) lastFrame = int(nuke.numvalue('root.last_frame')) step = 1 _range = str(nuke.FrameRange(firstFrame, lastFrame, step)) r = nuke.getInput('Enter Frame Range:', _range) try: if not r: return None else: return nuke.FrameRange(r) except: nuke.message('Invalid frame range') return None
def bakeCamFrame(bakeNode): #Get frame range to bake getRange = nuke.getFramesAndViews( "Bake projection curves?", "%s-%s" % (nuke.root().firstFrame(), nuke.root().lastFrame())) if not getRange: return fRange = nuke.FrameRange(getRange[0]) views = getRange[1] bakeCamExpressions(bakeNode, fRange.first(), fRange.last(), fRange.increment(), views)
def getKnobRange(knob): ''' Return a frame range object of the knob's animation range. If the knob has no keyframes the script range is returned args: knob - animated knob ''' allRanges = nuke.FrameRanges() for anim in knob.animations(): if not anim.keys(): #KNOB ONLY HAS EXPRESSION WITHOUT KEYS SO USE SCRIPT RANGE first = nuke.root().firstFrame() last = nuke.root().lastFrame() allRanges.add(nuke.FrameRange(first, last)) else: # GET FIRST FRAME allKeys = anim.keys() allRanges.add(nuke.FrameRange(allKeys[0].x, allKeys[-1].x, 1)) return nuke.FrameRange(allRanges.minFrame(), allRanges.maxFrame(), 1)
def bakeSelectedNodes(): '''bake selected nodes' knobs that carry expressions''' ret = nuke.getFramesAndViews( 'bake curves in selected nodes?', '%s-%s' % (nuke.root().firstFrame(), nuke.root().lastFrame())) if not ret: return fRange = nuke.FrameRange(ret[0]) views = ret[1] for n in nuke.selectedNodes(): bakeExpressionKnobs(n, fRange.first(), fRange.last(), fRange.increment(), views)
def setFrameRange(): ret = nuke.getFramesAndViews('Set Frame Range', '101-1000') getFrame = ret[0] convertFrame = nuke.FrameRange(getFrame) nuke.root().knob('first_frame').setValue(convertFrame.first()) nuke.root().knob('last_frame').setValue(convertFrame.last()) for i in nuke.selectedNodes(): if i.Class() == 'Read': i.knob('first').setValue(convertFrame.first()) i.knob('last').setValue(convertFrame.last()) i.knob('origfirst').setValue(convertFrame.first()) i.knob('origlast').setValue(convertFrame.last())
def getRange(gizmo): ''' getRange(node): This function set a range in order to execute an action to the node. It depends on the gizmo's knob 'tdRangeMode'. If the 'tdRangeMode' is set to 'Custom' it opens a pop-up window where we can set a user range before executing the action. Other range modes could be choose like 'Global' or 'Current'. @param 'gizmo': Must be a Gizmo object Nuke. Created on March 11, 2013 @author: Ryuu ''' #| TESTS |------------------------------------------------------------------------------------- if gizmo != None: if (gizmo.__class__.__name__) != 'Gizmo': tdLogger.printError('td.nuke.gizmos.vertexTracker3D', 'getRange()', "Argument 'node' must be a Gizmo object Nuke") #| VARIABLES |--------------------------------------------------------------------------------- rangeMode = gizmo.knob('tdRangeMode').value() #| EXECUTE |----------------------------------------------------------------------------------- if rangeMode == 'Custom': firstFrame = nuke.root().firstFrame() lastFrame = nuke.root().lastFrame() userInput = nuke.getFramesAndViews('Range', '%s-%s' %(firstFrame, lastFrame)) if not userInput: pass else: views = userInput[1] if views == ['main']: views = ['L', 'R'] userRange = nuke.FrameRange(userInput[0]) userFirstFrame = userRange.first() userLastFrame = userRange.last() userIncrFrame = userRange.increment() execRange(gizmo, userFirstFrame, userLastFrame, userIncrFrame, views) elif rangeMode == 'Global': views = nuke.views() firstFrame = nuke.root().firstFrame() lastFrame = nuke.root().lastFrame() execRange(gizmo, firstFrame, lastFrame, 1, ['L', 'R']) elif rangeMode == 'Current': views = nuke.views() currentFrame = nuke.frame() execRange(gizmo, currentFrame, currentFrame, 1, ['L', 'R'])
def bakeDependentNodes(): '''Add this to onUserDestroy callback - not yet implemented''' parentNode = nuke.thisNode() depNodes = parentNode.dependent(nuke.EXPRESSIONS) ret = nuke.getFramesAndViews( 'bake curves in dependent nodes?', '%s-%s' % (parentNode.firstFrame(), parentNode.lastFrame())) if not ret: return fRange = nuke.FrameRange(ret[0]) views = ret[1] for n in depNodes: bakeExpressionKnobs(n, fRange.first(), fRange.last(), fRange.increment(), views)
def trackCV(): # GET THE SELECTED NODE. SINCE WE PLAN ON CALLING THIS FROM THE PROPERTIES MENU # WE CAN BE SURE THAT THE SELECTED NODE IS ALWAYS THE ONE THE USER CLICKED IN node = nuke.selectedNode() # BAIL OUT IF THE NODE IS NOT WHAT WE NEED if node.Class() not in ('Roto', 'RotoPaint'): nuke.message( 'Unsupported node type. Node must be of class Roto or RotoPaint' ) return p = examples.ShapeAndCVPanel( node ) if p.showModalDialog(): fRange = nuke.FrameRange( p.fRange.value() ) shapeName = p.shape.value() cv = p.cv.value() threading.Thread( None, _cvTracker, args=(node, shapeName, cv, fRange) ).start()
def bakeDependentNodes(): '''Add this to onUserDestroy callback - not yet implemented''' parentNode = nuke.thisNode( ) # THIS IS GIVEN TO US BY THE CALLBACK, i.e. WHEN A NODE IS DELETED - WELL, NOT YET depNodes = parentNode.dependent(nuke.EXPRESSIONS) ret = nuke.getFramesAndViews( 'bake curves in dependent nodes?', '%s-%s' % (parentNode.firstFrame(), parentNode.lastFrame())) if not ret: return fRange = nuke.FrameRange(ret[0]) views = ret[1] for n in depNodes: bakeExpressionKnobs(n, fRange.first(), fRange.last(), fRange.increment(), views)
def pick_stuff_panel(): # 接受用户输入的 路径 和帧数,返回 帧数列表 # if __name__ == "__main__": (p, ret) = _createPannel() # ==get all need frames if not ret: return None copy2Dri = p.value('destination') frms = p.value('frames') frm_splt_comma = frms.split(',') allFrms = [] for ea in frm_splt_comma: if not re.search('-', ea) and ea not in allFrms: allFrms.append(int(ea)) else: frm_rang = nuke.FrameRange(ea) for ea_frm in (range(frm_rang.first(), frm_rang.last() + 1)): if ea_frm not in allFrms: allFrms.append(ea_frm) return {'dir': copy2Dri, 'frms': allFrms}
def render_next(self): if not self.nodes: return node = self.nodes[0] del self.nodes[0] # it's taken, so remove it f = int(node['first'].value()) l = int(node['last'].value()) ranges = nuke.FrameRanges() ranges.add(nuke.FrameRange('%d-%d' % (f,l))) pid = nuke.executeBackgroundNuke(self.path, [node], ranges, ['main'], {}) self.pids[pid] = node.name() self.pids_done[pid] = False self.pids_time[pid] = time.time() print 'Started rendering: %s, pid: %d' % (node.name(), pid)
def trackShape(node=None): ''' Turn a paint stroke or roto shape into an animation path. args: node - Roto or RotoPaint node that holds the required shape ''' # IF NO NODE IS GIVEN, USE THE CURRENTLY SELECTED NODE node = node or nuke.selectedNode() # BAIL OUT IF THE NODE IS NOT WHAT WE NEED if node.Class() not in ('Roto', 'RotoPaint'): if nuke.GUI: nuke.message( 'Unsupported node type. Node must be of class Roto or RotoPaint' ) raise TypeError, 'Unsupported node type. Node must be of class Roto or RotoPaint' # GET THE KNOB THAT HOLDS ALL THE SHAPES AND POP UP A PANEL THAT LISTS STROKES AND SHAPES (NO LAYERS) shPanel = examples.ShapePanel(nuke.selectedNode()) if not shPanel.showModalDialog(): return # GET SHAPE OBJECT BY NAME shapeName = shPanel.elementKnob.value() curveKnob = node['curves'] shape = curveKnob.toElement(shapeName) if isinstance(shape, rp.Stroke): # FOR PAINT STROKES WE JUST EVALUATE AS IS TO GET THE CURVE cubicCurve = shape.evaluate(nuke.frame()) elif isinstance(shape, rp.Shape): # FOR SHAPES WE EVALUATE INDEX "0" WHICH IS THE MAIN CURVE ("1" WOULD BE THE FEATHER CURVE) cubicCurve = shape.evaluate(0, nuke.frame()) # ASK FOR THE DESIRED FRAME RANGE TO DISTRIBUTE THE RESULTING KEYFRAMES OVER fRange = nuke.FrameRange( nuke.getInput( 'Track Range', '%s-%s' % (nuke.root().firstFrame(), nuke.root().lastFrame()))) # CREATE A TRACKER NODE TO HOLD THE DATA tracker = nuke.createNode('Tracker3') tracker['label'].setValue('tracking %s in %s' % (shape.name, node.name())) t = tracker['track1'] t.setAnimated() threading.Thread(None, _pointsToKeys, args=(cubicCurve, t, fRange)).start()
def promptAndBake(): ''' Simple GUI wrapper for the ``bakeExpressions`` function that prompts for an input frame range and view list, and always operates on the selected nodes. ''' nodes = nuke.selectedNodes() if not nodes: nuke.message('No nodes selected') return fr = nuke.getFramesAndViews("Range to Bake", str(nuke.root().frameRange())) if fr is None: return fr, v = fr try: fr = nuke.FrameRange(fr) except ValueError as e: nuke.message(str(e)) return bakeExpressions(nodes=nodes, start=fr.first(), end=fr.last(), views=v)
def snapToPointsAnim(node=None, mode='t'): ''' Animated versions of the three default snapping funtions in the axis menu args: node - node to snap mode - which mode. Available modes are: 't' to match translation, 'tr', to match translation ans rotation, 'trs' to match translation, rotation and scale. default: 't' ''' node = node or nuke.thisNode() if mode not in ('t', 'tr', 'trs'): raise ValueError, 'mode must be "t", "tr" or "trs"' # KNOB MAP knobs = dict(t=['translate'], tr=['translate', 'rotate'], trs=['translate', 'rotate', 'scaling']) # SNAP FUNCTION MAP snapFn = dict(t=nukescripts.snap3d.translateToPoints, tr=nukescripts.snap3d.translateRotateToPoints, trs=nukescripts.snap3d.translateRotateScaleToPoints) # SET REQUIRED KNOBS TO BE ANIMATED for k in knobs[mode]: node[k].clearAnimated() node[k].setAnimated() # GET FRAME RANGE fRange = nuke.getInput( 'Frame Range', '%s-%s' % (nuke.root().firstFrame(), nuke.root().lastFrame())) if not fRange: return # DO THE WORK tmp = nuke.nodes.CurveTool( ) # HACK TO FORCE PROPER UPDATE. THIS SHOULD BE FIXED for f in nuke.FrameRange(fRange): nuke.execute(tmp, f, f) snapFn[mode](node) nuke.delete(tmp) # CLEAN UP THE HACKY BIT
def flipbook_with_audio(node, framesAndViews=None): """Runs an arbitrary command on the images output by a node. This checks to see if the node is a Read or Write and calls the function directly otherwise it creates a temporary Write, executes it, and then calls the command on that temporary Write, then deletes it. By writing your own function you can use this to launch your own flipbook or video-output programs. Specify framesAndViews as a tuple if desired, like so: ("1,5", ["main"]) This can be useful when running without a GUI.""" # Stop here if we're trying to Framecycle in PLE mode, as in some code paths # the execute is called before the Framecycler script could do this check if nuke.env['ple']: raise RuntimeError("Framecycler is not available in PLE mode.") global previous_inrange global previous_userrange global previous_audio if node is None or (node.Class() == "Viewer" and node.inputs() == 0): return a = int(nuke.numvalue(node.name() + ".first_frame")) b = int(nuke.numvalue(node.name() + ".last_frame")) if a >= b: a = int(nuke.numvalue("root.first_frame")) b = int(nuke.numvalue("root.last_frame")) try: inrange = str(nuke.FrameRange(a, b, 1)) except ValueError, e: # In this case we have to extract from the error message the # correct frame range format string representation. # I'm expecting to have a error like: "Frame Range invalid (-1722942,-1722942)" msg = e.__str__() inrange = msg[msg.index("(") + 1:msg.index(")")]
def _tri_render_panel(_list, exceptOnError=True): """ This is copied directly from execute_panel.py with the exception of changing "execute" to "render" but is likely to evolve over time with other rendering-specific options. """ start = int(nuke.numvalue("root.first_frame")) end = int(nuke.numvalue("root.last_frame")) incr = 1 if start < 1: nuke.message("Start frame number cannot be less than 1") return try: _range = str(nuke.FrameRange(start, end, incr)) except ValueError,e: # In this case we have to extract from the error message the # correct frame range format string representation. # I'm expecting to have an error like: "Frame Range invalid (-1722942,-1722942)" msg = e. __str__() _range = msg[msg.index("(")+1: msg.index(")")]
def splitInSequence(f): # a file is a sequence if it is expressed in this way: # filename.####.ext 1-10 # filename_####.ext 1-10 # filename####.ext 1-10 idx = f.find('#') if idx == -1: return [f] # find the sub string that needs to be substituted with the frame number subst = '' for x in range(idx, len(f)): if f[x] != '#': break subst = subst + '#' # split the file name in filename,frange sfile = f.split(' ') # get the frame range try : frame_range = nuke.FrameRange( sfile[1] ) except ValueError: return [f] args = "%(#)0" + str(len(subst)) + "d" sequences = [] for r in frame_range: # replace in filename the pattern #### with the right frame range filename = sfile[0].replace( subst, args % {"#":r} ) sequences.append( filename ) return sequences
def RotoShape_to_Trackers(): rotoNode = nuke.selectedNode() if rotoNode.Class() not in ('Roto', 'RotoPaint'): if nuke.GUI: nuke.message( 'Unsupported node type. Selected Node must be Roto or RotoPaint' ) raise TypeError, 'Unsupported node type. Selected Node must be Roto or RotoPaint' fRange = nuke.FrameRange( nuke.getInput( 'Inform the Frame Range to bake', '%s-%s' % (nuke.root().firstFrame(), nuke.root().lastFrame()))) rotoCurve = rotoNode['curves'] rotoRoot = rotoCurve.rootLayer shapeList = [] shapeList = walker(rotoRoot, shapeList) cancel = False for shape in shapeList: if isinstance(shape[0], nuke.rotopaint.Shape): if cancel: break count = 0 trkList = [] positionsList = [] task = nuke.ProgressTask('Converting Shape(s)\nto Trackers\n') for points in shape[0]: positionsList.append([]) for f in fRange: trker = 0 for points in shape[0]: if task.isCancelled(): cancel = True break if cancel: break point = [ points.center.getPosition(f)[0], points.center.getPosition(f)[1] ] transf = shape[0].getTransform() xy = TransformToMatrix(point, transf, f) xy = TransformLayers(xy, shape[1], f, rotoRoot, shapeList) positionsList[trker].append(xy) trker += 1 trker = 0 if nuke.NUKE_VERSION_MAJOR >= 7: trackNode = nuke.createNode('Tracker4') for pos in positionsList: if task.isCancelled(): cancel = True break if cancel: break if nuke.NUKE_VERSION_MAJOR < 7: trackNode = nuke.createNode('Tracker3', inpanel=False) trackNode.setName("POINT_" + str(trker) + "_" + trackNode.name()) trackNode["track1"].setAnimated(0) trackNode["track1"].setAnimated(1) task.setMessage(shape[0].name + '\nBaking point ' + str(trker + 1) + " of " + str(len(positionsList))) count = 0 for f in fRange: if task.isCancelled(): cancel = True break task.setProgress( int(((float(f) - fRange.first()) + 1 / (fRange.last() - fRange.first() + 1) * 100))) a = trackNode["track1"].animations() a[0].setKey(f, pos[count][0]) a[1].setKey(f, pos[count][1]) count += 1 trker += 1 if nuke.NUKE_VERSION_MAJOR >= 7: k = trackNode['tracks'] #=========================================================== # handy ref is here: http://forums.thefoundry.co.uk/phpBB2/viewtopic.php?t=8130 #=========================================================== numColumns = 31 colTrackX = 2 colTrackY = 3 trackNode["add_track"].execute() trackIdx = trker # 0 for the first track count = 0 for f in fRange: if task.isCancelled(): cancel = True break task.setProgress( int(((float(f) - fRange.first()) + 1 / (fRange.last() - fRange.first() + 1) * 100))) k.setValueAt(pos[count][0], f, numColumns * trackIdx + colTrackX) k.setValueAt(pos[count][1], f, numColumns * trackIdx + colTrackY) count += 1 #=========================================================== # if execution frame is outside the framerange remove the keyframes from it! #=========================================================== if not fRange.isInRange(nuke.frame()): for n in range(numColumns): k.removeKeyAt(nuke.frame(), numColumns * trackIdx + n) trker += 1
def doReduceKeyframes(): p = doReduceKeyframesPanel(nuke.selectedNode()) if p.showModalDialog(): #user did not hit cancel button undo = nuke.Undo() undo.begin("Reduce keyframes") tErrorPercent = p.tErrorPercent.value() if (tErrorPercent > 100): tErrorPercent = 100 if (tErrorPercent < 0.000001): tErrorPercent = 0.000001 #print "tErrorPercent " + str(tErrorPercent) tFrameRange = nuke.FrameRange(p.tFrameRange.value()) tFirstFrame = tFrameRange.first() tLastFrame = tFrameRange.last() knob_names = nuke.animations( ) # Returns the animations names under this knob i = getKnobIndex( ) #find out if user only clicked on a single knob index, or the entire knob #print "knob index: " + str(i) j = 0 #index for knob for knob_name_with_suffix in knob_names: if (i > -1): j = i #print "for knob_name_with_suffix in knob_names:" knob_name = getKnobName(knob_name_with_suffix) # so that we can get at the knob object and do... k = nuke.thisNode()[knob_name] if (k.isAnimated(j)): tOriginalCurve = k.animation(j) tKeys = tOriginalCurve.keys() tOrigFirstFrame = tKeys[0].x tOrigLastFrame = tKeys[len(tKeys) - 1].x tOrigKeys = len(tOriginalCurve.keys()) fErrorHeight = getCurveHeight(tOriginalCurve, tFirstFrame, tLastFrame) tErrorThreshold = fErrorHeight * (tErrorPercent / 100) #print "tErrorThreshold " + str(tErrorThreshold) if (tOrigKeys > 2): #no point in reducing a straight line! x = nuke.selectedNode() #create a temp knob to copy new keyframes into tempname = "temp_" + knob_name + str(j) tTempKnob = nuke.Double_Knob(tempname) tTempKnob.setAnimated() tTempKnob.setValueAt(tOriginalCurve.evaluate(tFirstFrame), tFirstFrame) tTempKnob.setValueAt(tOriginalCurve.evaluate(tLastFrame), tLastFrame) tTempCurve = tTempKnob.animation(0) #if we are only reducing keyframes on a smaller frame range, then copy the original keyframes into the other frames if (tFirstFrame > tOrigFirstFrame) | (tLastFrame < tOrigLastFrame): tKeys = x[knob_name].animation(j).keys() tCopyKeys = [] for tKey in tKeys: if ((tKey.x < tFirstFrame) | (tKey.x > tLastFrame)): tCopyKeys.append(tKey) tTempKnob.animation(0).addKey(tCopyKeys) #do a quick check to see if 2 keyframes are enough deltaH = (tLastFrame - tFirstFrame) deltaV = (tTempKnob.getValueAt(tLastFrame) - tTempKnob.getValueAt(tFirstFrame)) tMasterSlope = 90 - getAngle(deltaH, deltaV) if (tMasterSlope < 0): tMasterSlope = tMasterSlope + 360 if (findErrorHeight(tOriginalCurve, tTempCurve, tFirstFrame, tLastFrame, tMasterSlope) < tErrorThreshold): print "Looks like this selection of frames was a straight line. Reduce the error threshold % if it isn't" else: #otherwise we run the keyframe reducing function on the selected frame range recursion = findGreatestErrorFrame( tOriginalCurve, tFirstFrame, tLastFrame, tErrorThreshold, tTempKnob, tTempCurve, 0) #copy our reduced keyframes from the temp knob back into our original knob x[knob_name].copyAnimation(j, tTempKnob.animation(0)) #calculate how much we have reduced number of keyframes tFinalKeys = len(x[knob_name].animation(j).keys()) tReductionPC = int( (float(tFinalKeys) / float(tOrigKeys)) * 100) print knob_name + "[" + str(j) + "] had " + str( tOrigKeys) + " keys reduced to " + str( tFinalKeys) + " keys (" + str(tReductionPC) + "%)" else: print "No animation found in " + knob_name + " index " + str(j) #break the loop if we are only running script on single knob index if (i > -1): break else: j = j + 1 undo.end()
if same_range: inrange = prev_userrange if framesAndViews is None: r = nuke.getFramesAndViews(label = "Frames to flipbook:", default = inrange, \ maxviews = 1) if r is None: return else: r = framesAndViews range_input = r[0] views_input = r[1] prev_userrange = range_input f = nuke.FrameRange(range_input) start = f.first() end = f.last() incr = f.increment() if (start) < 0 or (end < 0): raise RuntimeError( "Flipbook cannot be executed, negative frame range not supported(%s)." % (str(f), )) proxy = nuke.toNode("root").knob("proxy").value() if (node.Class() == "Read" or node.Class() == "Write") and not proxy: try: command(node, start, end, incr, views_input)
#--------------------------------''' Define Frame Range'''--------------------------------- p = nuke.Panel('Rotomatrix') p.addSingleLineInput( 'Frames', '%s-%s' % (nuke.root().firstFrame(), nuke.root().lastFrame())) p.addSingleLineInput('Ref Frame', nuke.frame()) ret = p.show() if (ret): frames = p.value('Frames') ref = int(p.value('Ref Frame')) frame_range = nuke.FrameRange(frames) for n in nuke.selectedNodes(): n["selected"].setValue(False) c = nuke.createNode("Roto") c.setInput(0, None) c.setInput(1, None) c.setInput(2, None) curve = c['curves'] root = curve.rootLayer transform = root.getTransform() for i in frame_range:
def createCam_Cam_MayatoNuke(): try: selectedNode = nuke.selectedNode() nodeName = selectedNode.name() node = nuke.toNode(nodeName) if nuke.getNodeClassName(node) != 'Read': nuke.message('Please select a read Node') print('Please select a read Node') return metaData = node.metadata() reqFields = ['exr/%s' % i for i in ('worldToCamera', 'worldToNDC')] if not set(reqFields).issubset(metaData): nuke.message('no basic matrices for camera found') return else: print('found needed data') imageWidth = metaData['input/width'] imageHeight = metaData['input/height'] aspectRatio = float(imageWidth) / float(imageHeight) hAperture = 36.0 vAperture = hAperture / aspectRatio # get additional stuff first = node.firstFrame() last = node.lastFrame() ret = nuke.getFramesAndViews('Create Camera from Metadata', '%s-%s' % (first, last)) frameRange = nuke.FrameRange(ret[0]) camViews = (ret[1]) for act in camViews: cam = nuke.nodes.Camera(name="Camera %s" % act) #enable animated parameters cam['useMatrix'].setValue(True) cam['haperture'].setValue(hAperture) cam['vaperture'].setValue(vAperture) for k in ('focal', 'matrix', 'win_translate'): cam[k].setAnimated() task = nuke.ProgressTask('Baking camera from meta data in %s' % node.name()) for curTask, frame in enumerate(frameRange): if task.isCancelled(): break task.setMessage('processing frame %s' % frame) #get the data out of the exr header wTC = node.metadata('exr/worldToCamera', frame, act) wTN = node.metadata('exr/worldToNDC', frame, act) #set the lenshiift if additional metadata is available or manage to calculate it from the toNDC matrix #cam['win_translate'].setValue( lensShift, 0 , frame ) # get the focal length out of the worldToNDC Matrix # thats the wip part any ideas ?? worldNDC = wTN lx = (-1 - worldNDC[12] - worldNDC[8]) / worldNDC[0] rx = (1 - worldNDC[12] - worldNDC[8]) / worldNDC[0] by = (-1 - worldNDC[13] - worldNDC[9]) / worldNDC[5] ty = (1 - worldNDC[13] - worldNDC[9]) / worldNDC[5] swW = max(lx, rx) - min(lx, rx) # Screen Window Width swH = max(by, ty) - min(by, ty) # Screen Window Height focal = hAperture / swW cam['focal'].setValueAt(float(focal), frame) # do the matrix math for rotation and translation matrixList = wTC camMatrix = getMetadataMatrix(wTC) flipZ = nuke.math.Matrix4() flipZ.makeIdentity() flipZ.scale(1, 1, -1) transposedMatrix = nuke.math.Matrix4(camMatrix) transposedMatrix.transpose() transposedMatrix = transposedMatrix * flipZ invMatrix = transposedMatrix.inverse() for i in range(0, 16): matrixList[i] = invMatrix[i] for i, v in enumerate(matrixList): cam['matrix'].setValueAt(v, frame, i) # UPDATE PROGRESS BAR task.setProgress( int(float(curTask) / frameRange.frames() * 100)) except: nuke.message('ERROR: Select a EXR from Maya')
def createCam_Cam_VraytoNuke(node): try: mDat = node.metadata() reqFields = [ 'exr/camera%s' % i for i in ('FocalLength', 'Aperture', 'Transform') ] if not set(reqFields).issubset(mDat): nuke.critical( 'No metadata for camera found! Please select a read node with EXR metadata from VRay!' ) return nuke.message( "Creating a camera node based on VRay metadata. This works specifically on VRay data coming from Maya!\n\nIf you get both focal and aperture as they are in the metadata, there's no guarantee your Nuke camera will have the same FOV as the one that rendered the scene (because the render could have been fit to horizontal, to vertical, etc). Nuke always fits to the horizontal aperture. If you set the horizontal aperture as it is in the metadata, then you should use the FOV in the metadata to figure out the correct focal length for Nuke's camera. Or, you could keep the focal as is in the metadata, and change the horizontal_aperture instead. I'll go with the former here. Set the haperture knob as per the metadata, and derive the focal length from the FOV." ) first = node.firstFrame() last = node.lastFrame() ret = nuke.getFramesAndViews('Create Camera from Metadata', '%s-%s' % (first, last)) if ret is None: return fRange = nuke.FrameRange(ret[0]) cam = nuke.createNode('Camera2') cam['useMatrix'].setValue(False) for k in ('focal', 'haperture', 'vaperture', 'translate', 'rotate'): cam[k].setAnimated() task = nuke.ProgressTask('Baking camera from meta data in %s' % node.name()) for curTask, frame in enumerate(fRange): if task.isCancelled(): break task.setMessage('processing frame %s' % frame) hap = node.metadata('exr/cameraAperture', frame) # get horizontal aperture fov = node.metadata('exr/cameraFov', frame) # get camera FOV focal = float(hap) / ( 2.0 * math.tan(math.radians(fov) * 0.5) ) # convert the fov and aperture into focal length width = node.metadata('input/width', frame) height = node.metadata('input/height', frame) aspect = float(width) / float( height) # calulate aspect ratio from width and height vap = float( hap) / aspect # calculate vertical aperture from aspect ratio cam['focal'].setValueAt(float(focal), frame) cam['haperture'].setValueAt(float(hap), frame) cam['vaperture'].setValueAt(float(vap), frame) matrixCamera = node.metadata('exr/cameraTransform', frame) # get camera transform data # create a matrix to shove the original data into matrixCreated = nuke.math.Matrix4() for k, v in enumerate(matrixCamera): matrixCreated[k] = v matrixCreated.rotateX( math.radians(-90) ) # this is needed for VRay, it's a counter clockwise rotation translate = matrixCreated.transform(nuke.math.Vector3( 0, 0, 0)) # get a vector that represents the camera translation rotate = matrixCreated.rotationsZXY( ) # give us xyz rotations from cam matrix (must be converted to degrees) cam['translate'].setValueAt(float(translate.x), frame, 0) cam['translate'].setValueAt(float(translate.y), frame, 1) cam['translate'].setValueAt(float(translate.z), frame, 2) cam['rotate'].setValueAt(float(math.degrees(rotate[0])), frame, 0) cam['rotate'].setValueAt(float(math.degrees(rotate[1])), frame, 1) cam['rotate'].setValueAt(float(math.degrees(rotate[2])), frame, 2) task.setProgress(int(float(curTask) / fRange.frames() * 100)) except: nuke.message('ERROR: Select a EXR from Max / VRay')