Skriv en Render Manager för Nuke med Python

Lär dig hur du skriver en anpassad renderingshanterare för Nuke med Python, så att du kan göra ett eller flera Nuke-projekt utan att behöva öppna programvaran.

1. Introduktion

Syftet med denna handledning är att förklara hur man skriver en programvara som låter dig hantera renderingsprocessen i Nuke. Du kan ha flera Nuke-kompisar som måste göras, så genom att använda ett sådant program kan du göra dem alla omedelbart utan att öppna Nuke själv, det betyder att systemet inte laddar Nukes grafiska gränssnitt så att det kan spara mer minne för rendering bearbeta. Här kan du se ett exempel på det program du ska bygga:

Grafiskt användargränssnitt.Programmet ger tre projekt.

Programmet har ett tydligt användargränssnitt som låter dig organisera och köa så många som möjligt.

Krav

I denna handledning antar jag att du har en grundläggande förståelse för Python och några doskommandon. Denna programvara är avsedd att köras på Windows operativsystem. De verktyg du behöver är följande:

Python 2.x installerad (https://www.python.org) Använd inte 3.x-versionen eftersom Nuke inte stöder det.

wxPython-biblioteket (http://www.wxpython.org) Det här låter dig skapa ett användargränssnitt. Du kan också använda Tkinter, Qt, men det här är inte behandlat i den här handledningen.

Programstruktur

Vi kommer att ringa denna programvara NukeRenderManager. Programmet består av tre filer:

  • NukeRenderingManager.py

  • exeNuke.bat

  • Rendering.py

NukeRenderingManager.py: Den innehåller allt om det grafiska användargränssnittet och all information om placeringen av Nuke-projekten och alla ramintervall.

exeNuke.bat: Det är ansvaret för att starta Nuke i terminalläge genom att passera igenom all information som kommer från NukeRenderingManager.py-filen. Denna fil kallas för att varje renderas, så om tre Nuke-kompositioner behöver göras kommer denna fil att köras tre gånger.

Rendering.py: Det får all information från exeNuke.bat och utför rendering. Den här filen körs för varje Nuke-projekt.

2. Skriva NukeRenderingManager.py

Beskrivning

NukeRenderingManager.py hanterar användargränssnittet och organiserar listan över de projekt som ska göras.

Användargränssnittet

För att bygga vårt användargränssnitt använder vi biblioteket wxPython. Som jag sa tidigare kan du använda ett annat bibliotek men för syftet med denna handledning kommer jag att förklara wxPython. För att installera det behöver du bara ladda ner installationsprogrammet, starta det och allt är klart (du kan hitta länken ovan). När biblioteket är installerat måste du starta Python 2.x IDLE och det här ger dig Python-skalet. Från Fil menyval Ny fil, Nu har du en tom redaktör. Om du vill kan du använda någon annan redaktör du känner dig bekväm med. 

Tom Python Editor.

 Spara filen som NukeRenderingManager.py och lägg det i vilken mapp du vill ha.

Det första du behöver göra är att importera de moduler vi behöver. Den första är os som tillåter oss att använda operativsystemets funktioner, den andra är wx som kommer att vara användbar för att skapa ett grafiskt användargränssnitt:

import os import wx

Vi ska skapa ett fönster som innehåller allt vi behöver, så vi uppnår detta mål genom att skapa en anpassad klass som härrör från wx.Frame:

Klass huvudWindow (wx.Frame):

Sedan genomför vi konstruktorn genom att ringa wx.Frame .__ init__:

def __init __ (self): #constructor wx.Frame .__ init __ (jag, ingen, title = "Nuke Rendering Manager", storlek = (600,300), style = wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX)

Då skapar vi en statusfält:

self.CreateStatusBar ()

 Vi lägger till en textkontroll för att visa vilka Nuke-projekt som ska behandlas:

# förbereda Nuke-skriptlistan på skärmen self.NukeScriptsList = wx.TextCtrl (själv, 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 ge oss ett område där vi kan skriva listan, vi behöver det som multiline så vi förklarar wx.TE_MULTILINE. Vi behöver inte det att kunna redigeras så vi använder SetEditable (falskt), då definierar vi några färger och slutligen visar vi en text.

Då skapar vi en återgivningsknapp:

# det skapar återställningsknappen self.RenderButton = wx.Button (själv, label = "Render", pos = (8 200))

 En mycket viktig sak är sizer. Sizer tillåter oss att definiera en layout, vi kommer att använda BoxSizer som placerar element horisontellt och vertikalt, vi väljer en vertikal placering för textkontrollen och 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 (self. layout)

Den andra parametern i Lägg till Metod är ett tal som beskriver hur mush space varje element upptar, 0 innebär att minsta storleken kommer att användas, 1 betyder att ledigt utrymme kommer att upptas, i det fall vi vill att knappen ska minimeras och att textkontrollen har det kvarvarande utrymmet.

Vi förbereder vissa variabler:

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

Då förbereder vi menyn. Vi börjar med att skapa en menyrade som wx.MenuBar (), vi skapar e menyn kallas filemenu som wx.Menu (), vi lägger till Lägg till Nuke Scripts och Utgång objekt och lägg dem till filmmenyn. Och till sist lägger vi till filmenu på menyBar:

# det skapar menyalternativ menyBar = wx.MenuBar () filemenu = wx.Menu () addNukeScript = filemenu.Append (wx.ID_ANY, "Add Nuke script", "Add Nuke script") ClearList = filemenu.Append (wx.ID_ANY , "Rensa listan", "Rensa listan") exitEvt = filemenu.Append (wx.ID_EXIT, "Exit", "Exit") menyBar.Append (filmenu, "File") self.SetMenuBar (menyBar)

wx.ID_ANY wx.ID_EXIT används för att ge en ID till elementen, i det första fallet får vi ett ID för objektet, men i det andra fallet har vi en ID_EXIT som skapar ett speciellt ID för utträdesåtgärden.

Nästa steg är att låta dessa element utföra någon operation, för att vi använder wx.Bind funktion som tillåter oss att binda elementet till en specifik funktion:

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

Det första argumentet säger att vi har att göra med en meny händelse, den andra kallar den funktion som vi vill länka till detta element och det tredje är själva elementet. I det här fallet är addNukeScritp objekt i menyn. Vi måste fortfarande implementera self.onAdd funktion kommer vi att göra det senare:

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

 De Tydlig lista åtgärd är bunden till onClearList metod:

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

Här binder vi self.RenderButton till self.onRender funktion som vi måste genomföra:

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

 Slutligen tilldelar vi self.onExit funktion till exitEvt element.

För att slutföra konstruktören visar vi huvudfönster:

# det visar huvudfönstret själv.Show (True)

Hittills har vi vår konstruktör:

import os import wx class mainWindow (wx.Frame): def __init __ (self): #constructor wx.Frame .__ init __ (själv, Ingen, title = "Nuke Rendering Manager", storlek = (600,300), style = wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX) # det skapar en statusfält self.CreateStatusBar () # förbereda Nuke-skriptlistan på skärmen 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') # det skapar återställningsknappen self.RenderButton = wx.Button (själv, 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 skapar menyalternativ menyBar = wx. MenuBar () filemenu = wx.Menu () addNukeScript = filemenu.Append (wx.ID_ANY, "Add Nuke script", " Lägg till Nuke-skript ") ClearList = filemenu.Append (wx.ID_ANY," Rensa listan "," Rensa listan ") exitEvt = filemenu.Append (wx.ID_EXIT," Exit "," Exit ") menyBar.Append (filemenu," File ") self.SetMenuBar (menuBar) # det binder elementen till händelserna själv.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 visar huvudfönstret själv.Show (True)
Snapshot av redaktören.

Låt oss titta på funktionerna. Det första jag vill förklara är onAdd som exekveras när menyhändelsen addNukeScript kallas. Målet med denna funktion är att lägga till Nuke-skriptinformationen på en lista:

# det lägger till Nuke-skript på listan def onAdd (self, event): wildcard = "Nuke-skript * .nk | * .nk" dlg = wx.FileDialog (självmeddelande = "Lägg till Nuke-skript", wildcard = jokertecken, stil = wx.OPEN) om dlg.ShowModal () == wx.ID_OK: self.dirName = dlg.GetDirectory () self.fileName = dlg.GetFilename () self.NukeScripts.append (self.dirName + self.fileName) själv .updateList () dlg.Destroy ()

Eftersom den här funktionen kallas när en händelse inträffar, måste vi, som vi definierar det, inkludera en extra parameter som i detta fall ringde till händelse. Vi definierar ett jokertecken som en sträng, som är användbar för att styra användarna till vilken förlängning de måste leta efter:

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

En dialogruta för filåtergivning skapas och när användaren klickar på OK, minnes vi katalogen och filnamnet till våra variabler och vi ringer updateList för att uppdatera skärmen:

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

De updateList Metoden rensar skärmen, slingorna genom NukeScripts lista och skriva igen på skärmen:

#it ​​uppdaterar Nuke-skriptlistan på skärmen def updateList (själv): self.NukeScriptsList.Clear () för jag i self.NukeScripts: self.NukeScriptsList.AppendText (i + "\ n") 

De onClearList funktionen rensar skärmen och NukeScripts lista:

def onClearList (själv, händelse): self.NukeScriptsList.Clear () self.NukeScripts = []

Vi har onRender () , som kommer att genomföras i nästa avsnitt och onExit funktion som stänger applikationen:

# det startar renderingsprocessen def onRender (själv, händelse): print "Rendering ..." # det stänger programmet def onExit (self, event): self.Close (True)

Det här är definitionen av huvudvinduklassen, nu måste vi göra en förekomst av den för att kunna se och använda den, men först måste vi skapa en wx.App objekt:

app = wx.App (falskt)

Då skapar vi vår huvudfönster exempel:

huvudfönster = huvudfönster ()

Slutligen måste vi ringa MainLoop funktion för att starta programmet:

app.MainLoop ()

Så vid denna tidpunkt har vi NukeRenderingManager.py-koden utom den onRender-metoden som vi ska genomföra i nästa avsnitt.

För att göra vårt program mer robust, lade jag till ett par rader för att göra några kontroller. När vi laddar ett Nuke-skript, skulle det vara bra om vi kontrollerar om filtillägget är .nk, även om jokerteckenet filtrerar vårt val. Vi använder os.path.splitext funktion, då om förlängningen är .nk vi fortsätter som vanligt:

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

De os.path.splitext ger tillbaka en lista med namnet och filtillägget på [0] och [1] placera. Eftersom vi laddar externa filer kan det vara möjligt att vissa av dem kan vara skadade, så för att öka kvaliteten på vår ansökan kommer vi att hantera undantagen:

# det lägger till Nuke-skript på listan def onAdd (self, event): wildcard = "Nuke-skript * .nk | * .nk" dlg = wx.FileDialog (självmeddelande = "Lägg till Nuke-skript", wildcard = jokertecken, stil = wx.OPEN) försök: om dlg.ShowModal () == wx.ID_OK: self.dirName = dlg.GetDirectory () self.fileName = dlg.GetFilename () #Vi kontrollerar om vi har ett Nuke-script self.extension = os.path.splitext (self.fileName) om self.extension [1] == ".nk": self.NukeScripts.append (self.dirName + "\\" + self.fileName) self.updateList () förutom: print "kan inte läsa den här filen" dlg.Destroy ()

 Som du har märkt har jag använt self.NukeScripts.append (self.dirName +”\\” + self.fileName), Jag var tvungen att lägga till ”\\” eftersom jag fick reda på att om något nukle script finns i c: \ det återvänder c: \, du måste lägga till \ manuellt.

Innan slutet av det här avsnittet vill jag nämna att för att hela systemet ska kunna fungera bör vi undvika att placera nukescripten, exeNuke.bat och den Rendering.py filer i en mapp som har en mycket lång väg. Jag har testat programmet och av någon anledning när den här vägen är för lång fungerar den inte, det kan bero på att prompten inte kan hantera sådana strängar.

Så vår NukeRenderingManager.py är följande:

import os import wx class mainWindow (wx.Frame): def __init __ (self): #constructor wx.Frame .__ init __ (själv, Ingen, title = "Nuke Rendering Manager", storlek = (600,300), style = wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX) # det skapar en statusfält self.CreateStatusBar () # förbereda Nuke-skriptlistan på skärmen 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') # det skapar återställningsknappen self.RenderButton = wx.Button (själv, 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 skapar menyalternativ menyBar = wx. MenuBar () filemenu = wx.Menu () addNukeScript = filemenu.Append (wx.ID_ANY, "Lägg till Nuke script", "Add Nuke script") ClearList = filemenu.Append (wx.ID_ANY, "Rensa listan", "Rensa listan") exitEvt = filemenu.Append (wx.ID_EXIT, "Exit", "Exit") menyBar.Append (filemenu, "File") self.SetMenuBar (menyBar) # det binder elementen till händelserna själv.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 visar huvudfönstret själv.Show (True) #it uppdaterar Nuke-skriptlistan på skärmen def updateList (själv) : self.NukeScriptsList.Clear () för jag i self.NukeScripts: self.NukeScriptsList.AppendText (jag + "\ n") # det lägger till Nuke-skript i listan def onAdd (self, event): wildcard = "Nuke-skript *. nk | * .nk "dlg = wx.FileDialog (självmeddelande =" Lägg till Nuke-skript ", wildcard = wildcard, style = wx.OPEN) försök: om dlg.ShowModal () == wx.ID_OK: self.dirName = dlg.GetDirectory () self.fileName = dlg.GetFilename () # vi kolla om vi har ett Nuke-script self.extension = os.path.splitext (self.fileName) om self.extension [1] == ".nk": self.NukeScripts.append (self.dirName + "\\" + self.fileName) self.updateList () förutom: skriv ut "kan inte läsa den här filen" dlg.Destroy () def onClearList (self, event) : self.NukeScriptsList.Clear () self.NukeScripts = [] # det startar renderingsprocessen för varje Nuke-script def onRender (själv, händelse): #för att implementera retur # det stänger programmet def onExit (själv, händelse): själv .Close (True) app = wx.App (False) mainWindow = mainWindow () app.MainLoop ()
En annan ögonblicksbild av redaktören.

3. Skriva filen exeNuke.bat

Beskrivning

En fladderfil identifieras av operativsystemet Windows som en samling kommandon. Du kan skriva vilken typ av kommando du vill, du kan också starta program, och det är en funktion vi ska använda. Om du är bekant med snabba instruktioner hittar du denna process enkelt.

 Först och främst behöver du öppna en tom textfil (jag rekommenderar Anteckningsblock) och spara det som exeNuke.bat. Som jag nämnde i det föregående avsnittet borde vi undvika att placera dessa filer på en plats som har en väldigt lång väg, eftersom det inte går att hantera det, eftersom prompten inte klarar av det, så placera alla tre filerna vi skriver på din enhet, med bara några undermappar, något som c: \ NukeRenderingManager eller c: \ myProjects \ NukeRenderingManager. 

Den här regeln gäller också Nuke-skripten, de kan vara placerade på en annan plats, men se till att banan inte är för lång.

Genomförande

Jag vill kortfattat förklara hur Nuke fungerar. Vi brukar arbeta i Nuke genom sitt grafiska användargränssnitt, men för vissa specifika uppgifter kanske vi vill köra det i terminalläget. Det betyder att vi bara skriver kommandon för att utföra någon vanlig operation, det ser ut som en Windows-prompt:

Så här skickar vi instruktioner till Nuke i terminalläge genom att skriva en del Python-kod. Låt oss anta att du vill skapa en Blur-nod, du kan skriva nuke.createNode ( 'skärpe) och så vidare. Vad vi ska göra är att låta batfilen öppna Nuke i terminalläget och starta ett projekt, göra allt genom att skicka kommandon och utan grafiskt användargränssnitt.

Den första instruktionen är:

C: \ C:

 Detta är för att se till att vi kan börja skriva Nuke-sökvägen för att starta den:

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

Naturligtvis kan dessa linjer vara olika, skriv platsen för din maskin. De -t betyder terminalläge. Om du dubbelklickar på exeNuke.bat-filen bör du se Nuke i terminalläget. Om du vill sluta skriver du bara sluta med() och slå Stiga på. För att kunna göra rendering måste vi också utföra Rendering.py fil, så vi kan uppdatera vår kod:

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

Genom att lägga till platsen för Rendering.py fil, ber vi att öppna Nuke i terminalläge och exekvera Rendering.py som innehåller all kod som ska utföras, och som jag sa innan terminalläget kräver Python-språket, så använder vi Rendering.py koda. Men vi behöver fortfarande en bit av information, rendering.py-filen behöver veta var Nuke-skript är placerade. 

Kom ihåg att exeNuke.bat och Rendering.py kommer att krävas för varje Nuke-skript, så om vi måste göra tre projekt kommer de att lanseras tre gånger. Men varje gång de kallas Rendering.py behöver veta var scritp finns, för att uppnå denna uppgift behöver vi få den här informationen från ovanstående NukeRenderingManager.py.

Snapshot av batchfilredigeraren .

Komplett NukeRenderingManagerFile.py

Den enda metod som vi behöver genomföra är onRender (). Vad vi gör är att loopa genom NukeScripts och ringa till fladderfilen varje gång:

# det startar renderingsprocessen för varje Nuke-script def onRender (själv, händelse): för jag i self.NukeScripts: os.system ("C: /exeNuke.bat" + "" + i)

Vi använder os.system funktion för att utföra filen. Som du har märkt passerar vi också jag som argumentet efter ett mellanslag. Vi skickar i grunden NukeScript-sökvägen till batchfilen. Det faktum att vi enkelt kan skicka denna information till batchfilen ger oss stor flexibilitet.

Fyll i filen exeNuke.bat

Hur en batchfil får argument är att använda symbolen % följt av ett nummer, eftersom vi passerade en information vi ska skriva % 1. Här är den fullständiga koden:

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

 Vi startar Nuke och vi kallar Rendering.py genom att ge den vägen för manuset som ett argument.

Innan jag avslutar det här avsnittet vill jag återskapa processen som beskrivits fram tills nu. NukeRenderingManager.py ger oss det grafiska användargränssnittet och organiserar listan över Nuke-skript som ska göras. För var och en av skripten exeNuke.bat och Rendering.py kommer att kallas. Den första är ansvarig för att köra Nuke i terminalläget, och tar tag i skriptets väg att bearbetas och skickar den till Rendering.py som kommer att utföra själva reningen. Nu måste vi implementera Rendering.py.

4. Skriva Rendering.py-filen

Genomförande

Det första vi behöver göra är att ta tag i sökvägen för det skript vi passerade in i batchfilen. För att uppnå detta använder vi helt enkelt följande uttalande sys.argv [1]. Då omvandlar vi denna information i strängen:

prj = str (sys.argv [1])

Instruktionen för att öppna ett Nuke-projekt är följande:

nuke.scriptOpen (prj)

Nu har vi manuset redo att använda. Vad vi behöver göra nu är att leta efter den skrivnod vi vill ha och göra. I mitt exempel kallas den skrivnod som jag behöver Write1, men du kan använda vilket namn du vill ha. Här är den fullständiga koden:

prj = str (sys.argv [1]) nuke.scriptOpen (prj) för jag i nuke.allNodes (): om i.Class () == "Skriv": om jag ['name']. getValue () = = "Skriv1": first_frame = nuke.Root (). Knopp ('first_frame') .värde () last_frame = nuke.Root (). Knopp ('last_frame') .värde () nuke.execute (jag, first_frame, last_frame )

Vad vi gör är att slinga igenom alla noder i manuset, vi kontrollerar om noden är en skriv en, vi kontrollerar att namnet är Write1, vi får den första och sista ramen för projektet och vi använder nuke.execute funktion för att utföra renderingen.

Stillbild av rendering.py-filen.

Slutsats

För att starta programmet bara dubbelklicka på NukeRenderingManager.py. Njut av!