Commandes de base (Nuke)

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 :

Nuke_preferences_cachelimit

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 :

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 :

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 :

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>

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 :

Nuke_cache_clearBuffers

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