Commandes de base (Nuke)
- Préférences
- Les nodes
- Animation
- Interface
- Debug
- Messages d'erreur connus
- Divers
Cette page a pour but de donner des exemples simples des commandes python les plus utilisées dans Nuke.
Préférences
Modifier les préférences de Nuke
nuke.toNode('preferences')['CacheLimit'].value()
nuke.toNode('preferences')['CacheLimit'].setValue(75)
Le nom du knob peut être obtenu en plaçant le curseur dessus :
Modifier les préférences du projet
nuke.root()['first_frame'].value() # renvoi le numéro de la frame
nuke.root()['first_frame'].setValue(101)
Les formats
Les formats contiennent la résolution et la taille des pixels.
La documentation de la classe nuke.Format
est disponible ici.
Obtenir la liste des formats disponibles
nuke.formats()
Sélectionner un format depuis une résolution donnée
def format_from_resolution(width, height):
for fmt in nuke.formats():
if fmt.width() == width and \
fmt.height() == height:
return fmt
break
else: # No break.
raise ValueError("cannot find format")
Autres exemples d’utilisation disponible dans la documentation officielle.
Modifier le format du projet
nuke.root()['format'].value().name() # renvoi le nom du format
nuke.root()['format'].value().setName("nomDuFormat")
Et bien d'autres options
nuke.root()['format'].value().width()
nuke.root()['format'].value().height()
Obtenir le format d'un node
nodeFormat = muNode.format()
nodeFormat.name() # renvoi le nom du format de l'image en entrée.
nodeFormat.width() # renvoi la largeur, en pixel, de l'image en entrée.
nodeFormat.height() # renvoi la heuteur, en pixel, de l'image en entrée.
Faire un echo des commandes Python lancé par Nuke (à la Maya)
Allez dans :
- Edit/Preferences
- Onglet Script Editor
- Cocher echo python commands to output window
Les nodes
Voir la doc de la classe Node pour plus d'informations :
Créer un node
Deux méthodes pour faire la même chose :
nuke.createNode("Blur")
nuke.nodes.Blur()
D’après la doc officielle :
- La première version créé un node comme si l'utilisateur l'avait créé. En utilisant le “contexte”. Exemple: Si un node est sélectionné, le nouveau node sera connecté au premier. Son panel sera affiché, etc...
- La seconde méthode créé un node “dans le vide”. Connecté a rien, pas de comportement particulier, juste un node.
Ne pas ouvrir le panel du node créé :
nuke.createNode("Blur", inpanel=False )
Setter les knobs d'un node a la création :
nuke.nodes.Blur(size=10)
Supprimer un node
nuke.delete(myNode)
La sélection
Éviter :
nuke.selectedNode()
Comportement complexe, préférer :
nuke.selectedNodes()
Qui revoit une bête liste dans l'ordre inversé de la sélection.
Savoir si un node est sélectionné
myNode.isSelected() # True/False
Ajouter/Enlever le node a la sélection
myNode.setSelected(True)
Depuis le projet
Récupérer tout les nodes
nuke.allNodes() # list tout les nodes du projet en cours
nuke.allNodes("Blur") # list tout les nodes du projet en cours de class Blur
Récupérer un node depuis son nom
nuke.toNode("Blur1")
Récupérer le nom d'un node
myNode.name() # renvoit le nom du node "Blur1"
myNode.fullName() # renvoi le nom complet du node
Récupérer le positionnement d'un node dans le graph
myNode.xpos()
myNode.ypos()
myNode.setXpos(30)
myNode.setYpos(30)
Paramètre des nodes
Lister les dict des attributs d'un node
myNode.knobs()
Méthode de base pour get/set de variable d'un node
myNode.knob("size").value() # get value
myNode.knob("size").setValue(2) # set value
Et une autre façon :
myNode["translate"].value() # get value [2.0, 0.0, 32.0]
myNode["translate"].setValue([1.0, 0.0, 16.0]) # set array value
Si le knob contient une expression (tcl), on peut évaluer cette dernière avec :
myNode["file"].evaluate()
Ajouter un paramètre a un node
myControl = nuke.Array_Knob("name", "label") # "name" est simplement le nom du knob et "label" est ce qui sera affiché dans l'UI. Ce dernier est optionnel.
myControl.setTooltip('Mon tooltip') # Ajoute un tooltip au knob
myNode.addKnob(myControl)
Les différents types de knobs
textControl = nuke.Text_Knob("divider") # Juste une barre de separation
colorControl = nuke.Color_Knob("color") # Un knob de couleur
doubleControl = nuke.Double_Knob("value") # Un knob de valeur a virgule flottante
sliderControl = nuke.WH_Knob("value") # Un knob de deux valeurs: W et H
myNode.addKnob(textControl)
myNode.addKnob(colorControl)
myNode.addKnob(doubleControl)
myNode.addKnob(sliderControl)
Ajouter un bouton qui exécute du Python :
pyButton = nuke.PyScript_Knob("Do something")
pyButton.setCommand("print 'Toto'")
myNode.addKnob(pyButton)
Les autres types de knob sont disponibles dans les sous-classes de la classe Knob.
Certains paramètres peuvent être “exécuté” (comme si on cliquait sur le bouton en fait) :
for myNode in nuke.allNodes("Read") :
myNode["reload"].execute()
Connections des nodes
Toute les connections se font par les index des inputs/output :
myNode.minInputs() # 3 pour un node de merge: A, B, et Mask
myNode.maxInputs() # 101 pour un node de merge: A2, B2, etc...
myNode.maxOutputs() # Pas le nombre de connections, en output, du node mais le nombre d’élément que sort le node (un seul la plupart du temps)
myNode.optionalInput() # Index de l'input optionnel (souvent le mask). 2 pour le node de merge
La taille du tableau des inputs :
myNode.inputs() # La taille du tableau des inputs
Si mask (index 2) est connecté, la taille est de 3 (0,1,2).
Si A est connecté, la taille est de... 2 (0,1). (Apparemment, A est la seconde entrée du tableau et B la première... Allez savoir pourquoi...)
Si B est connecté, la taille est de... 1 (Juste 0).
myNode.canSetInput(0, anotherNode) # Vérifie que la connection de anotherNode sur myNode a l'index 0 est possible
myNode.setInput(0, anotherNode) # Connecter un node a un autre sur l'index 0 (myNode prend anotherNode en input, anotherNode se connecte a myNode)
myNode.setInput(0, None) # Déconnecter un input
myNode.connectInput(0, anotherNode) # connect l'output de anotherNode a l'input 0 de myNode
myNode.channels() # ['rgba.red', 'rgba.green', 'rgba.blue', 'rgba.alpha', 'depth.Z']
Lister les dépendances montantes et descendantes
myNode.dependent() # Renvoi la liste des nodes dépendants (enfant) de myNode
myNode.dependencies() # Renvoi la liste des nodes dont dépendent myMode (ces parents)
Les metadatas
Lire les metadatas :
node = nuke.toNode("Read1")
print node.metadata() # un dict de metadata
# Result:
{'exr/displayWindow': [0, 0, 2047, 1555], 'input/width': 2048, 'exr/nuke/camera/vaperture': '18.672', 'input/bitsperchannel': '16-bit half float'...
Source: Reading Metadata.
Label des nodes
On peut modifier le label d'un node (ce qui est affiché dans l'interface, sous le nom du fichier) avec une syntaxe particulière :
[ lindex [split [filename] /] end-1] # le nom du dossier qui contient l'image ("p099" si "s002/p099/diffuse.0001.exr")
[ lindex [split [filename] /] end-2][ lindex [split [filename] /] end-1] # Variante du dessus ("s002p099" si "s002/p099/diffuse.0001.exr")
[ lindex [split [lindex [split [knob [topnode].file] .] 0] /] end] # Le nom du fichier sans l'extension
[date %d]/[date %m]/[date %y] # Affiche la date de l'image
Le langage utilisé est le tcl.
D'autres commandes utiles ici : Value vs knob command
Animation
Récupérer la valeur d'une animation a une image donnée, pour une vue donnée
myNode["translate"].valueAt(25, view='R')
# Result: [-26.308155060000001, 2.3234429360000002, 72.413200380000006]
On peut ajouter l'index du tableau (ici: 0) :
myNode["translate"].valueAt(25, 0, view='R')
# Result: -26.308155060000001
Interface
Liens intéressants :
- NUKE Python Developers Guide v12.1 documentation: Customizing the UI
Menus
Customiser le menu
menuBar = nuke.menu("Nuke") # La barre de menu principale
myMenu = menuBar.addMenu("&myMenu") # Ajoute un menu custom
myMenuCommand = myMenu.addCommand("Do Something", "doSomething()") # Ajoute une commande
mySubMenu = myMenu.addMenu("mySubMenu") # Ajoute un sous menu a notre menu custom
mySubMenu.addCommand("Do Something", "doSomething()") # Ajoute une commande
editMenu = menuBar.findItem("&Edit") # Cherche un menu existant
editMenu.addCommand("Do Something", "doSomething()") # Et y ajoute une commande
nodeSubMenu = editMenu.findItem("Node") # Cherche le sous menu "Node"
nodeSubMenu.addSeparator() # Y ajoute un separator
nodeSubMenu.addCommand("Do Something", "doSomething()") # Et une commande
Dialog
Une fileDialog, pour les clips. Un seul/plusieurs fichiers
nuke.getClipname( "fileDialogName" )
# Result: '/path/to/my/file'
nuke.getClipname( "fileDialogName", multiple=True )
# Result: [/path/to/my/file1', '/path/to/my/file2', '/path/to/my/file3']
Une fileDialog avec pattern et defaultPath
nuke.getFilename("fileDialogName", pattern="*.png;*.jpeg", default="/path/to/a/file" )
Yes/No dialog
nuke.ask("Ça roule?") # revoit True/False
Icones
Appliquer une icône à un node
myNode["icon"].setValue("/path/to/an/icon.png")
Autres
Overrider la fonction de création d'un node
def myCreateNode() :
print "coucou"
nukescripts.create_read = myCreateNode
Désactiver le thumbnail d'un node
myNode["postage_stamp"].setValue(False)
PySide
Des bouts de codes trouvé par ci par la.
Une fenêtre qui reste toujours “devant” Nuke, même si elle n'a plus le focus (ala Maya)
Trouvé sur la mailing list nuke-python@support.thefoundry.co.uk.
from PySide import QtCore, QtGui
class TestWindow(QtGui.QDialog):
def __init__(self, parent=QtGui.QApplication.activeWindow()):
QtGui.QDialog.__init__(self, parent)
self.hbox=QtGui.QHBoxLayout()
self.button=QtGui.QPushButton("TEST")
self.hbox.addWidget(self.button)
self.setLayout(self.hbox)
tw = TestWindow()
tw.show()
Pour avoir la possibilité de la faire passer “derrière” Nuke il suffit de remplacer :
QtGui.QApplication.activeWindow()
Par :
QtGui.QApplication.desktop()
Dans tous les cas, il faut lui donner un parent. Sans parent, Nuke vous gratifiera d'un Segmentation fault lorsque vous quittez.
Debug
Afficher les plugin path
nuke.pluginPath()
Obtenir des statistiques (performance metrics) sur les nodes calculés
En mode terminal ou GUI, uniquement sous Linux
nuke -P
Afficher tout les callbacks de Nuke dans le terminal
Dans votre .nuke/init.py, ajoutez :
import callbacksTrace
Obtenir un debug des déchargements de la mémoire de Nuke
Lancer le Nuke avec la variable d’environnement NUKE_DEBUG_MEMORY à 1 (voir doc).
Combiné à -P cette option est très intéressante.
Connaître l'état de Nuke lors d'un crash
Il faut récupérer le PID de Nuke avec la commande :
ps aux | grep nuke
Puis lancer :
gdb -p <PID>
- gdb s’initialisera et Nuke s’arrêtera.
- tapez continue pour que Nuke reprenne son travail.
- Quand Nuke crash, gdb reprend la main.
- Tapez bt (pour backtrace) et ainsi voir la liste des fonctions et celle ou Nuke plante.
Vous aurez quelque chose qui ressemble à ça :
(gdb) c
Continuing.
Program received signal SIGINT, Interrupt.
0x00007f991ca63672 in select () from /lib64/libc.so.6
(gdb) bt
#0 0x00007f991ca63672 in select () from /lib64/libc.so.6
#1 0x0000000001296115 in ?? ()
#2 0x00000000012965bf in ?? ()
#3 0x00000000012976d6 in ?? ()
#4 0x0000000001275457 in ?? ()
#5 0x0000000000714b58 in ?? ()
#6 0x00000000005dabf0 in ?? ()
#7 0x00000000005d846f in ?? ()
#8 0x00000000005d7cbc in ?? ()
#9 0x0000000000b703d8 in ?? ()
#10 0x00007f991a8d2041 in PyEval_EvalFrameEx (f=0x11029010, throwflag=<value optimized out>) at Python/ceval.c:3750
#11 0x00007f991a8d3e91 in PyEval_EvalCodeEx (co=0x20f0b70, globals=<value optimized out>, locals=<value optimized out>, args=0xb, argcount=1, kws=0x10a645d8, kwcount=10, defs=0x2125770, defcount=8, closure=0x0) at Python/ceval.c:3000
#12 0x00007f991a8d2289 in PyEval_EvalFrameEx (f=0x10a64300, throwflag=<value optimized out>) at Python/ceval.c:3846
#13 0x00007f991a8d2780 in PyEval_EvalFrameEx (f=0x21629d0, throwflag=<value optimized out>) at Python/ceval.c:3836
#14 0x00007f991a8d3e91 in PyEval_EvalCodeEx (co=0x2125300, globals=<value optimized out>, locals=<value optimized out>, args=0xe, argcount=0, kws=0x2162870, kwcount=14, defs=0x0, defcount=0, closure=0x0) at Python/ceval.c:3000
#15 0x00007f991a8d2289 in PyEval_EvalFrameEx (f=0x21626f0, throwflag=<value optimized out>) at Python/ceval.c:3846
#16 0x00007f991a8d3e91 in PyEval_EvalCodeEx (co=0x213aaf8, globals=<value optimized out>, locals=<value optimized out>, args=0x0, argcount=0, kws=0x0, kwcount=0, defs=0x0, defcount=0, closure=0x0) at Python/ceval.c:3000
#17 0x00007f991a8d4182 in PyEval_EvalCode (co=0x7, globals=0x1da48e8, locals=0x1da4b80) at Python/ceval.c:541
#18 0x00007f991a8f7d51 in PyRun_FileExFlags (fp=0x1ebee90, filename=0x7fffb1933004 "/tmp/InKExe-20111007-61dtGE/nukeRenderer.py", start=<value optimized out>, globals=0x1e07dc0, locals=0x1e07dc0, closeit=1, flags=0x0) at Python/pythonrun.c:1339
#19 0x0000000000b653bc in scriptFile(char const*) ()
#20 0x0000000000b8b202 in ?? ()
#21 0x00007f991c9b5586 in __libc_start_main () from /lib64/libc.so.6
#22 0x00000000004a767a in ?? ()
#23 0x00007fffb1930818 in ?? ()
#24 0x000000000000001c in ?? ()
#25 0x0000000000000006 in ?? ()
Ici, Nuke s’est planté sur la fonction select() de la libc.so.6.
Plus de commandes ici : Utiliser le debuger GDB
Messages d'erreur connus
Voici une liste des messages d'erreur et leur signification/solution.
“ValueError: not attached to a node”
Ce message :
"ValueError: not attached to a node"
Arrive souvent quand on appelle un node supprimé (plus haut dans le script la plupart du temps).
Divers
Lancer nuke en mode terminal (pas de GUI)
nuke -t
Faire un print dans le terminal qui a lancé Nuke
nuke.tprint("Hello World!")
Vider le cache mémoire
nuke.memory("free")
Reviens à cliquer sur Clear Buffers F12 :
Vider le cache disque
nuke.clearDiskCache()
Reviens a cliquer sur Clear Disk Cache.
Savoir si le script s’exécute en mode terminal ou en mode GUI
nuke.GUI
Connaître le nombre de CPU
nuke.NUM_CPUS
Pour une liste complète :
help(nuke)
Dernière mise à jour : sam. 28 janvier 2023