Nos premiers pas

Dans ce chapitre, nous allons voir quelques commandes de base qui nous permettent de « regarder », puis de modifier notre scène.

Vous allez voir que le chapitre est un peu long, mais ces quelques commandes sont sûrement les plus utilisées en script, n’hésitez donc pas à prendre votre temps et avancer progressivement. :)

À partir de maintenant, je vous invite à toujours avoir un fichier texte d’ouvert sur votre bureau pour garder les précieuses petites lignes de code que vous allez taper. Elles formeront un bloc-note qui vous servira au fil de vos améliorations. Elles vous permettront de trouver et coller rapidement des morceaux pour les adapter à votre usage plutôt que de tout réécrire à chaque fois (ce qui est souvent décourageant). ;)

nodeType() pour récupérer le type des nœuds

La commande nodeType() sert à récupérer le type d’un nœud.

Nous allons partir d’une scène vide et créez une sphère, mais ce coup-ci, en script :

mc.polySphere()
# Result: [u'pSphere1', u'polySphere1'] # 

Votre première commande, c’est-y pas beau tout ça ? :D

Mais nous ne l’expliquerons pas pour l’instant. Gardez juste en tête que cette commande fait la même chose que ce que vous faites manuellement quand vous faites ça :

create polysphere in maya
Créer une polySphere dans Maya.

Maintenant exécutez :

mc.nodeType('pSphere1')
# Result: u'transform' # 

Comme vous pouvez le constater, le nœud s’appelant pSphere1 est de type tansform. :D

Faites des essais en modifiant le nom du nœud dont vous souhaitez vérifier le type.

Notez que le type des nœuds est accessible dans l’Attribute Editor:

maya attribute editor
maya attribute editor
maya attribute editor

C’est à peu près tout ce qu’il y a à dire de cette commande… ^^

Quoi ? Une chapitre pour ça ? o_O

Vous vous doutez qu’il y a anguille sous roche pas vrai ? :-°

Ici, la commande est simpliste… Mais il y a énormément de commandes, chacune disposant de pleins d’arguments possibles, et certains arguments (edit et query entre autres) changent parfois le sens des autres arguments. Alors comment faire dans le cas des commandes plus compliquées ? Vous pensez que les développeurs ont des cerveaux de fou ? Tapent des commandes super complexes, comme ça, les doigts dans le nez ? :-°

Certains peut-être… Mais la grande majorité utilise leur clavier la documentation. :pirate:

nodeType() était une commande simplissime que je vous ai présentée non pas dans le but de savoir s’en servir (vous avez vu, c’est basique…), mais comme prétexte à l’apprentissage de la documentation.

« l’apprentissage de la documentation » ? Mais c’est si dur que ça d’utiliser la documentation ? :euh:

Ne vous inquiétez pas ! Apprendre à s’en servir ne prend pas plus de quelques minutes ! Si c’est la première fois que vous faites du script, sachez que la documentation est un véritable outil de travail. Savoir comment y trouver une information est fondamental pour gagner du temps.

Alors allons-y ! Allez dans Help/Autodesk Maya Help:

Accéder à l’aide dans Maya.
Accéder à l’aide dans Maya.

En bas à gauche, allez dans Technical Documentation/Python Commands:

Vous devriez obtenir une page qui ressemble à ça :

maya documentation

En haut, tapez le nom de la commande qui vous intéresse (dans notre cas tapez nodetype):

Maya documentation
Un concentré de technologie !

Cliquez sur la commande et vous devriez retomber sur une page qui ressemble à ça :

Y a des gens qui pense que la doc’ elle est mauvaise, qu’elle est méchante, qu’elle ne changera jamais, bref, qu’elle est mauvaise… :diable:

Fichtre, c’est vraiment à ch…

Tatata ! C’est très vilain d’utiliser ces mots-là! :D

La documentation de chaque commande est organisé en blocs :

Maya documentation

En haut à gauche le nom de la commande, en haut à droite un accès vers la version de la documentation en MEL ainsi que les catégories à laquelle elle appartient (le lien MEL version).

Gardez bien en tête la position de ce lien, car vous en aurez besoin plus tard, quand nous convertirons les commandes MEL en Python. ;)

Synopsis

Ici vous trouverez un gros bloc jaune qui liste les arguments et la manière dont on appelle la commande :

maya documentation synopsis

Juste en dessus il y une explication souvent assez claire, parfois longue, de ce que fait la commande :

maya documentation

Return value

Ce court bloc résume ce que renvoie la commande :

maya documentation

Le type des valeurs renvoyées dépend d’une certain nombre de choses, souvent expliquées ici.

maya documentation

Ce bloc propose une liste d’autres commandes en lien (plus ou moins) direct avec la commande courante.

Flags (arguments)

Ce bloc contient la documentation de chacun des arguments possibles de la commande. C’est souvent là-dedans qu’on passe pas mal de temps. :D

Flags de la commande nodeType
Flags de la commande nodeType.

Vous avez chacun des arguments sous la forme longue et courte :

apiType(api) veut dire que l’argument peut être passé soit sous la forme :

mc.nodeType('pSphere1', apiType = True)

Soit sous la forme :

mc.nodeType('pSphere1', api = True)

Les deux versions faisant la même chose.

Je vous invite à toujours utiliser la version longue d’un argument afin de conserver une idée assez claire de ce que fait la commande, surtout quand vous y revenez après plusieurs semaines/mois.

mc.nodeType('pSphere1', derived = True)

Étant quand même plus clair que :

mc.nodeType('pSphere1', d = True)

Il y a de rares cas ou la version longue d’un argument rentre en conflit avec un mot clef de Python. C’est le cas de import de la commande file() qu’il est impossible d’utiliser. Dans ce cas, il faut se contenter de la version courte i.

Notez, dans le tableau, une colonne Argument Type qui détermine le type de la variable que vous devez passer à l’argument de la commande.

Gardez la colonne Properties pour plus tard, on ne s’y attarde pas pour le moment. ;)

OK, mais c’est quoi apiType, derived, inherited o_O

Ouh là, malheureux, que vous allez vite en besogne ! :D

Ne vous préoccupez pas de ça pour l’instant. Ce sont des notions qui ne servent qu’avec l’API de Maya.

Je vous invite à essayer ces arguments, mais nous ne les expliquerons pas ici. ^^

Python examples

Ce dernier bloc est sûrement le premier que vous devez regarder quand vous découvrez une commande :

Exemple Python de la commande nodeType

La version copié-collé :

import maya.cmds as cmds

cmds.sphere( n='balloon' )

# Find the type of node created by the sphere command
cmds.nodeType( 'balloon' )
# Result: transform #

# What is the API type of the balloon node?
cmds.nodeType( 'balloon', api=True )
# Result: kTransform #

# Which node types derive from camera?
cmds.nodeType( 'camera', derived=True, isTypeName=True )
# Result: [u'stereoRigCamera', u'camera'] #

Ce sont des exemples très commentés et clairs à copier-coller dans votre Script Editor et qui peuvent fonctionner instantanément. :magicien:

C’est souvent une excellente base pour se familiariser avec une commande, en particulier les commandes concernant l’interface (pour créer des boutons et tout). Je vous invite vraiment à vous en servir, surtout si vous débutez.

ls(), ou comment lister les nœuds de sa scène

La première vraie commande que nous allons voir est ls() (abréviation de list).

Avant de commencer, pensez à garder la page de la documentation officielle sous le coude. ;)

Par défaut, cette commande renvoie tous les nœuds présents dans la scène (en Python : Une list de str). C’est la combinaison des arguments que vous allez utiliser qui va « filtrer » le résultat.

Dans une console Linux, ls est la commande permettant de lister le contenu d’un dossier. Il y a fort à parier que les développeurs de Maya ont choisi ces deux lettres par habitude.

Allez-y, prenez une scène vide et exécutez ceci :

mc.ls()

La sortie devrait vous afficher quelque chose comme ça :

[u'time1', u'sequenceManager1', u'renderPartition', …

Ce sont (presque) tous les nœuds présents dans votre scène Maya ! :soleil:

La sélection

Voici un des arguments dont vous vous servirez sûrement souvent. :)

Vous souhaitez lister les nœuds sélectionnés ? Rien de plus simple !

Créez une sphère (Create/Polygon Primitives/Sphere) :

Créer une polySphere dans Maya
Créer une polySphere dans Maya.

Sélectionnez-la puis exécutez :

mc.ls(selection=True)
# Result: [u'pSphere1'] # 

Bien entendu, vous pouvez sélectionner plusieurs nœuds et l’argument selection vous renverra les nœuds dans l’ordre de leur sélection.

Créez plusieurs sphères et essayez. ;)

Des étoiles pleins les yeux

Vous pouvez aussi utiliser les étoiles * (wildcard en anglais) pour essayer de filtrer des nœuds par nom.

Lancez ceci :

mc.ls("*Sphere*")
# Result: [u'pSphere1', u'pSphereShape1', u'polySphere1'] # 

Une sphère, trois nœuds ? Intéressant… Mais on y reviendra plus tard ! ;)

Il est important de noter qu’à partir du moment où vous mettez une étoile * dans le nom du nœud, Maya va aller chercher tous les nœuds qui correspondent à l’expression.

À l’inverse, s’il n’y a aucune étoile, Maya considère que vous lui donnez un « nom unique » (notion importante pour la suite :-° ).

Par type

On peut préciser le type des nœuds qu’on veut lister. Voici trois exemples :

transform

Renverra une liste contenant tous les nœuds de type transform de la scène :

mc.ls(type="transform")
# Result: [u'front', u'pSphere1', u'persp', u'side', u'top'] #

Remarquez comme il vous retourne également les caméras. :)

mesh

mc.ls(type="mesh")
# Result: [u'pSphereShape1'] # 

polySphere

mc.ls(type="polySphere")
# Result: [u'polySphere1'] #

Au passage, le type d’un nœud est visible dans l’Attribute Editor, à côté du nom :

Trois types, trois nœuds, une sphère ? Intéressant… Mais on y reviendra plus tard ! ;) (bis)

unknown

Un type intéressant est le type unknown. Il apparaît souvent quand on ouvre des scènes Maya ASCII (extension .ma) contenant des nœuds de plugins externes (moteurs de rendu par exemple) non disponibles dans votre session Maya lors de l’ouverture. Maya découvre un nœud dont il n’a pas le plugin et, ne réussissant pas à l’interpréter, le met de ce type spécial : unknown.

Si vous faites un :

mc.ls(type="unknown")

Et que ça vous renvoie quelque chose, vous aurez potentiellement des soucis. :)

Cumuler les types

On peut cumuler les types en les passant sous la forme d’une liste !

mc.ls(type=["transform", "mesh"])
# Result: [u'front', u'pSphere1', u'persp', u'side', u'top', u'pSphereShape1'] # 

Ici on demande indistinctement tous les nœuds de type transform ainsi que mesh.

Deux types, deux nœuds. Coïncidence ? Je ne crois pas… Mais on y… OK, j’arrête ! :lol:

Exclure certains types

Si on peut demander certains types particuliers, comment peut-on demander l’inverse, à savoir, demander à ce que certains types ne soient explicitement pas renvoyés ?

Pour ceci, on utilise l’argument excludeType:

mc.ls(excludeType="transform")

Vous vous en doutez, on peut aussi lui passer une liste :

mc.ls(excludeType=["transform", "mesh"])

Note sur les différents types

Dans Maya, les types sont organisés en hiérarchies. Ainsi, le type surfaceShape regroupe mesh et nurbsSurface. C’est assez anecdotique, mais il peut arriver, sur des scènes crados un peu complexes, que le résultat obtenu ne soit pas nécessairement celui attendu.

L’argument exactType est fait pour renvoyer les nœuds du type spécifié sans prendre en compte les types descendants. Si vous voulez éviter les surprises, utilisez exactType.

Par attribut

On peut également aller chercher tous les nœuds ayant un attribut particulier. Par exemple :

mc.ls("*.focalLength")

renverra tous les nœuds ayant l’attribut focalLength (soit les quatre caméras par défaut si vous n’en avez pas créé d’autres).

Notez que l’étoile * ne fonctionne pas avec les attributs :

mc.ls("*.film*")

ou même :

mc.ls("perspShape.film*")

renverront tous deux une liste vide, bien que des attributs commençant par film existent sur les caméras (exemples : filmTranslateH, filmRollValue, etc).

Je vous concède que cette utilisation est alléchante, mais je vous déconseille de l’utiliser dans vos scripts. Vous pouvez avoir plusieurs types de nœuds différents ayant un nom d’attribut similaire. Exemple : les nœuds polySphere, polyTorus, makeNurbCylinder et plein d’autres ont tous un attribut radius. Si vous récupérez les nœuds par attribut aveuglément, vous risquez de modifier des choses sans vraiment savoir quoi. Il est souvent plus propre de récupérer un/des nœuds en fonction de leur type qu’en fonction de leurs attributs. La seule exception s’applique aux attributs customs, et là encore, il est préférable de ne créer des attributs spécifiques que sur un type de nœud particulier (en gros, de travailler proprement). :P

Le principe de noms uniques

Un chouillat plus avancé maintenant :

  • Repartez d’une scène vide (Ctrl+n ou File/New Scene).
  • Créez un groupe (Ctrl+g ou Edit/Group ou encore Create/Empty Group).
  • Appelez-le toto.
  • Mettez-le dans un groupe (Sélectionnez toto puis faites Ctrl+g).
  • Dupliquez le groupe (Ctrl+d ou Edit/Duplicate).
  • Enfin, renommez-le toto du deuxième groupe en titi.

Il va falloir vous y habituer tout de suite, mes noms de variable favoris sont toto tutu et titi (parce que les touches u, i et o se suivent sur le clavier :P ).

En développement, les variables souvent utilisées lors des exemples s’appellent des variables syntaxiques. Les anglo-saxons utilisent beaucoup les variables « foo » et « bar » dans leurs codes d’exemples. Ceci vient de l’acronyme militaire « FUBAR » pour « fucked up beyond all/any recognition/repair/reason/redemption » qu’on pourrait poliment traduire par « un merdier innommable ».

Mais continuons ! ^^

Votre scène devrait ressembler à ceci :

Sélectionnez toto et faites :

mc.ls(selection=True)

En toute logique, vous obtenez :

[u'toto']

Et bien oui : vous sélectionnez toto, vous demandez la sélection, forcément vous obtenez toto. L’inverse serait troublant non ? ;)

Maintenant, renommez titi en toto :

Vous voyez le piège venir ? :-°

Re-sélectionnez le premier toto et refaites :

mc.ls(selection=True)

Vous obtenez :

[u'group1|toto']

Mais ! Mais ! Mon nœud a changé de nom ? Je n’y ai pourtant pas touché ! :'(

Ne paniquez pas ! Tout va bien ! :D

Il y a une chose très importante à comprendre : les commandes Maya sont prévues pour communiquer entre elles. Les commandes retournant un ou plusieurs nœuds renvoient le « nom unique le plus court possible ». Ici, nous avons deux nœuds nommés toto. Si, vous passez toto en argument d’une autre commande, Maya ne saura pas auquel des deux nœuds vous faites référence.

Vous ne me croyez pas, essayez par vous-même :

mc.select('toto')

Et :

# Error: More than one object matches name: toto
# Traceback (most recent call last):
#   File "<maya console>", line 1, in <module>
# ValueError: More than one object matches name: toto # 

Le message est explicite : plusieurs nœuds correspondent à toto et il ne sait pas quoi faire. :euh:

En cela, les développeurs de Maya ont décidé d’utiliser le concept de « nom unique » pour être sûr que les nœuds renvoyés par les commandes sont utilisables par d’autres commandes.

Sauf mention contraire, une commande renvoyant un ou plusieurs nœuds ne renvoient pas son nom, mais son identifiant, à savoir : son « nom unique le plus court possible ».

Très bien mais c’est quoi ce trait | ?

Ça s’appelle un pipe (prononcer à l’anglaise paillp’). Sous Windows, les hiérarchies de dossiers s’écrivent en utilisant le séparateur back slash "\": "C:\Windows\System". Sous Linux, les hiérarchies de dossiers s’écrivent en utilisant le séparateur slash "/": "/usr/share". Et bien sous Maya, les hiérarchies de nœud s’écrivent en utilisant le séparateur pipe "|": "|geo|tete|oeilG".

Il n’y a rien à comprendre de plus ! ^^

Mais comment je fais si je souhaite simplement avoir le nom du nœud ?

La commande ls() ne le fait pas (pour les raisons évoquées précédemment) mais c’est très simple en Python via la commande split():

for n in mc.ls(selection=True) :
    print n.split("|")[-1]

Si ce dernier est « le plus court possible », cela sous-entend qu’il y a un nom « le plus long possible »?

Vous avez tout compris ! ^^ Et c’est l’argument long qui s’en charge.

mc.ls(selection=True, long=True)

Cet argument est supposé renvoyer le nom long (long name en anglais) mais je trouve qu’il est mal choisi. fullPath (chemin complet en français) aurait été plus approprié.

[u'|group1|toto']

Vous remarquerez le pipe | devant group1. Tout nom de nœud qui commence par | est un chemin complet. Un chemin complet est par définition un nom unique.

Je vous recommande d’utiliser l’argument long à chaque fois que vous appelez ls(). Vous aurez ainsi la garantie d’avoir un chemin complet. :)

Gardez à l’esprit que tout peut se combiner avec ls(). C’est souvent LA commande que vous appellerez en premier dans vos scripts. N’hésitez pas à jeter un œil à ses arguments sur sa page de documentation, notez ceux qui vous semblent intéressants et expérimentez par vous-même. Croyez-moi, ce n’est pas du temps perdu pour vos futurs scripts. ;)

getAttr() pour récupérer la valeur des attributs

Vous savez maintenant comment récupérer et filtrer les nœuds de votre scène. :D

Ici, nous allons nous servir de la commande getAttr() pour récupérer le contenu des attributs des nœuds.

Une fois encore (et il va falloir prendre l’habitude ;) ), gardez-la page de la documentation sous le coude.

On va commencer par un exemple simple. ^^

Créez une polySphere dans votre scène puis faites :

mc.getAttr("pSphere1.translateX")
# Result: 6.034336531007678 #

Comme vous le voyez, vous récupérez la valeur de l’attribut translateX de la sphère. Rien de très compliqué vous en conviendrez. :)

Maintenant, faites :

mc.getAttr("pSphere1.translate")
# Result: [(6.034336531007678, 0.0, 3.0054366242372197)] # 

Ça renvoie une liste contenant un unique tuple de trois valeurs correspondant respectivement à l’attribut translateX, translateY et translateZ.

Pourquoi Maya renvoie une liste contenant un unique tuple et pas directement un tuple ?

Sûrement parce que getAttr() peut renvoyer plusieurs valeurs grâce à l’étoile. ;)

L’étoile (encore !)

Si ça ce n’est pas de la transition… :P

Vous pouvez donc utiliser l’étoile. Ici, on va récupérer l’attribut translate de tous les nœuds en ayant un :

mc.getAttr("*.translate")

Ce qui me renvoie :

[(0.0, 100.1, 0.0),
 (100.1, 0.0, 0.0),
 (28.0, 21.0, 28.0),
 (6.034336531007678, 0.0, 3.0054366242372197),  # << surement notre sphère… ;)
 (0.0, 0.0, 100.1)]

Comme pour la commande ls(), ce n’est pas très pratique si vous écrivez des scripts, car il est difficile de savoir à quel nœud appartient quelle valeur. Ça peut être utile pour de l’introspection et du debug manuel. :ninja:

Les types

À l’instar des nœuds, les attributs ont des types respectifs. La variable que renvoie getAttr() dépend donc du type de l’attribut que vous demandez.

Et des types d’attributs, il y en a un paquet ! :lol:

Allez sur la page de la documentation de addAttr() pour vous faire une petite idée. Ne soyez pas effrayé pour autant, c’est beaucoup plus simple que ça en a l’air. ;)

Python dispose de moins de types qui englobent pas mal de ceux des attributs Maya. Par exemple, le type d’attributs long, short et byte sont toujours retournés sous la forme d’un int Python. Idem pour float, double, doubleAngle, doubleLinear, time, qui sont tous renvoyé sous la forme d’un float Python.

Allez, un tableau non exhaustif :

Type des attributs Type Python
long, short, byte et enum int
float, double, doubleAngle, doubleLinear et time float
string string
stringArray list de string
short2 et long2 tuple de deux int
short3 et long3 tuple de trois int
float2 et double2 tuple de deux float
float3 et double3 tuple de trois float
matrix list de seize float

Vous remarquerez que les types en Python sont simplement une agrégation de types principaux (bool, int, float, str, list et tuple). Ça rend les valeurs moins compliquées à manipuler.

Ajouter à ça qu’en pratique, c’est souvent les mêmes qui sont utilisés ! :D

Intéressant, comment puis-je récupérer les types d’un attribut ?

Avec l’argument type pardi ! Reprenons nos exemples précédents :

mc.getAttr("pSphere1.translateX", type=True)
# Result: u'doubleLinear' #
mc.getAttr("pSphere1.translate", type=True)
# Result: u'double3' #

Et pour le fun : :soleil:

mc.getAttr("pSphere1.rotateOrder", type=True)
# Result: u'enum' #
mc.getAttr("pSphere1.matrix", type=True)
# Result: u'matrix' #

Il est assez rare qu’on demande le type d’un attribut directement dans un script, mais on s’en sert souvent à la main, quand on cherche à en savoir plus sur un attribut donné.

Souvent, quand on connaît le type du nœud et le nom de l’attribut, on en déduit implicitement son type.

mc.getAttr("pSphere1.matrix")
# Result: [1.0,
 0.0,
 0.0,
 0.0,
 0.0,
 1.0,
 0.0,
 0.0,
 0.0,
 0.0,
 1.0,
 0.0,
 6.034336531007678,
 0.0,
 3.0054366242372197,
 1.0] #

C’est quoi une matrice ?

Vous suivez, c’est bien. ;)

Mais c’est un gros morceau, je ne vais pas vous l’expliquer maintenant. Notez toutefois les valeurs de position de la sphère vers la fin de la liste. :-°

Les enum

Les attributs énumérés sont assez fréquents dans Maya. On s’en sert quand on souhaite avoir un attribut qui propose un choix parmi une liste établie. En interne, seul un numéro est stocké.

Par exemple, l’attribut rotateOrder est un petit menu (une combo box dans le jargon) qui propose plusieurs choix (xyz par défaut):

Les attributs de transformation
Les attributs de transformation

Essayez de récupérer la valeur de l’attribut rotateOrder:

mc.getAttr("pSphere1.rotateOrder")
# Result: 0 # 

Mais, 0 ce n’est pas la valeur de la boîte de dialogue… o_O

On va y venir. ;)

Essayez d’exécuter la commande plusieurs fois en choisissant différents ordres de rotation et observez le résultat.

1, 2, 3, c’est bien gentil tout ça. Mais des petits numéros c’est pas super pratique non ? :'(

En effet, c’est pourquoi l’argument asString existe ! :D

L’argument asString

C’est un argument spécial qui n’a d’effet que sur les attributs de type enum. Il renvoie la valeur de l’argument sous sa forme de string.

mc.getAttr("pSphere1.rotateOrder", asString=True)
# Result: u'xyz' # 

Bien plus pratique me direz-vous ! :D

En effet. Mais il faut être vigilant :

Cette string n’a de valeur informative que pour l’affichage de l’interface. Vous n’avez aucune garantie qu’elle ne change pas entre les versions de Maya.

En pratique cela pose rarement des soucis, mais il faut le savoir. :-°

time

L’argument time permet d’évaluer la valeur d’un attribut a un temps donné. Animez le déplacement de votre sphère de l’image 1 a 10 puis faites :

for frame in range(1, 11):
    print "Frame:", frame, "| Translate:", mc.getAttr("pSphere1.translate", time=frame)

Si vous ne comprenez pas ce qui se passe, vous ne savez pas ce qu’est une boucle ni la commande range(), il est temps de creuser votre tutoriel Python un peu plus. ;)

Chez moi, cela donne :

Frame: 1 | Translate: [(0.0, 0.0, 0.0)]
Frame: 2 | Translate: [(2.6587184482341937, 0.853674501465477, -0.4781830218152393)]
Frame: 3 | Translate: [(9.784083036035243, 3.1415218913576712, -1.759713366780099)]
Frame: 4 | Translate: [(20.09991122219489, 6.453779151945815, -3.615063600597007)]
Frame: 5 | Translate: [(32.330012250318575, 10.380680627726392, -5.814704811428484)]
Frame: 6 | Translate: [(45.19820996878731, 14.512465352569638, -8.129110714174649)]
Frame: 7 | Translate: [(57.42831088281122, 18.43936679171449, -10.328751904484744)]
Frame: 8 | Translate: [(67.74414203556556, 21.751625004831574, -12.184102671857667)]
Frame: 9 | Translate: [(74.86950399907123, 24.039471552101986, -13.465632544830653)]
Frame: 10 | Translate: [(77.52822107810779, 24.893145613938714, -13.943815320389263)]

Ceci vous évite d’avoir à vous déplacer dans le temps (spoil: via la commande currentTime() :ninja: ) avant de faire votre getAttr(). C’est à la fois puissant et risqué. Puissant, car cela évite bien des manipulations ; risqué, car cela ne marche pas toujours suivant l’organisation de votre graphe de nœuds.

setAttr() pour modifier des attributs

On a réussi à récupérer des nœuds ainsi que les valeurs des attributs qui les composent. Et maintenant ? Et bien on va les modifier ! Mouhahaha ! Et pour ça on va utiliser la commande setAttr().

C’est parti ! :pirate:

Repartez d’une scène vide et créez une sphère :

Créer une polySphere dans Maya
Créer une polySphere dans Maya

Euh… Tu ne nous donnes pas la page de la documentation avant de commencer ? :euh:

Palsambleu ! C’est qu’ils suivent les petits agrumes ! La voici. :D

Continuons, ne m’interrompez plus et exécutez-moi ceci sur le champ !

mc.setAttr("pSphere1.translateX", 2)

Comme vous pouvez le voir, la valeur de l’attribut translateX s’est mis à 2 et votre sphère a bougé.

Essayez de trouver des attributs et modifiez-les :

mc.setAttr("polySphere1.radius", 5)
mc.setAttr("polySphere1.subdivisionsAxis", 8)
mc.setAttr("polySphere1.subdivisionsHeight", 4)
mc.setAttr("pSphere1.visibility", False)

Je ne vous explique pas ce que font ces lignes, à vous de travailler un peu. ;)

Les attributs en chaîne de caractères

Comme vous pouvez le voir, vous pouvez modifier les attributs numériques facilement. Il existe une petite nuance concernant les attributs en chaîne de caractères (string attributes en anglais). Mais faisons un test. Vous voyez l’attribut Current UVSet ici :

Current UVSet dans Maya
Current UVSet dans Maya

Son nom de code c’est currentUVSet (je vous expliquerai plus loin comment je l’ai eu ;) ).

Regardez cette ligne puis exécutez-la :

mc.setAttr("pSphereShape1.currentUVSet", "map2")

Je ne sais pas pourquoi, mais je sens que ça ne va pas marcher. :'(

Mais pourquoi dis-tu ça ? :-°

# RuntimeError: setAttr: 'pSphereShape1.currentUVSet' is not a simple numeric attribute.  Its values must be set with a -type flag. # 

Tiens, quelle surprise ! :D

Plus sérieusement, prenez le temps de lire le message d’erreur, il est très clair et… Oh et puis allez ! Vous avez gagné un bloc bien lourd pour un point important :

D’une manière générale, les messages d’erreur de Python ou de script sont assez clairs. Ils contiennent de précieuses informations et mettent souvent le doigt sur le problème principal. Si un jour vous avez un message d’erreur que vous ne comprenez pas, cherchez le sur le Net. Dans tous les cas, une fois la solution trouvée, relisez le message d’erreur pour faire le lien entre lui et votre solution, ceci vous permettra d’aller plus vite le jour ou vous re-rencontrerez ce message.

Revenons à notre souci : si la commande setAttr() fonctionne sans soucis avec les attributs numériques (float, int, bool, etc.), certains types (dont str) nécessitent qu’on spécifie le type via l’argument… type :

mc.setAttr("pSphereShape1.currentUVSet", "map2", type="string")

Ça marche beaucoup mieux déjà ! :)

Quand on souhaite exécuter un setAttr() sur un attribut en chaîne de caractères, il faut utiliser l’argument type="string"

Bloquer un attribut avec lock

Peut-être avez-vous déjà rencontré ceci :

ou cela :

Dans les deux cas, l’attribut transform est verrouillé (locked en anglais). On peut le faire depuis l’interface de Maya (Bouton droit de souris puis (Un)Lock Attribute).

Comme je vous en parle, c’est qu’on peut faire de même en script. :-°

Voici comment verrouiller un attribut :

mc.setAttr("pSphere1.translate", lock=True)

Je vous laisse le plaisir de deviner comment déverrouiller l’attribut. ;)

Au passage, vous pouvez également utiliser l’argument lock avec getAttr() pour savoir si un attribut est verrouillé ou non.

Un aspect intéressant concernant un attribut verrouillé c’est qu’il ne peut pas être déverrouillé dans une scène en référence. Ce qui veut dire que si vous faites un rig de personnage et que vous l’importez en référence dans une scène en vu de l’animer, les animateurs ne pourront pas déverrouiller l’attribut. C’est très pratique ! :D

select() pour... Je ne sais plus pour quoi en fait...

Je ne pouvais pas finir ce premier chapitre sans vous montrer cette commande très simple à utiliser et qui vous parlera.

La commande select() (doc ici) permet de scripter tout ce qui a trait à la sélection.

Notre scène avant nos diverses sélections.
Notre scène avant nos diverses sélections.

Mon étoile filante…

Notez qu’elle est compatible avec l’étoile *. Vous pouvez donc faire des sélections par rapport à des noms particuliers. Par exemple :

mc.select('pCube*')

vous sélectionnera tous les nœuds commençant par pCube :

Plus aucun prétexte pour oublier des nœuds mal nommés dans vos scènes. ;)

Et comme on parle de vraies scènes de production, voici la suite :

mc.select('toto:*')

qui sélectionne tout le contenu d’un namespace donné :

Et une dernière variation que je n’ai pas voulu vous montrer avec la commande ls() pour ne pas trop vous surcharger :

mc.select('*:pCube*')

Ceci sélectionnera tous les nœuds commençant par pCube dans n’importe quel namespace (ici, il n’y a que toto) :

Je suis sûr que vous l’aimez déjà celle-là. :D

Sélectionner tous les nœuds

Celui-là vous vous ne vous en servirez sûrement jamais tout seul :

mc.select(all=True)

Notez comment cette commande ne sélectionne pas le contenu des groupes. ;)

En revanche, combiné à d’autres options il peut devenir intéressant.

Sélectionner tous les nœuds visibles

mc.select(all=True, visible=True)

Celui-ci je vous le montre juste pour vous donner un exemple de combinaison entre all et un autre argument. :P

Sélectionner le contenu de la hiérarchie

Mais à quoi peut-il bien servir celui-là ?

Comme vous le savez sûrement, vous pouvez sélectionner un nœud sans ses enfants :

Cette commande s’assure de sélectionner tous les enfants des nœuds sélectionnés.

mc.select(hierarchy=True)

C’est l’équivalent du Select hierarchy de Maya :

Vider la sélection

Il n’est pas rare de vouloir scripter des choses qui agissent sur la sélection. On peut devoir vider la sélection. Cela se fait comme ceci :

mc.select(clear=True)

Alterner une sélection

mc.select('pCube*', toggle=True)

Chaque appel à cette commande sélectionnera puis désélectionnera alternativement les nœuds commençant par pCube.

Sélectionner et désélectionner un (ou plusieurs) nœud(s)

Aussi évident que ça puisse paraître :

mc.select('pCube*', add=True)
mc.select('pSphere*', add=True)

Ici, la commande sélectionne tous les nœuds commençant par pCube et dans la seconde commande, l’argument add ajoute tous les nœuds commençant par pCube à la sélection :

mc.select('pCube*', deselect=True)

Et ici, l’argument deselect désélectionnera les nœuds commençant par pCube :

Vous auriez presque pu la deviner tout seul celle-là pas vrai ? :D

Remplacer la sélection

L’argument replace remplace la sélection quelle qu’elle eût été avant :

mc.select('pCube*', replace=True)

Les sets

Comme vous le savez peut-être, Maya dispose de nœuds de type set qui sont un peu particuliers, car ils permettent de stocker… une sélection.

Donc quand on sélectionne un nœud de set :

mc.select('set1')

Maya sélectionnera en fait le contenu du set et non le nœud de set lui-même :

Il faut ajouter l’argument noExpand:

mc.select('set1', noExpand=True)

Ainsi, c’est bien le nœud qui sera sélectionné et non son contenu :

Note importante concernant la commande select()

Quand un graphiste travaille au quotidien, il le fait en sélectionnant des nœuds. C’est donc par un jeu de sélection qu’il conçoit son travail dans Maya. :)

Les graphistes débutants en script dans Maya ont tendance à reproduire ce schéma et abuser de la commande select() en s’appuyant sur le mécanisme d’argument implicite des commandes (quand aucun nœud n’est fourni en argument d’une commande, Maya utilise le nœud sélectionné). :(

C’est une très mauvaise pratique, car elle vous incite à saupoudrer votre code de select() suivant ce que vous faites. Bien qu’intuitif de prime abord, gérer la sélection est plus compliqué qu’il n’y paraît :

  • Toutes les commandes ne fonctionnent pas de la même façon suivant la sélection.
  • Le code est difficilement lisible.

Utiliser select() uniquement pour sélectionner des choses pour l’utilisateur, souvent en fin de script. Mais ne vous appuyez pas dessus pour exécuter une suite de commandes. Toutes les commandes Maya peuvent fonctionner avec des arguments explicites, sans avoir recours à des sélections. :-°

Privilégiez le passage explicite de variables aux commandes Maya.


Et voilà ! Un chapitre bien costaud, mais vous avez maintenant de solides bases. :)

C’est super, mais j’avoue que je me demande comment on utilise tout ça dans un vrai script. :euh:

Ne vous inquiétez pas, le chapitre suivant sera composé de petits codes simples utilisant les commandes que vous avez apprises ici, mais en essayant de vous proposer des cas pratiques que j’espère intéressants.