Scrivi un gestore di rendering per Nuke usando Python

Scopri come scrivere un gestore di rendering personalizzato per Nuke usando Python, permettendoti di eseguire il rendering di uno o più progetti Nuke senza dover aprire il software.

1. Introduzione

Lo scopo di questo tutorial è spiegare come scrivere un software che consente di gestire il processo di rendering in Nuke. Potresti avere diverse compilation Nuke che devono essere renderizzate, quindi usando un programma di questo tipo puoi renderle tutte contemporaneamente senza aprire Nuke stesso, il che significa che il sistema non sta caricando l'interfaccia grafica di Nuke in modo che possa riservare più memoria per il rendering processi. Qui puoi vedere un esempio del programma che stai per costruire:

Interfaccia utente grafica.Il programma che mostra tre progetti.

Il programma ha un'interfaccia utente chiara che ti consente di organizzare e mettere in coda tutti i rendering di cui hai bisogno.

Requisiti

In questo tutorial presumo tu abbia una conoscenza di base di Python e alcuni comandi DOS. Questo software è pensato per essere eseguito sul sistema operativo Windows. Gli strumenti di cui avrai bisogno sono i seguenti:

Python 2.x installato (https://www.python.org) Non utilizzare la versione 3.x perché Nuke non la supporta.

libreria wxPython (http://www.wxpython.org) Ciò consente di creare un'interfaccia utente. Puoi anche usare Tkinter, Qt, ma questo non è trattato in questo tutorial.

Struttura del software

Chiameremo questo software NukeRenderManager. Il programma è composto da tre file:

  • NukeRenderingManager.py

  • exeNuke.bat

  • Rendering.py

NukeRenderingManager.py: contiene tutto ciò che riguarda l'interfaccia utente grafica e tutte le informazioni riguardanti la posizione dei progetti Nuke e tutte le gamme di frame.

exeNuke.bat: è incaricato di avviare Nuke in modalità terminale passando attraverso tutte le informazioni provenienti dal file NukeRenderingManager.py. Questo file viene chiamato per ogni rendering, quindi se è necessario eseguire il rendering di tre compilation Nuke, questo file verrà eseguito tre volte.

Rendering.py: ottiene tutte le informazioni da exeNuke.bat ed esegue il rendering. Questo file viene eseguito per ogni progetto Nuke.

2. Scrittura di NukeRenderingManager.py

Descrizione

NukeRenderingManager.py gestisce l'interfaccia utente e organizza l'elenco dei progetti da rendere.

L'interfaccia utente

Per costruire la nostra interfaccia utente, utilizziamo la libreria wxPython. Come ho detto prima, puoi usare una libreria diversa ma per lo scopo di questo tutorial, spiegherò wxPython. Per installarlo devi solo scaricare il programma di installazione, avviarlo e tutto è pronto (puoi trovare il link sopra). Dopo aver installato la libreria è necessario avviare Python 2.x IDLE e questo ti dà la shell Python. Dal File menu scegli Nuovo file, ora hai un editor vuoto. Se lo desideri, puoi utilizzare qualsiasi altro editor con cui potresti sentirti a tuo agio. 

Editor di Python vuoto.

 Salva il file come NukeRenderingManager.py e mettilo in qualsiasi cartella tu voglia.

La prima cosa da fare è importare i moduli di cui abbiamo bisogno. Il primo è os che ci permette di usare le funzioni del sistema operativo, il secondo è il wx che sarà utile per costruire un'interfaccia utente grafica:

importazione os importazione wx

Creeremo una finestra che contiene tutto ciò di cui abbiamo bisogno, quindi raggiungiamo questo obiettivo creando una classe personalizzata derivata da wx.Frame:

Classe mainWindow (wx.Frame):

Quindi implementiamo il costruttore chiamando il wx.Frame .__ init__:

def __init __ (self): #constructor wx.Frame .__ init __ (self, None, title = "Gestore rendering Nuke", size = (600,300), style = wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX)

Quindi creiamo una barra di stato:

self.CreateStatusBar ()

 Aggiungiamo un controllo testuale per mostrare quali progetti Nuke verranno elaborati:

# preparare l'elenco di script Nuke sullo schermo self.NukeScriptsList = wx.TextCtrl (self, style = wx.TE_MULTILINE) self.NukeScriptsList.SetEditable (False) self.NukeScriptsList.SetBackgroundColour ((120,120,120)) self.NukeScriptsList.SetForegroundColour ((50,255 , 50)) self.NukeScriptsList.SetValue ('Script Nuke: \ n')

Il wx.TextCtrl forniscici un'area in cui possiamo scrivere la lista, ne abbiamo bisogno come multilinea, così dichiariamo wx.TE_MULTILINE. Non abbiamo bisogno che sia modificabile, quindi usiamo SetEditable (Falso), quindi definiamo alcuni colori e finalmente mostriamo un testo.

Quindi creiamo un pulsante di rendering:

# crea il pulsante di rendering self.RenderButton = wx.Button (self, label = "Render", pos = (8.200))

 Una cosa molto importante è il misuratore. Il sizer ci permette di definire un layout, useremo BoxSizer che posiziona gli elementi orizzontalmente e verticalmente, scegliamo un posizionamento verticale per il controllo del testo e il pulsante:

self.layout = wx.BoxSizer (wx.VERTICAL) self.layout.Add (self.NukeScriptsList, 1, wx.EXPAND) self.layout.Add (self.RenderButton, 0, wx.EXPAND) self.SetSizer (self. disposizione)

Il secondo parametro nel Inserisci il metodo è un numero che descrive come la poltiglia occupa ciascun elemento, 0 significa che verrà utilizzata la dimensione minima, 1 significa che lo spazio disponibile sarà occupato, nel nostro caso vogliamo che il pulsante sia ridotto al minimo e che il controllo del testo abbia lo spazio rimanente.

Prepariamo alcune variabili:

self.NukeScripts = [] self.dirName = "" self.fileName = ""

Quindi prepariamo il menu. Iniziamo creando una barra dei menu come wx.MenuBar (), creiamo e menu chiamato filemenu come wx.Menu (), aggiungiamo il Aggiungi gli script Nuke e Uscita oggetti e aggiungerli al film. E infine aggiungiamo il file a menuBar:

# crea voci di menu menuBar = wx.MenuBar () filemenu = wx.Menu () addNukeScript = filemenu.Append (wx.ID_ANY, "Aggiungi script Nuke", "Aggiungi script Nuke") ClearList = filemenu.Append (wx.ID_ANY , "Cancella elenco", "Cancella elenco") exitEvt = filemenu.Append (wx.ID_EXIT, "Exit", "Exit") menuBar.Append (filemenu, "File") self.SetMenuBar (menuBar)

wx.ID_ANY wx.ID_EXIT sono usati per fornire un ID agli elementi, nel primo caso otteniamo un ID per l'oggetto, ma nel secondo caso abbiamo a ID_EXIT che crea un ID speciale per l'azione di uscita.

Il prossimo passo è lasciare che questi elementi eseguano qualche operazione, per questo usiamo il wx.Bind funzione che ci consente di associare l'elemento a una funzione specifica:

self.Bind (wx.EVT_MENU, self.onAdd, addNukeScript)

Il primo argomento dice che abbiamo a che fare con un evento di menu, il secondo chiama la funzione che vogliamo collegare a questo elemento e il terzo è l'elemento stesso. In questo caso è il addNukeScritp voce nel menu. Dobbiamo ancora implementare il self.onAdd funzione, lo faremo più avanti:

self.Bind (wx.EVT_MENU, self.onClearList, ClearList)

 Il Elenco chiaro l'azione è legata al onClearList metodo:

self.Bind (wx.EVT_BUTTON, self.onRender, self.RenderButton)

Qui leghiamo il self.RenderButton al self.onRender funzione che dobbiamo implementare:

self.Bind (wx.EVT_MENU, self.onExit, exitEvt)

 Alla fine assegniamo il self.onExit funzione al exitEvt elemento.

Per completare il costruttore mostriamo il finestra principale:

# mostra la finestra principale self.Show (True)

Finora abbiamo il nostro costruttore:

import os import wx class mainWindow (wx.Frame): def __init __ (self): #constructor wx.Frame .__ init __ (self, None, title = "Gestore rendering Nuke", size = (600,300), style = wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX) # crea una barra di stato self.CreateStatusBar () # prepara l'elenco di script Nuke sullo schermo self.NukeScriptsList = wx.TextCtrl (self, style = wx.TE_MULTILINE) self.NukeScriptsList.SetEditable (False self.NukeScriptsList.SetBackgroundColour ((120,120,120)) self.NukeScriptsList.SetForegroundColour ((50,255,50)) self.NukeScriptsList.SetValue ('Nuke scripts: \ n') # crea il pulsante di rendering self.RenderButton = wx.Button (self, label = "Render", pos = (8,8)) # layout self.layout = wx.BoxSizer (wx.VERTICAL) self.layout.Add (self.NukeScriptsList, 1, wx.EXPAND) self.layout .Add (self.RenderButton, 0, wx.EXPAND) self.SetSizer (self.layout) #variables self.NukeScripts = [] self.dirName = "" self.fileName = "" # crea voci di menu menuBar = wx. MenuBar () filemenu = wx.Menu () addNukeScript = filemenu.Append (wx.ID_ANY, "Aggiungi script Nuke", " Aggiungi script Nuke ") ClearList = filemenu.Append (wx.ID_ANY," Cancella elenco "," Cancella elenco ") exitEvt = filemenu.Append (wx.ID_EXIT," Exit "," Exit ") menuBar.Append (filemenu," File ") self.SetMenuBar (menuBar) # associa gli elementi agli eventi self.Bind (wx.EVT_MENU, self.onAdd, addNukeScript) self.Bind (wx.EVT_MENU, self.onClearList, ClearList) self.Bind (wx.EVT_BUTTON , self.onRender, self.RenderButton) self.Bind (wx.EVT_MENU, self.onExit, exitEvt) # mostra la finestra principale self.Show (True)
Istantanea dell'editor.

Diamo un'occhiata alle funzioni. La prima cosa che voglio spiegare è onAdd che viene eseguito ogni volta che si verifica l'evento del menu addNukeScript è chiamato. L'obiettivo di questa funzione è aggiungere le informazioni sugli script Nuke in un elenco:

# aggiunge gli script Nuke nella lista def onAdd (self, event): wildcard = "Script Nuke * .nk | * .nk" dlg = wx.FileDialog (self, message = "Aggiungi script Nuke", carattere jolly = carattere jolly, stile = wx.OPEN) if dlg.ShowModal () == wx.ID_OK: self.dirName = dlg.GetDirectory () self.fileName = dlg.GetFilename () self.NukeScripts.append (self.dirName + self.fileName) self .updateList () dlg.Destroy ()

Poiché questa funzione viene chiamata quando si verifica un evento, mentre lo definiamo dobbiamo includere un parametro aggiuntivo che in questo caso abbiamo chiamato evento. Definiamo un carattere jolly come stringa, utile per guidare gli utenti a quale estensione devono cercare:

wildcard = "Script Nuke * .nk | * .nk"

Viene creata una finestra di dialogo di apertura file e, quando l'utente fa clic su OK, memorizziamo la directory e il nome del file nelle nostre variabili e chiamiamo updateList per aggiornare lo schermo:

if dlg.ShowModal () == wx.ID_OK: self.dirName = dlg.GetDirectory () self.fileName = dlg.GetFilename () self.NukeScripts.append (self.dirName + self.fileName) self.updateList ()

Il updateList metodo cancella lo schermo, scorre attraverso il NukeScripts elenca e scrive di nuovo sullo schermo:

#it ​​aggiorna l'elenco di script Nuke sullo schermo def updateList (self): self.NukeScriptsList.Clear () per i in self.NukeScripts: self.NukeScriptsList.AppendText (i + "\ n") 

Il onClearList funzione cancella lo schermo e il NukeScripts elenco:

def onClearList (self, event): self.NukeScriptsList.Clear () self.NukeScripts = []

abbiamo onRender () , che sarà implementato nella prossima sezione, e il onExit funzione che chiude l'applicazione:

# avvia il processo di rendering def onRender (self, event): stampa "Rendering ..." # chiude il programma def onExit (self, event): self.Close (True)

Questa è la definizione della classe mainWindow, ora abbiamo bisogno di crearne un'istanza per vederla e usarla, ma prima dobbiamo creare un wx.App oggetto:

app = wx.App (False)

Quindi creiamo il nostro finestra principale esempio:

MainWindow = MainWindow ()

Alla fine dobbiamo chiamare il MainLoop funzione per avviare l'applicazione:

app.MainLoop ()

Quindi a questo punto abbiamo il codice NukeRenderingManager.py ad eccezione del metodo onRender che implementeremo nella prossima sezione.

Per rendere il nostro programma più robusto ho aggiunto un paio di righe per fare alcuni controlli. Mentre carichiamo uno script Nuke, sarebbe positivo se controllassimo l'estensione del file .nk, anche se il carattere jolly filtra la nostra scelta. Usiamo la os.path.splitext funzione, quindi se l'estensione è .nk procediamo normalmente:

#we controlla se abbiamo uno script Nuke self.extension = os.path.splitext (self.fileName) if self.extension [1] == ". nk": self.NukeScripts.append (self.dirName + self.fileName ) self.updateList ()

Il os.path.splitext restituisce una lista con il nome e l'estensione del file al [0] e [1] posizione. Dal momento che stiamo caricando file esterni, potrebbe essere possibile che alcuni di essi possano essere danneggiati, quindi per aumentare la qualità della nostra applicazione gestiremo le eccezioni:

# aggiunge gli script Nuke nella lista def onAdd (self, event): wildcard = "Script Nuke * .nk | * .nk" dlg = wx.FileDialog (self, message = "Aggiungi script Nuke", carattere jolly = carattere jolly, stile = wx.OPEN) try: if dlg.ShowModal () == wx.ID_OK: self.dirName = dlg.GetDirectory () self.fileName = dlg.GetFilename () #we controlla se abbiamo uno script Nuke self.extension = os.path.splitext (self.fileName) if self.extension [1] == ". nk": self.NukeScripts.append (self.dirName + "\\" + self.fileName) self.updateList () eccetto: stampa "impossibile leggere questo file" dlg.Destroy ()

 Come hai notato, ho usato self.NukeScripts.append (self.dirName +”\\” + self.fileName), Ho dovuto aggiungere “\\” perché ho scoperto che se si trova uno script nuke in c: \ ritorna c: \, devi aggiungere il \ manualmente.

Prima della fine di questa sezione voglio ricordare che per far funzionare l'intero sistema, dovremmo evitare di inserire gli script nuke, i exeNuke.bat e il Rendering.py file in una cartella che ha un percorso molto lungo. Ho provato il programma e per qualche ragione quando questo percorso è troppo lungo non funziona, potrebbe perché il prompt non è in grado di gestire tali stringhe.

Quindi il nostro NukeRenderingManager.py è il seguente:

import os import wx class mainWindow (wx.Frame): def __init __ (self): #constructor wx.Frame .__ init __ (self, None, title = "Gestore rendering Nuke", size = (600,300), style = wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX) # crea una barra di stato self.CreateStatusBar () # prepara l'elenco di script Nuke sullo schermo self.NukeScriptsList = wx.TextCtrl (self, style = wx.TE_MULTILINE) self.NukeScriptsList.SetEditable (False self.NukeScriptsList.SetBackgroundColour ((120,120,120)) self.NukeScriptsList.SetForegroundColour ((50,255,50)) self.NukeScriptsList.SetValue ('Nuke scripts: \ n') # crea il pulsante di rendering self.RenderButton = wx.Button (self, label = "Render", pos = (8,8)) # layout self.layout = wx.BoxSizer (wx.VERTICAL) self.layout.Add (self.NukeScriptsList, 1, wx.EXPAND) self.layout .Add (self.RenderButton, 0, wx.EXPAND) self.SetSizer (self.layout) # variables self.NukeScripts = [] self.dirName = "" self.fileName = "" # crea voci di menu menuBar = wx. MenuBar () filemenu = wx.Menu () addNukeScript = filemenu.Append (wx.ID_ANY, "Aggiungi script Nuke", "Aggiungi script Nuke") ClearList = filemenu.Append (wx.ID_ANY, "Cancella elenco", "Cancella elenco") exitEvt = filemenu.Append (wx.ID_EXIT, "Exit", "Exit") menuBar.Append (filemenu, "File") self.SetMenuBar (menuBar) # associa gli elementi agli eventi self.Bind (wx.EVT_MENU, self.onAdd, addNukeScript) self.Bind (wx.EVT_MENU, self.onClearList, ClearList) self.Bind (wx. EVT_BUTTON, self.onRender, self.RenderButton) self.Bind (wx.EVT_MENU, self.onExit, exitEvt) # mostra la finestra principale self.Show (True) #it aggiorna la lista degli script Nuke sullo schermo def updateList (self) : self.NukeScriptsList.Clear () per i in self.NukeScripts: self.NukeScriptsList.AppendText (i + "\ n") # aggiunge gli script Nuke nella lista def onAdd (self, event): wildcard = "Script Nuke *. nk | * .nk "dlg = wx.FileDialog (self, message =" Aggiungi script Nuke ", jolly = jolly, style = wx.OPEN) provare: if dlg.ShowModal () == wx.ID_OK: self.dirName = dlg.GetDirectory () self.fileName = dlg.GetFilename () #we controlla se abbiamo uno script Nuke self.extension = os.path.splitext (self.fileName) se self.extension [1] == ".nk": self.NukeScripts.append (self.dirName + "\\" + self.fileName) self.updateList () eccetto: print "impossibile leggere questo file" dlg.Destroy () def onClearList (self, event) : self.NukeScriptsList.Clear () self.NukeScripts = [] # avvia il processo di rendering per ogni script Nuke def onRender (self, event): #per implementare return # chiude il programma def onExit (self, event): self .Close (True) app = wx.App (False) mainWindow = mainWindow () app.MainLoop ()
Un'altra istantanea dell'editore.

3. Scrittura del file exeNuke.bat

Descrizione

Un file bat è riconosciuto dal sistema operativo Windows come una raccolta di comandi. Puoi scrivere qualsiasi tipo di comando che desideri, puoi anche avviare programmi, e questa è una funzione che useremo. Se hai familiarità con le istruzioni rapide, troverai questo processo facile.

 Prima di tutto è necessario aprire un file di testo vuoto (consiglio Blocco note) e salvarlo come exeNuke.bat. Come ho menzionato nella sezione precedente, dovremmo evitare di posizionare questi file in una posizione che ha un percorso molto lungo, perché il prompt non è in grado di gestirlo, quindi posiziona tutti e tre i file che stiamo scrivendo sul tuo disco, con alcune sottocartelle, ad esempio c: \ NukeRenderingManager o c: \ myProjects \ NukeRenderingManager. 

Questa regola si applica anche agli script Nuke, potrebbero trovarsi in un posto diverso, ma assicurarsi che il percorso non sia troppo lungo.

Implementazione

Voglio spiegare brevemente come funziona Nuke. Di solito lavoriamo in Nuke attraverso la sua interfaccia utente grafica, ma per alcune attività specifiche potremmo voler eseguirlo in modalità terminale. Ciò significa che scriviamo solo comandi per eseguire qualsiasi operazione, sembra un prompt di Windows:

Il modo in cui inviamo istruzioni a Nuke in modalità terminale è la scrittura di un codice Python. Supponiamo che tu voglia creare un nodo di sfocatura, puoi digitare nuke.createNode ( 'Blur') e così via. Quello che faremo è lasciare che il file bat apra Nuke in modalità terminale e avviare il rendering di un progetto, facendo tutto inviando comandi e senza alcuna interfaccia utente grafica.

Le prime istruzioni sono:

C: \ C:

 Questo per assicurarci di poter iniziare a digitare il percorso Nuke per avviarlo:

cd Programmi \ Nuke6.2v6 Nuke6.2 -t

Naturalmente queste linee potrebbero essere diverse, scrivi la posizione della tua macchina. Il -t significa modalità terminale. Se fai doppio clic sul tuo file exeNuke.bat dovresti vedere Nuke in modalità terminale. Se vuoi smettere, digita smettere() e colpisci accedere. Per eseguire il rendering abbiamo anche bisogno di eseguire il Rendering.py file, così possiamo aggiornare il nostro codice:

cd \ c: cd Programmi \ Nuke6.2v6 Nuke6.2 -t c: \ NukeRenderingManager \ Rendering.py

Aggiungendo la posizione del Rendering.py file, chiediamo di aprire Nuke in modalità terminale ed eseguire il file Rendering.py che contiene tutto il codice per eseguire il rendering e, come ho detto prima, la modalità terminale richiede il linguaggio Python, quindi usiamo il Rendering.py codice. Ma abbiamo ancora bisogno di un'informazione, il file Rendering.py deve sapere dove si trovano gli script di Nuke. 

Ricorda che il exeNuke.bat e Rendering.py sarà chiamato per ogni script Nuke, quindi Se dobbiamo rendere tre progetti, verranno lanciati tre volte. Ma ogni volta vengono chiamati i Rendering.py ha bisogno di sapere dove si trova lo scritp, per raggiungere questo compito abbiamo bisogno di ottenere queste informazioni da quanto sopra NukeRenderingManager.py.

Istantanea dell'editor di file batch .

Completa NukeRenderingManagerFile.py

L'unico metodo che dobbiamo implementare è onRender (). Quello che facciamo è passare in rassegna NukeScripts e chiamare il file bat ogni volta:

# avvia il processo di rendering per ogni script Nuke def onRender (self, event): for i in self.NukeScripts: os.system ("C: /exeNuke.bat" + "" + i)

Noi usiamo il os.system funzione per eseguire il file. Come hai notato, anche noi passiamo io come argomento dopo uno spazio. Fondamentalmente inviamo il percorso NukeScript al file batch. Il fatto che possiamo facilmente inviare queste informazioni al file batch ci dà una grande flessibilità.

Completa il file exeNuke.bat

Il modo in cui un file batch ottiene argomenti è utilizzando il simbolo % seguito da un numero, perché abbiamo passato una informazione che scriveremo 1%. Qui il codice completo:

cd \ c: cd Programmi \ Nuke6.2v6 Nuke6.2 -t c: \ Rendering.py% 1

 Lanciamo Nuke e chiamiamo il Rendering.py dandogli il percorso della sceneggiatura come argomento.

Prima di concludere questa sezione voglio ricapitolare il processo descritto fino ad ora. NukeRenderingManager.py ci fornisce l'interfaccia utente grafica e organizza l'elenco degli script Nuke da rendere. Per ciascuno degli script exeNuke.bat e Rendering.py sarà chiamato. Il primo è incaricato di eseguire Nuke in modalità terminale, afferrando il percorso dello script da elaborare e passandolo a Rendering.py che eseguirà il rendering stesso. Ora dobbiamo implementare Rendering.py.

4. Scrittura del file Rendering.py

Implementazione

La prima cosa che dobbiamo fare è prendere il percorso dello script che abbiamo passato nel file batch. Per fare ciò, usiamo semplicemente la seguente dichiarazione sys.argv [1]. Quindi trasformiamo queste informazioni in stringa:

prj = str (sys.argv [1])

Le istruzioni per aprire un progetto Nuke sono le seguenti:

nuke.scriptOpen (PRO)

Ora abbiamo lo script pronto per l'uso. Quello che dobbiamo fare ora è cercare il nodo di scrittura che vogliamo e renderizziamo. Nel mio esempio, viene chiamato il nodo di scrittura di cui ho bisogno Write1, ma puoi usare qualsiasi nome tu voglia. Ecco il codice completo:

prj = str (sys.argv [1]) nuke.scriptOpen (prj) per i in nuke.allNodes (): if i.Class () == "Write": if i ['name']. getValue () = = "Write1": first_frame = nuke.Root (). Knob ('first_frame'). Value () last_frame = nuke.Root (). Knob ('last_frame'). Value () nuke.execute (i, first_frame, last_frame )

Quello che facciamo è passare in rassegna tutti i nodi nello script, controlliamo se il nodo è uno di scrittura, controlliamo che il nome sia Write1, otteniamo il primo e l'ultimo frame del progetto e usiamo il nuke.execute funzione per eseguire il rendering.

Istantanea del file rendering.py.

Conclusione

Per avviare il programma basta fare doppio clic sul NukeRenderingManager.py. Godere!