Skriv en Render Manager for Nuke ved hjelp av Python

Lær hvordan du skriver en tilpasset renderingsbehandling for Nuke ved hjelp av Python, slik at du kan gjengi ett eller flere Nuke-prosjekter uten å måtte åpne programvaren..

1. Introduksjon

Formålet med denne opplæringen er å forklare hvordan du skriver en programvare som lar deg administrere gjengivelsesprosessen i Nuke. Du kan ha flere Nuke-komposisjoner som må gjengis, så ved å bruke et slikt program kan du gjengi dem alle samtidig uten å åpne Nuke selv, det betyr at systemet ikke laster Nukes grafiske grensesnitt slik at det kan reservere mer minne for gjengivelsen prosess. Her kan du se et eksempel på programmet du skal bygge:

Grafisk brukergrensesnitt.Programmet gir tre prosjekter.

Programmet har et klart brukergrensesnitt som lar deg organisere og kø så mange som du trenger.

Krav

I denne opplæringen antar jeg at du har en grunnleggende forståelse av Python og noen DOS-kommandoer. Denne programvaren er ment å bli kjørt på Windows-operativsystemet. Verktøyene du trenger er følgende:

Python 2.x installert (https://www.python.org) Ikke bruk 3.x-versjonen fordi Nuke ikke støtter det.

wxPython bibliotek (http://www.wxpython.org) Dette lar deg lage et brukergrensesnitt. Du kan også bruke Tkinter, Qt, men dette er ikke dekket i denne opplæringen.

Programvarestruktur

Vi kaller denne programvaren NukeRenderManager. Programmet er laget av tre filer:

  • NukeRenderingManager.py

  • exeNuke.bat

  • Rendering.py

NukeRenderingManager.py: den inneholder alt om det grafiske brukergrensesnittet og all informasjon om plasseringen av Nuke-prosjekter og alle rammeintervaller.

exeNuke.bat: Det er ansvaret for å lansere Nuke i terminalmodus ved å passere gjennom all informasjonen som kommer fra NukeRenderingManager.py-filen. Denne filen kreves for hver gjengivelse, så hvis tre Nuke comps må gjengis, vil denne filen bli kjørt tre ganger.

Rendering.py: det får all informasjon fra exeNuke.bat og utfører gjengivelsen. Denne filen utføres for hvert Nuke-prosjekt.

2. Skrive NukeRenderingManager.py

Beskrivelse

NukeRenderingManager.py styrer brukergrensesnittet og organiserer listen over prosjektene som skal gjengis.

Brukergrensesnittet

For å bygge brukergrensesnittet bruker vi wxPython biblioteket. Som jeg sa før, kan du bruke et annet bibliotek, men i form av denne opplæringen vil jeg forklare wxPython. For å installere det trenger du bare å laste ned installasjonsprogrammet, starte det og alt er klart (du finner linken over). Etter at biblioteket er installert må du starte Python 2.x IDLE og dette gir deg Python-skallet. Fra Fil menyvalg Ny fil, nå har du en tom editor. Hvis du vil at du kan bruke andre redaktører, kan du føle deg komfortabel med. 

Tom Python Editor.

 Lagre filen som NukeRenderingManager.py og legg det i hvilken som helst mappe du vil ha.

Det første du må gjøre er å importere modulene vi trenger. Den første er os som lar oss bruke operativsystemfunksjonene, den andre er wx som skal være nyttig for å bygge et grafisk brukergrensesnitt:

import oss import wx

Vi skal lage et vindu som inneholder alt vi trenger, så vi oppnår dette målet ved å lage en egendefinert klasse som er avledet fra wx.Frame:

Klasse mainWindow (wx.Frame):

Da implementerer vi konstruktøren ved å ringe wx.Frame .__ init__:

def __init __ (selv): #constructor wx.Frame .__ init __ (selv, Ingen, tittel = "Nuke Rendering Manager", størrelse = (600,300), style = wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX)

Deretter oppretter vi en statuslinje:

self.CreateStatusBar ()

 Vi legger til en tekstkontroll for å vise hvilke Nuke-prosjekter som skal behandles:

# forberede Nuke-skriptlisten på skjermen selv.NukeScriptsList = wx.TextCtrl (selv, stil = wx.TE_MULTILINE) self.NukeScriptsList.SetEditable (False) self.NukeScriptsList.SetBackgroundColour ((120,120,120)) self.NukeScriptsList.SetForegroundColour ((50.255 , 50)) self.NukeScriptsList.SetValue ('Nuke skript: \ n')

De wx.TextCtrl gi oss et område der vi kan skrive listen, vi trenger det som multiline, så vi erklærer wx.TE_MULTILINE. Vi trenger ikke at det skal redigeres slik vi bruker SetEditable (usann), da definerer vi noen farger og til slutt viser vi en tekst.

Deretter lager vi en gjengeknapp:

# det skaper gjengivelsen selv.RenderButton = wx.Button (selv, label = "Render", pos = (8,200))

 En veldig viktig ting er sizer. Sizer lar oss definere en layout, vi bruker BoxSizer som plasserer elementer horisontalt og vertikalt, vi velger en vertikal plassering for tekstkontrollen og knappen:

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

Den andre parameteren i Legg til Metode er et tall som beskriver hvordan mush-plass hvert element opptar, 0 betyr at minimumsstørrelsen vil bli brukt, 1 betyr at ledig plass vil bli okkupert, i vårt tilfelle vil vi at knappen skal minimeres og tekstkontrollen har den gjenværende plassen.

Vi forbereder noen variabler:

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

Deretter forbereder vi menyen. Vi starter med å opprette en menylinje som wx.MenuBar (), vi lager e meny kalt filemenu som wx.Menu (), vi legger til Legg til Nuke Scripts og Exit elementer og legge dem til filmmenyen. Og til slutt legger vi filemenu til menyen Bar:

# det lager menyelementer menyBar = wx.MenuBar () filemenu = wx.Menu () addNukeScript = filemenu.Append (wx.ID_ANY, "Legg til Nuke-skript", "Legg til Nuke-skript") ClearList = Filemenu.Oppdatering (wx.ID_ANY , "Clear list", "Clear list") exitEvt = filemenu.Append (wx.ID_EXIT, "Exit", "Exit") menuBar.Append (filmenu, "File") self.SetMenuBar (menuBar)

wx.ID_ANY wx.ID_EXIT brukes til å gi en ID til elementene, i det første tilfellet får vi en ID for varen, men i andre tilfelle har vi en ID_EXIT som skaper en spesiell ID for utgangsaksjonen.

Det neste trinnet er å la disse elementene utføre noe operasjon, for det vi bruker wx.Bind funksjon som tillater oss å binde elementet til en bestemt funksjon:

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

Det første argumentet sier at vi har å gjøre med en menyhendelse, den andre kalles funksjonen som vi vil koble til dette elementet, og det tredje er selve elementet. I dette tilfellet er det addNukeScritp element i menyen. Vi må fortsatt implementere self.onAdd funksjon, vil vi gjøre det senere:

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

 De Klar liste Handlingen er bundet til onClearList metode:

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

Her binder vi self.RenderButton til self.onRender funksjon som vi må implementere:

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

 Til slutt tildeler vi self.onExit funksjon til exitEvt element.

For å fullføre konstruktøren viser vi mainWindow:

# det viser hovedvinduet selv.Show (True)

Så langt har vi vår konstruktør:

import oss import wx klasse mainWindow (wx.Frame): def __init __ (selv): #constructor wx.Frame .__ init __ (selv, Ingen, title = "Nuke Rendering Manager", størrelse = (600,300), style = wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX) # det lager en statuslinje self.CreateStatusBar () # klargjør Nuke-skriptlisten på skjermen self.NukeScriptsList = wx.TextCtrl (selv, stil = wx.TE_MULTILINE) self.NukeScriptsList.SetEditable (False ) self.NukeScriptsList.SetBackgroundColour ((120,120,120)) self.NukeScriptsList.SetForegroundColour ((50,255,50)) self.NukeScriptsList.SetValue ('Nuke skript: \ n') # det skaper gjengivelsen selv.RenderButton = wx.Button (selv, 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 = "" # det lager menyelementer menyBar = wx. MenuBar () filemenu = wx.Menu () addNukeScript = filemenu.Append (wx.ID_ANY, "Legg til Nuke script", " Legg til Nuke-skript ") ClearList = filemenu.Append (wx.ID_ANY," Ryd liste "," Ryd liste ") exitEvt = filemenu.Append (wx.ID_EXIT," Exit "," Exit ") menuBar.Append (filemenu," File ") self.SetMenuBar (menuBar) # det binder elementer til hendelser selv.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) # det viser hovedvinduet selv.Show (True)
Snapshot av redaktøren.

La oss se på funksjonene. Det første jeg vil forklare er onAdd som utføres når menyhendelsen addNukeScript er kalt. Målet med denne funksjonen er å legge til Nuke-skriptinformasjonen på en liste:

# det legger til Nuke-skript på listen def onAdd (selvtillit, begivenhet): wildcard = "Nuke-skript * .nk | * .nk" dlg = wx.FileDialog (selvtillit, melding = "Legg til Nuke-skript", wildcard = wildcard, stil = wx.OPEN) hvis dlg.ShowModal () == wx.ID_OK: self.dirName = dlg.GetDirectory () self.fileName = dlg.GetFilename () self.NukeScripts.append (self.dirName + self.fileName) selv .updateList () dlg.Destroy ()

Fordi denne funksjonen kalles som en hendelse, da vi definerer det, må vi inkludere en ekstra parameter som i dette tilfellet kalte vi hendelsen. Vi definerer et jokertegn som en streng, som er nyttig for å lede brukerne til hvilken utvidelse de må søke etter:

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

En fildialogboksen er opprettet, og når brukeren klikker OK, husker vi katalogen og filnavnet til våre variabler, og vi ringer updateList å oppdatere skjermen:

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

De updateList Metode fjerner skjermen, sløyfer gjennom NukeScripts liste og skriv igjen på skjermen:

#it ​​oppdaterer Nuke-skriptlisten på skjermen def updateList (selv): self.NukeScriptsList.Clear () for jeg i selv.NukeScripts: self.NukeScriptsList.AppendText (i + "\ n") 

De onClearList funksjonen fjerner skjermen og NukeScripts liste:

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

Vi har onRender () , som vil bli implementert i neste avsnitt, og onExit funksjon som lukker programmet:

# det starter gjengivelsesprosessen def onRender (selvtillit, begivenhet): print "Rendering ..." # det lukker programmet def onExit (selvtillit, begivenhet): self.Close (True)

Dette er hovedvinduklassdefinisjonen, nå må vi gjøre en forekomst av den for å se og bruke den, men først må vi lage en wx.App gjenstand:

app = wx.App (False)

Da skaper vi vår mainWindow forekomst:

mainWindow = mainWindow ()

Til slutt må vi ringe MainLoop funksjon for å starte programmet:

app.MainLoop ()

Så på dette tidspunktet har vi NukeRenderingManager.py-koden bortsett fra onRender-metoden som vi skal implementere i neste avsnitt.

For å gjøre vårt program mer robust, la jeg til et par linjer for å gjøre noen sjekker. Når vi laster et Nuke-skript, ville det være bra hvis vi sjekker om filtypen er .nk, selv om wildcard filtrerer vårt valg. Vi bruker os.path.splitext funksjon, så hvis utvidelsen er .nk vi fortsetter som normalt:

# Vi sjekker om vi har et Nuke-skript self.extension = os.path.splitext (self.fileName) hvis self.extension [1] == ". nk": self.NukeScripts.append (self.dirName + self.fileName ) self.updateList ()

De os.path.splitext gir tilbake en liste med navnet og filtypen på [0] og [1] stilling. Siden vi laster inn eksterne filer, kan det hende at noen av dem kan bli skadet. For å øke kvaliteten på applikasjonen vi håndterer unntakene:

# det legger til Nuke-skript på listen def onAdd (selvtillit, begivenhet): wildcard = "Nuke-skript * .nk | * .nk" dlg = wx.FileDialog (selvtillit, melding = "Legg til Nuke-skript", wildcard = wildcard, stil = wx.OPEN) Prøv: hvis dlg.ShowModal () == wx.ID_OK: self.dirName = dlg.GetDirectory () self.fileName = dlg.GetFilename () #Vi sjekker om vi har et Nuke-script self.extension = os.path.splitext (self.fileName) hvis self.extension [1] == ".nk": self.NukeScripts.append (self.dirName + "\\" + self.fileName) self.updateList () bortsett fra: print "Kan ikke lese denne filen" dlg.Destroy ()

 Som du har lagt merke til, har jeg brukt self.NukeScripts.append (self.dirName +”\\” + self.fileName), Jeg måtte legge til “\\” fordi jeg fant ut at hvis noen nåke script er plassert i c: \ det kommer tilbake c: \, du må legge til \ manuelt.

Før slutten av denne delen vil jeg nevne at for å få hele systemet til å fungere, bør vi unngå å plassere nukescriptene, exeNuke.bat og Rendering.py filer i en mappe som har en veldig lang sti. Jeg har testet programmet og av en eller annen grunn når denne banen er for lang, fungerer den ikke, det kan fordi spørringen ikke klarer å håndtere slike strenger.

Så vår NukeRenderingManager.py er følgende:

import oss import wx klasse mainWindow (wx.Frame): def __init __ (selv): #constructor wx.Frame .__ init __ (selv, Ingen, title = "Nuke Rendering Manager", størrelse = (600,300), style = wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX) # det lager en statuslinje self.CreateStatusBar () # klargjør Nuke-skriptlisten på skjermen self.NukeScriptsList = wx.TextCtrl (selv, stil = wx.TE_MULTILINE) self.NukeScriptsList.SetEditable (False ) self.NukeScriptsList.SetBackgroundColour ((120,120,120)) self.NukeScriptsList.SetForegroundColour ((50,255,50)) self.NukeScriptsList.SetValue ('Nuke skript: \ n') # det skaper gjengivelsen selv.RenderButton = wx.Button (selv, 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) # variabler self.NukeScripts = [] self.dirName = "" self.fileName = "" # det skaper menyelementer menuBar = wx. MenuBar () filemenu = wx.Menu () addNukeScript = filemenu.Append (wx.ID_ANY, "Legg til Nuke script", "Legg til Nuke-skript") ClearList = filemenu.Append (wx.ID_ANY, "Ryd liste", "Ryd liste") exitEvt = filemenu.Append (wx.ID_EXIT, "Exit", "Exit") menuBar.Append (filemenu, "File") self.SetMenuBar (menuBar) # det binder elementer til hendelser selv.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) # det viser hovedvinduet selv.Show (True) #t oppdaterer Nuke-skriptlisten på skjermen def updateList (selv) : selv.NukeScriptsList.Clear () for jeg i selv.NukeScripts: self.NukeScriptsList.AppendText (i + "\ n") # det legger til Nuke-skript på listen def onAdd (selvtillit, event): wildcard = "Nuke skript *. nk | * .nk "dlg = wx.FileDialog (self, message =" Legg til Nuke script ", wildcard = wildcard, style = wx.OPEN) forsøk: hvis dlg.ShowModal () == wx.ID_OK: self.dirName = dlg.GetDirectory () self.fileName = dlg.GetFilename () # vi sjekker om vi har et Nuke-skript self.extension = os.path.splitext (self.fileName) hvis self.extension [1] == ".nk": self.NukeScripts.append (self.dirName + "\\" + self.fileName) self.updateList () unntatt: print "ikke i stand til å lese denne filen" dlg.Destroy () def onClearList (selvtillit, event) : self.NukeScriptsList.Clear () self.NukeScripts = [] # det starter gjengivelsesprosessen for hver Nuke script def onRender (self, event): # for å implementere retur # det lukker programmet def onExit (selvtillit, begivenhet): selv .Close (True) app = wx.App (False) mainWindow = mainWindow () app.MainLoop ()
Et annet øyeblikksbilde av redaktøren.

3. Skrive filen exeNuke.bat

Beskrivelse

En flaggermusfil anerkjennes av Windows-operativsystemet som en samling av kommandoer. Du kan skrive noen form for kommando du vil, du kan også starte programmer, og det er en funksjon vi skal bruke. Hvis du er kjent med ledige instruksjoner, finner du denne prosessen enkelt.

 Først og fremst må du åpne en tom tekstfil (jeg anbefaler Notisblokk), og lagre det som exeNuke.bat. Som jeg nevnte i forrige avsnitt, bør vi unngå å plassere disse filene på et sted som har en veldig lang sti, fordi fordi spørringen ikke klarer å håndtere det, så plasser alle de tre filene vi skriver på stasjonen, med bare noen undermapper, noe som c: \ NukeRenderingManager eller c: \ myProjects \ NukeRenderingManager. 

Den regelen gjelder også Nuke-skriptene, de kan være plassert på et annet sted, men sørg for at banen ikke er for lang.

Gjennomføring

Jeg vil kort forklare hvordan Nuke fungerer. Vi jobber vanligvis i Nuke gjennom det grafiske brukergrensesnittet, men for enkelte spesifikke oppgaver kan det være lurt å kjøre det i terminalmodus. Det betyr at vi bare skriver kommandoer for å utføre vanlig bruk, det ser ut som en Windows-prompt:

Måten vi sender instruksjoner til Nuke i terminalmodus, er å skrive noen Python-kode. La oss anta at du vil opprette en uskarphetskode, du kan skrive nuke.createNode ( 'uklarhet') og så videre. Hva vi skal gjøre er å la batfilen åpne Nuke i terminalmodus og starte gjengivelsen av et prosjekt, gjør alt ved å sende kommandoer og uten grafisk brukergrensesnitt.

Den første instruksjonen er:

C: \ C:

 Dette er for å sikre at vi kan begynne å skrive Nuke-banen for å starte den:

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

Selvfølgelig kan disse linjene være forskjellige, skriv maskinens plassering. De -t betyr terminal modus. Hvis du dobbeltklikker på exeNuke.bat-filen, bør du se Nuke i terminalmodus. Hvis du vil avslutte, skriv bare slutte() og treffer Tast inn. For å utføre gjengivelsen må vi også utføre Rendering.py fil, slik at vi kan oppdatere vår kode:

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

Ved å legge til plasseringen av Rendering.py fil, ber vi om å åpne Nuke i terminalmodus og utføre Rendering.py som inneholder all koden for å utføre gjengivelsen, og som jeg sa før terminalmodus krever Python-språket, så bruker vi Rendering.py kode. Men vi trenger fortsatt et stykke informasjon, rendering.py-filen må vite hvor Nuke-skriptene er plassert. 

Husk at exeNuke.bat og Rendering.py vil bli kalt for hvert Nuke-skript, så hvis vi må gjøre tre prosjekter, vil de bli lansert tre ganger. Men hver gang de kalles Rendering.py trenger å vite hvor scritp er plassert, for å oppnå denne oppgaven må vi få denne informasjonen fra ovenstående NukeRenderingManager.py.

Stillbilde av batchfileditoren .

Fullfør NukeRenderingManagerFile.py

Den eneste metoden vi trenger å implementere er onRender (). Hva vi gjør, er sløyfe gjennom NukeScripts og ring batfilen hver gang:

# det starter gjengivelsesprosessen for hvert Nuke-script def onRender (selvtillit, begivenhet): for jeg i selv.NukeScripts: os.system ("C: /exeNuke.bat" + "" + i)

Vi bruker os.system funksjon for å utføre filen. Som du har lagt merke til, passerer vi også Jeg som argumentet etter et mellomrom. Vi sender i utgangspunktet NukeScript-banen til batchfilen. Det faktum at vi enkelt kan sende denne informasjonen til batchfilen, gir oss stor fleksibilitet.

Fullfør filen exeNuke.bat

Måten en batchfil får argumenter er ved å bruke symbolet % etterfulgt av et nummer, fordi vi bestod en informasjon vi vil skrive %1. Her er den komplette koden:

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

 Vi lanserer Nuke og vi kaller Rendering.py ved å gi den veien til skriptet som et argument.

Før jeg avslutter denne delen vil jeg gjenskape prosessen som er beskrevet frem til nå. NukeRenderingManager.py gir oss det grafiske brukergrensesnittet og organiserer listen over Nuke-skriptene som skal gjengis. For hvert av skriptene exeNuke.bat og Rendering.py vil bli kalt. Den første har ansvaret for å kjøre Nuke i terminalmodus, og tar tak i skriptets vei som skal behandles og overføres til Rendering.py som vil utføre gjengivelsen selv. Nå må vi implementere Rendering.py.

4. Skriver Rendering.py-filen

Gjennomføring

Det første vi må gjøre er å få tak i stien til skriptet vi passerte inn i batchfilen. For å oppnå dette, bruker vi bare følgende erklæring sys.argv [1]. Så transformerer vi denne informasjonen i streng:

PRJ = str (sys.argv [1])

Instruksjonen for å åpne et Nuke-prosjekt er følgende:

nuke.scriptOpen (PRJ)

Nå har vi skriptet klar til bruk. Det vi trenger å gjøre nå, er å lete etter skrive node vi ønsker og gjengi. I mitt eksempel kalles den skrive node jeg trenger Write1, men du kan bruke hvilket som helst navn du vil ha. Her er den komplette koden:

prj = str (sys.argv [1]) nuke.scriptOpen (prj) for jeg i nuke.allNodes (): hvis jeg.Class () == "Skriv": hvis jeg ['navn']. getValue () = = "Skriv1": first_frame = nuke.Root () .knappen ('first_frame') .verdien () last_frame = nuke.Root () .knappen ('last_frame') .verdien () nuke.execute (jeg, first_frame, last_frame )

Det vi gjør er å løpe gjennom alle noder i skriptet, vi sjekker om noden er en skrive en, vi kontrollerer at navnet er Write1, vi får prosjektets første og siste ramme og vi bruker nuke.execute funksjon for å utføre gjengivelsen.

Stillbilde av rendering.py-filen.

Konklusjon

For å starte programmet, dobbeltklikk du på NukeRenderingManager.py. Nyt!