Écrire un gestionnaire de rendu pour Nuke à l'aide de Python

Apprenez à écrire un gestionnaire de rendu personnalisé pour Nuke à l'aide de Python, vous permettant ainsi de restituer un ou plusieurs projets Nuke sans avoir à ouvrir le logiciel..

1. Introduction

L'objectif de ce didacticiel est d'expliquer comment écrire un logiciel permettant de gérer le processus de rendu dans Nuke. Plusieurs compositions Nuke doivent peut-être être rendues. Par conséquent, si vous utilisez un tel programme, vous pouvez toutes les rendre en même temps sans ouvrir Nuke, ce qui signifie que le système ne charge pas l'interface graphique de Nuke, il peut donc réserver davantage de mémoire pour le rendu. processus. Ici vous pouvez voir un exemple du programme que vous allez construire:

Interface utilisateur graphique.Le programme rendant trois projets.

Le programme a une interface utilisateur claire qui vous permet d’organiser et de mettre en file d'attente autant de rendus que vous le souhaitez.

Exigences

Dans ce tutoriel, je suppose que vous avez une compréhension de base de Python et de certaines commandes DOS. Ce logiciel est destiné à être exécuté sur le système d'exploitation Windows. Les outils dont vous aurez besoin sont les suivants:

Python 2.x installé (https://www.python.org) N'utilisez pas la version 3.x car Nuke ne la prend pas en charge..

Bibliothèque wxPython (http://www.wxpython.org) Ceci vous permet de créer une interface utilisateur. Vous pouvez également utiliser Tkinter, Qt, mais ceci n'est pas couvert dans ce tutoriel..

Structure du logiciel

Nous appellerons ce logiciel NukeRenderManager. Le programme est composé de trois fichiers:

  • NukeRenderingManager.py

  • exeNuke.bat

  • Rendu.py

NukeRenderingManager.py: il contient tout ce qui concerne l'interface utilisateur graphique et toutes les informations concernant l'emplacement des projets Nuke et toutes les plages d'images..

exeNuke.bat: il est chargé de lancer Nuke en mode terminal en passant par toutes les informations provenant du fichier NukeRenderingManager.py. Ce fichier est appelé pour chaque rendu, donc si trois compositions Nuke doivent être rendues, ce fichier sera exécuté trois fois..

Rendu.py: il obtient toutes les informations de exeNuke.bat et effectue le rendu. Ce fichier est exécuté pour chaque projet Nuke.

2. Écrire le NukeRenderingManager.py

La description

NukeRenderingManager.py gère l’interface utilisateur et organise la liste des projets à rendre..

L'interface utilisateur

Pour construire notre interface utilisateur, nous utilisons la bibliothèque wxPython. Comme je l'ai dit précédemment, vous pouvez utiliser une bibliothèque différente, mais pour les besoins de ce tutoriel, je vais expliquer wxPython. Pour l'installer, il vous suffit de télécharger le programme d'installation, de le lancer et tout est prêt (vous pouvez trouver le lien ci-dessus). Une fois la bibliothèque installée, vous devez démarrer Python 2.x IDLE, ce qui vous donne le shell Python. Du Fichier menu choisir Nouveau fichier, maintenant vous avez un éditeur vide. Si vous le souhaitez, vous pouvez utiliser n’importe quel autre éditeur avec lequel vous pourriez vous sentir à l’aise.. 

Éditeur de Python vide.

 Enregistrez le fichier sous NukeRenderingManager.py et le mettre dans n'importe quel dossier que vous voulez.

La première chose à faire est d’importer les modules dont nous avons besoin. Le premier est os qui nous permet d’utiliser les fonctions du système d’exploitation, le second est le wx qui va être utile pour construire une interface utilisateur graphique:

import os import wx

Nous allons créer une fenêtre contenant tout ce dont nous avons besoin. Nous atteignons donc cet objectif en créant une classe personnalisée dérivée de wx.Frame:

Classe mainWindow (wx.Frame):

Ensuite, nous implémentons le constructeur en appelant wx.Frame .__ init__:

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

Ensuite, nous créons une barre d'état:

self.CreateStatusBar ()

 Nous ajoutons un contrôle de texte pour indiquer quels projets Nuke vont être traités:

# prépare la liste des scripts Nuke à l’écran self.NukeScriptsList = wx.TextCtrl (self, style = wx.TE_MULTILINE) , 50)) self.NukeScriptsList.SetValue ('Nuke scripts: \ n')

le wx.TextCtrl nous fournir un domaine où nous pouvons écrire la liste, nous en avons besoin comme multiligne afin que nous déclarions wx.TE_MULTILINE. Nous n’avons pas besoin d’être éditable, nous utilisons donc SetEditable (False), alors nous définissons des couleurs et finalement nous montrons un texte.

Ensuite, nous créons un bouton de rendu:

# il crée le bouton de rendu self.RenderButton = wx.Button (self, label = "Render", pos = (8 200))

 Une chose très importante est la sizer. Le sizer nous permet de définir une mise en page. Nous allons utiliser BoxSizer pour placer les éléments horizontalement et verticalement, nous choisissons un emplacement vertical pour le contrôle de texte et le bouton:

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. disposition)

Le deuxième paramètre de la Ajouter méthode est un chiffre qui décrit comment chaque élément occupe l'espace, 0 signifie que la taille minimale sera utilisée, 1 signifie que l'espace disponible sera occupé, dans notre cas, nous voulons que le bouton soit réduit au minimum et que le contrôle de texte dispose de l'espace restant.

Nous préparons quelques variables:

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

Ensuite, nous préparons le menu. Nous commençons par créer une barre de menu comme wx.MenuBar (), nous créons un menu appelé filemenu comme wx.Menu (), nous ajoutons le Ajouter des scripts Nuke et Sortie éléments et les ajouter à la filmenu. Et finalement, nous ajoutons filemenu à menuBar:

# il crée des éléments de menu menuBar = wx.MenuBar () filemenu = wx.Menu () addNukeScript = filemenu.Append (wx.ID_ANY, "Ajouter un script Nuke", "Ajouter un script Nuke") ClearList = filemenu.Append (wx.ID_ANY , "Effacer la liste", "Effacer la liste") exitEvt = filemenu.Append (wx.ID_EXIT, "Quitter", "Quitter") menuBar.Append (filemenu, "Fichier") self.SetMenuBar (menuBar)

wx.ID_ANY wx.ID_EXIT sont utilisés pour fournir un ID aux éléments, dans le premier cas, nous obtenons un ID pour l'élément, mais dans le second cas, nous avons un ID_EXIT qui crée un identifiant spécial pour l'action de sortie.

La prochaine étape consiste à laisser ces éléments effectuer certaines opérations, pour cela nous utilisons le wx.Bind fonction qui nous permet de lier l'élément à une fonction spécifique:

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

Le premier argument dit que nous avons affaire à un événement de menu, le second appelle la fonction que nous voulons lier à cet élément et le troisième est l'élément lui-même. Dans ce cas, le addNukeScritp élément dans le menu. Nous devons encore mettre en œuvre le self.onAdd fonction, nous le ferons plus tard:

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

 le Effacer la liste l'action est liée à la onClearList méthode:

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

Ici on lie le self.RenderButton au self.onRender fonction que nous devons implémenter:

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

 Enfin, nous assignons le self.onExit fonction à la exitEvt élément.

Pour compléter le constructeur, nous montrons la fenêtre principale:

# il montre la fenêtre principale self.Show (True)

Jusqu'ici nous avons notre constructeur:

import os import wx classe mainWindow (wx.Frame): def __init __ (self): #constructor wx.Frame .__ init __ (self, Aucun, title = "Gestionnaire de rendu Nuke", taille = (600 300), style = wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX) # il crée une barre d'état self.CreateStatusBar () # prépare la liste des scripts Nuke à l'écran self.NukeScriptsList = wx.TextCtrl (self, style = wx.TE_MULTILINE) self.NukeScriptsList.SetEddit (False ) self.NukeScriptsList.SetBackgroundColour ((120,120,120)). (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 = "" # crée des éléments de menu menuBar = wx. MenuBar () filemenu = wx.Menu () addNukeScript = filemenu.Append (wx.ID_ANY, "Ajouter un script Nuke", " Ajouter un script Nuke ") ClearList = filemenu.Append (wx.ID_ANY," Effacer la liste "," Effacer la liste ") exitEvt = filemenu.Append (wx.ID_EXIT," Quitter "," Quitter ") menuBar.Append (filemenu," Fichier ") self.SetMenuBar (menuBar) # lie les éléments aux événements self.Bind (wx.EVT_MENU, self.onAdd, addNukeScript) self.Bind (wx.EVT_MENU, self.onClearList, ClearList) self.Bind (wx.EVT_MENU, self.onClearList, ClearList) , self.onRender, self.RenderButton) self.Bind (wx.EVT_MENU, self.onExit, exitEvt) # affiche la fenêtre principale self.Show (True)
Instantané de l'éditeur.

Regardons les fonctions. La première chose que je veux expliquer est onAdd qui est exécuté chaque fois que l'événement de menu addNukeScript est appelé. Le but de cette fonction est d’ajouter les informations des scripts Nuke sur une liste:

# il ajoute des scripts Nuke à la liste def onAdd (self, event): wildcard = "Scripts Nuke * .nk | * .nk" dlg = wx.FileDialog (self, message = "Ajouter un script Nuke", wildcard = wildcard = style, style = wx.OPEN) si dlg.ShowModal () == wx.ID_OK: self.dirName = dlg.GetDirectory () self.fileName = dlg.GetFilename () self.NukeScripts.append (self.dirName + self.fileName) self .updateList () dlg.Destroy ()

Comme cette fonction est appelée lorsqu'un événement se produit, lors de sa définition, nous devons inclure un paramètre supplémentaire que nous avons appelé dans ce cas événement. Nous définissons un caractère générique comme une chaîne, ce qui est utile pour guider les utilisateurs vers quelle extension ils doivent rechercher:

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

Une boîte de dialogue d’ouverture de fichier est créée et lorsque l’utilisateur clique sur OK, nous mémorisons le répertoire et le nom du fichier dans nos variables et nous appelons. updateList pour mettre à jour l'écran:

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

le updateList La méthode efface l'écran, parcourt la NukeScripts liste et écrit à nouveau sur l'écran:

#it ​​met à jour la liste de scripts Nuke à l'écran def updateList (self): self.NukeScriptsList.Clear () pour i dans self.NukeScripts: self.NukeScriptsList.AppendText (i + "\ n") 

le onClearList la fonction efface l'écran et le NukeScripts liste:

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

On a onRender () , qui sera mis en œuvre dans la section suivante, et le onExit fonction qui ferme l'application:

# il lance le processus de rendu def onRender (self, event): affiche "Rendu ..." # ferme le programme def onExit (self, event): self.Fermer (True)

C’est la définition de la classe mainWindow. Nous devons maintenant en créer une instance pour pouvoir la voir et l’utiliser, mais nous devons d’abord créer un wx.App objet:

app = wx.App (False)

Ensuite, nous créons notre fenêtre principale exemple:

mainWindow = mainWindow ()

Enfin, nous devons appeler le Boucle principale fonction pour démarrer l'application:

app.MainLoop ()

Nous avons donc à ce stade le code NukeRenderingManager.py, à l’exception de la méthode onRender que nous allons implémenter dans la section suivante..

Pour rendre notre programme plus robuste, j'ai ajouté quelques lignes pour effectuer des vérifications. Comme nous chargeons un script Nuke, il serait bon de vérifier si l’extension de fichier est .nk, même si le caractère générique filtre notre choix. Nous utilisons le os.path.splitext fonction, alors si l'extension est .nk nous procédons comme d'habitude:

#not vérifie si nous avons un script Nuke self.extension = os.path.splitext (self.fileName) si self.extension [1] == ". nk": self.NukeScripts.append (self.dirName + self.fileName ) self.updateList ()

le os.path.splitext donne une liste avec le nom et l'extension du fichier au [0] et [1] position. Puisque nous chargeons des fichiers externes, il est possible que certains d'entre eux soient corrompus. Pour améliorer la qualité de notre application, nous allons gérer les exceptions:

# il ajoute des scripts Nuke à la liste def onAdd (self, event): wildcard = "Scripts Nuke * .nk | * .nk" dlg = wx.FileDialog (self, message = "Ajouter un script Nuke", wildcard = wildcard = style, style = wx.OPEN) essayez: if dlg.ShowModal () == wx.ID_OK: self.dirName = dlg.GetDirectory () self.fileName = dlg.GetFilename () #nous vérifions si nous avons un script Nuke self.extension = os.path.splitext (self.fileName) si self.extension [1] == ". nk": self.NukeScripts.append (self.dirName + "\\" + self.fileName) self.updateList () sauf: imprimer "impossible de lire ce fichier" dlg.Destroy ()

 Comme vous l'avez remarqué, j'ai utilisé self.NukeScripts.append (self.dirName + "\\" + self.fileName), Je devais ajouter "\" parce que j'ai découvert que si un script Nuke est situé dans c: \ il revient c: \, vous devez ajouter le \ manuellement.

Avant la fin de cette section, je tiens à mentionner que, pour que tout le système fonctionne, nous devrions éviter de placer les scripts Nuke, exeNuke.bat et le Rendu.py fichiers dans un dossier qui a un très long chemin. J'ai testé le programme et, pour une raison quelconque, lorsque ce chemin est trop long, il ne fonctionne pas, il se peut que l'invite ne puisse pas gérer de telles chaînes..

Notre NukeRenderingManager.py est donc le suivant:

import os import wx classe mainWindow (wx.Frame): def __init __ (self): #constructor wx.Frame .__ init __ (self, Aucun, title = "Gestionnaire de rendu Nuke", taille = (600 300), style = wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX) # il crée une barre d'état self.CreateStatusBar () # prépare la liste de scripts Nuke à l'écran ) self.NukeScriptsList.SetBackgroundColour ((120,120,120)) self.NukeScriptsList.SetForegroundColour ((50,255,50)) self.NukeScriptsList.SetValue ('Nuke scripts: \ n') (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 = "" # crée des éléments de menu menuBar = wx. MenuBar () filemenu = wx.Menu () addNukeScript = filemenu.Append (wx.ID_ANY, "Ajouter un script Nuke", "Ajouter un script Nuke") ClearList = filemenu.Append (wx.ID_ANY, "Effacer la liste", "Effacer la liste") exitEvt = filemenu.Append (wx.ID_EXIT, "Quitter", "Quitter") menuBar.Append (filemenu, "Fichier") self.SetMenuBar (menuBar) # lie les éléments aux événements 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) # affiche la fenêtre principale self.Show (True) #it met à jour la liste de scripts Nuke à l'écran def updateList (self). : self.NukeScriptsList.Clear () pour i dans self.NukeScripts: self.NukeScriptsList.AppendText (i + "\ n") # ajoute les scripts Nuke à la liste def onAdd (auto, événement): wildcard = "Scripts Nuke *. nk | * .nk "dlg = wx.FileDialog (self, message =" Ajouter un script Nuke ", caractère générique = caractère générique, style = wx.OPEN) essayez: if dlg.ShowModal () == wx.ID_OK: self.dirName = dlg.GetDirectory () self.fileName = dlg.GetFilename () #we vérifions si nous avons un script Nuke self.extension = os.path.splitext (self.fileName) si self.extension [1] == ".nk": self.NukeScripts.append (self.dirName + "\\" + self.fileName) self.updateList () sauf: print "impossible de lire ce fichier" dlg.Destroy () def onClearList (self, event) : self.NukeScriptsList.Clear () self.NukeScripts = [] # démarre le processus de rendu pour chaque script Nuke def onRender (self, événement): #pour appliquer un retour # ferme le programme def onExit (self, événement): self .Close (True) app = wx.App (False) mainWindow = mainWindow () app.MainLoop ()
Un autre instantané de l'éditeur.

3. Écrire le fichier exeNuke.bat

La description

Un fichier bat est reconnu par le système d'exploitation Windows comme une collection de commandes. Vous pouvez écrire n’importe quel type de commande, vous pouvez également lancer des programmes et c’est une fonctionnalité que nous allons utiliser. Si vous connaissez les instructions rapides, vous trouverez ce processus facile..

 Tout d’abord, vous devez ouvrir un fichier texte vide (je recommande le Bloc-notes) et l’enregistrer en tant que exeNuke.bat. Comme je l’ai mentionné dans la section précédente, nous devrions éviter de placer ces fichiers dans un emplacement comportant un chemin très long, car, comme l’invite ne peut pas le gérer, placez tous les trois fichiers que nous écrivons sur votre lecteur, avec juste quelques sous-dossiers, quelque chose comme c: \ NukeRenderingManager ou c: \ myProjects \ NukeRenderingManager. 

Cette règle s'applique également aux scripts Nuke, ils peuvent être situés à un endroit différent, mais assurez-vous que le chemin n'est pas trop long.

la mise en oeuvre

Je veux expliquer brièvement comment fonctionne Nuke. Nous travaillons généralement dans Nuke via son interface utilisateur graphique, mais pour certaines tâches spécifiques, nous souhaitons peut-être l’exécuter en mode terminal. Cela signifie que nous n'écrivons que des commandes pour effectuer les opérations habituelles. Cela ressemble à une invite Windows:

Nous envoyons des instructions à Nuke en mode terminal en écrivant du code Python. Supposons que vous vouliez créer un nœud de flou, vous pouvez taper nuke.createNode ('Blur') etc. Ce que nous allons faire, c'est laisser le fichier bat ouvrir Nuke en mode terminal et lancer le rendu du projet, tout en envoyant des commandes et sans aucune interface graphique..

Les premières instructions sont:

C: \ C:

 C'est pour nous assurer que nous pouvons commencer à taper le chemin Nuke afin de le lancer:

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

Bien sûr, ces lignes peuvent être différentes, écrivez l'emplacement de votre machine. le -t signifie mode terminal. Si vous double-cliquez sur votre fichier exeNuke.bat, vous devriez voir Nuke en mode terminal. Si vous voulez quitter, tapez simplement quitter() et frapper Entrer. Pour effectuer le rendu, nous devons également exécuter le Rendu.py fichier, afin que nous puissions mettre à jour notre code:

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

En ajoutant l'emplacement de la Rendu.py fichier, nous demandons d’ouvrir Nuke en mode terminal et d’exécuter le Rendu.py qui contient tout le code pour effectuer le rendu, et comme je l’ai dit auparavant, le mode terminal nécessite le langage Python, nous utilisons donc le Rendu.py code. Mais nous avons toujours besoin d’une information, le fichier Rendering.py doit savoir où se trouvent les scripts Nuke.. 

Rappelez-vous que le exeNuke.bat et Rendu.py sera appelé pour chaque script Nuke, donc si nous devons rendre trois projets, ils seront lancés trois fois. Mais à chaque fois on les appelle le Rendu.py a besoin de savoir où se trouve le scritp; pour accomplir cette tâche, nous devons obtenir ces informations à partir des éléments ci-dessus. NukeRenderingManager.py.

Instantané de l'éditeur de fichier de commandes .

Terminez NukeRenderingManagerFile.py

La seule méthode que nous devons mettre en œuvre est onRender (). Ce que nous faisons, c'est parcourir NukeScripts et appeler le fichier bat à chaque fois:

# il lance le processus de rendu pour chaque script Nuke def onRender (auto, événement): pour i dans self.NukeScripts: os.system ("C: /exeNuke.bat" + "" + i)

Nous utilisons le os.system fonction pour exécuter le fichier. Comme vous l'avez remarqué, nous passons aussi je comme argument après un espace. Nous envoyons essentiellement le chemin NukeScript au fichier de commandes. Le fait que nous puissions facilement envoyer ces informations au fichier de commandes nous donne une grande flexibilité..

Complétez le fichier exeNuke.bat

La manière dont un fichier de commandes obtient des arguments est en utilisant le symbole % suivi d'un nombre, car nous avons passé une information que nous écrirons %1. Voici le code complet:

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

 Nous lançons Nuke et nous appelons le Rendu.py en lui donnant le chemin du script comme argument.

Avant de conclure cette section, je souhaite récapituler le processus décrit jusqu'à présent.. NukeRenderingManager.py nous fournit l'interface utilisateur graphique et organise la liste des scripts Nuke à rendre. Pour chacun des scripts exeNuke.bat et Rendu.py sera appelé. Le premier est chargé d’exécuter Nuke en mode terminal, de récupérer le chemin du script à traiter et de le transmettre au Rendu.py qui effectuera le rendu lui-même. Maintenant, nous devons implémenter Rendering.py.

4. Écrire le fichier Rendering.py

la mise en oeuvre

La première chose à faire est de saisir le chemin du script que nous avons transmis au fichier de commandes. Pour ce faire, nous utilisons simplement la déclaration suivante sys.argv [1]. Ensuite, nous transformons cette information en chaîne:

prj = str (sys.argv [1])

L'instruction pour ouvrir un projet Nuke est la suivante:

nuke.scriptOpen (prj)

Nous avons maintenant le script prêt à être utilisé. Ce que nous devons faire maintenant, c’est rechercher le noeud d’écriture que nous voulons et le rendre. Dans mon exemple, le noeud d'écriture dont j'ai besoin s'appelle Écrire1, mais vous pouvez utiliser le nom de votre choix. Voici le code complet:

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

Ce que nous faisons est de parcourir tous les nœuds du script, nous vérifions si le nœud est un nœud en écriture, nous contrôlons que le nom est Écrire1, nous obtenons la première et la dernière image du projet et nous utilisons le nuke.execute fonction pour exécuter le rendu.

Instantané du fichier rendering.py.

Conclusion

Pour lancer le programme, double-cliquez simplement sur le bouton NukeRenderingManager.py. Prendre plaisir!