API Python de Maya, les choses à savoir
Par Narann le lundi, 4 octobre 2010, 22:27 - Crashs et bugs - Lien permanent
Étant de plus en plus amené à utiliser l'API Python de Maya dans le cadre de mon travail, je remarque que beaucoup de choses ne fonctionnent pas très bien, voir, pas du tout...
L'implémentation Python (qui à au moins le mérite d'exister et d'être très pratique) est pas mal buggé... On se demande souvent si la faute vient de nous. Mais c'est une fois qu'on a réussi à isoler le bug et à trouver un workaround qu'on se rend compte que le problème n'était pas due (qu')à notre incompétence... :sourit:
Autodesk s'efforce d'améliorer son API Python au fil des versions (C'est d'ailleurs très dommageable, en prod, de devoir attendre une nouvelle version pour corriger des bugs d'API...).
La plupart des utilisateurs de l'API Python n'étant pas des développeurs (qui eux bossent, en général, en C++) mais plutôt des graphistes avancés, TD, ils leur arrive souvent de "douter".
L'idée, dans ce billet, est de parler des limitation de l'API Python de Maya que j'ai pu rencontré et qui m'ont vraiment bloqué. Le but étant que vous ne restiez pas vous même bloqué sur des trucs bêtes, comme j'ai pu l'être.
Ce billet ne se veut pas exhaustif et est bien entendu destiné au personnes qui connaissent un temps soit peu l'API. N'hésitez pas à laisser un commentaire si vous rencontrez d'autres bugs ainsi que leur workaround. :siffle:
On commence!
Sommaire
- Les MFloat(Matrix, Array, Point, etc...) (v2010)
- Les problème de typage avec les Array (v2010)
- Fin et suite
Les MFloat(Matrix, Array, Point, etc...) (v2010)
Pour éviter de retaper à chaque fois: MFloat(Matrix, Array, Point, etc...) et M(Matrix, Array, Point, etc..) dans mes exemples, je prendrais la formulation MType et MFloatType.
Un des premier point sur lequel j'ai "buté" est la conversion de l'objet Maya: MFloatMatrix et tout les objets de type MFloat(Matrix, Array, Point, etc..) en leur équivalent M(Matrix, Array, Point, etc..)
En effet, certaines méthodes et constructeurs de classes ne demande, en entré, un MType. Si on n'a pas été assez vigilant, on se retrouve avec des MFloatMatrix dans notre code python et bien entendu, si vous passez un MFloatMatrix à la place d'un MMatrix, ça vous envoi balader...
Ce "double typage" des objets Maya est fait afin de donner facilement un équivalent aux de type de nombre flottant en C:
- Double (8 octets, le "format" par défaut de Maya)
- Float (4 octets)
Autant la conversion de MType à MFloatType est assez simple en C++ (voir ce billet) autant en Python c'est beaucoup plus laborieux.
La solution la plus simple que je vous conseil est donc de bannir les MFloatType autant que possible en Python. Je n'ai pas vraiment trouvé de solution pour convertir les deux type en Python (mais c'est surement possible :baffed: ).
EDIT 2010 10 08: Sur ce billet Peter J. Richardson propose une solution (qui est en fait très simple :pasClasse: ):
myMPoint = OpenMaya.MPoint() myMFloatPoint = OpenMaya.MFloatPoint( myMPoint[0], myMPoint[1], myMPoint[2] )
Je l'ai testé et ça fonctionne très bien! J'ai un peu honte de ne pas l'avoir trouvé moi même... (Je pourrais tenter de m'excuser lamentablement en disant que quand on se met à tripatouiller l'API de Maya, les choses sont plus simple si on n'en "sort pas" :baffed: ).
EDIT 2011 02 11: La méthode ci dessus n'est pas applicable pour une MMatrix. Vous pouvez utiliser la classe MScriptUtil qui permet de créer une MMatrix ou MFloatMatrix depuis une liste (un tuple plutôt).
Voici un code qui permet de convertir une MFloatMatrix en MMatrix:
myFloatMatrix = OpenMaya.MFloatMatrix() myMatrix = OpenMaya.MMatrix() floatList = (myFloatMatrix(0,0), myFloatMatrix(0,1), myFloatMatrix(0,2), myFloatMatrix(0,3), myFloatMatrix(1,0), myFloatMatrix(1,1), myFloatMatrix(1,2), myFloatMatrix(1,3), myFloatMatrix(2,0), myFloatMatrix(2,1), myFloatMatrix(2,2), myFloatMatrix(2,3), myFloatMatrix(3,0), myFloatMatrix(3,1), myFloatMatrix(3,2), myFloatMatrix(3,3)) OpenMaya.MScriptUtil().createMatrixFromList(floatList, myMatrix)
Ne me sautez pas a la gorge de suite, c’était juste pour l'exemple :grenadelauncher: . Il y a un moyen beaucoup plus rapide de faire ça:
myFloatMatrix = OpenMaya.MFloatMatrix() myMatrix = OpenMaya.MMatrix(myFloatMatrix.matrix)
Il faut en effet utiliser l'attribut .matrix. Le résultat des deux méthodes est le même. Juste qu'il y en a une chiante a écrire et l'autre en deux lignes. :seSentCon:
Les problème de typage avec les Array (v2010)
Dans l'API, un MPointArray est une classe tableau de MPoint (logique!). L'opérateur (crochet) permet, de récupérer rapidement un MPoint dans ce tableau. (relogique!)
En C++, ça doit sûrement marcher. :gne: Mais en Python c'est une autre histoire.
Comme rien ne vaut mieux qu'un exemple:
myMPointTmp = myMPointArray[i]
Ceci fera un segmentation fault! (Le truc qui quitte Maya instantanément :siffle: ).
Après m'être arraché les cheveux, là dessus, il se trouve que la solution est assez... "Spéciale". Jugez par vous même:
inMeshMPointTmp = OpenMaya.MPoint( inMeshMPointArray[i] )
Ceci marchera impeccable! En gros, il faut ré-encapsuler ce qu'on récupère d'un Array Maya dans un objet de son type. :aupoil:
Faut avouez que c'est assez pathétique comme méthode... Mais bon.
Il faut savoir que la plupart des soucis de segmentation fault avec l'API Python sont due à ce problème de typage (Autodesk n'a pas complètement fini son travail on va dire. :seSentCon: )
N'hésitez donc pas, quand vous avez ce genre de soucis (crash sans raisons apparentes) à ré-encapsuler toutes vos variables. ça résout quelques soucis.
Fin et suite
Je continuera à ajouter des "choses bizarres" que je trouve dans l'API Python au fil du temps.
N'hésitez surtout pas à me laisser un commentaire si vous rencontrez, vous aussi, quelque chose de "tricky"! (Je sais que les MString font aussi de jolies choses! :hihi: )
A bientôt!
Dorian
Commentaires
Hello man,
je débute en api Python et j'ai bien compris ce que tu as écris :
myMPoint = OpenMaya.MPoint()
myMFloatPoint = OpenMaya.MFloatPoint( myMPoint[0], myMPoint[1], myMPoint[2] )
pas de souci.
En revanche j'ai l'impression que la conversion dans l'autre sens ne fonctionne pas ( MFloatType --> MType )
C'est peut etre idiot mais je ne comprend pas pourquoi
T'aurais une astuce ?
myMPoint = OpenMaya.MPoint( myMFloatPoint[0], myMFloatPoint[1], myMFloatPoint[2] )
Ça ne marche pas ça?
Au pire, essaye de "forcer" le type Python:
myMPoint = OpenMaya.MPoint( float(myMFloatPoint[0), float(myMFloatPoint[1]), float(myMFloatPoint[2]) )
Tiens moi au courant! ;)
sisi c'est bon en fait :)
autant pour moi l'erreur venait d'ailleur :
il s'agissait d'une boulette que je fait sans arret en python :
MTruc.insert( tmpMVector , i ) au lieu de MTruc.set( tmpMVector , i )
ca ca plante direct :)
et merci pour ta réponse aussi rapide !
Pas de soucis! ;)
Et pendant que j'y suis sais tu comment on convertit un float en double et l'inverse ?
Je ne comprend pas trop la question. ^^'
Il n'y a qu'un seul type de float en Python: float() qui est équivalent à un double en C. Il n'y a pas d'équivalent en float du C à ma connaissance.
Maintenant, si tu parle de convertir un MPoint en MFloatPoint, la seule méthode que je connaisse est celle dont on a parlé juste au dessus. :)
Arf désolé je m'explique mal :)
Je ne parle pas des type complexes mais de base.
tu sais souvent les commandes de l'api attendant des doubles en argument.
Seulement en python on manipule des float,
du coup quand je met un float en argument ba forcément il me sort
un truc du genre "erreur il faut un double et pas un float"
C'est ca qui me pose probleme, comment convertir un float en double ?
Mmmh tu aurais un exemple? :(
oh lui
Mais encore? ^^
Re, ba par exemple :
truc = 3.5
vecteur = OpenMaya.MVector( 1 , 2 , 3 )
multVecteur = vecteur * truc
ceci ferait erreur : il faut que "truc" soit un double et pas un float
j'ai reglé le probleme en faisant :
vecteur = OpenMaya.MFloatVector( 1,2,3)
multVecteur = vecteur * truc
en effet ca fonctionne car le MFloatVector est lui , multipliable
par un float et pas un double.
bref ca a fait l'affaire cette fois mais ya quand meme des cas
ou on doit VRAIMENT avoir besoin d'utiliser un double en argument sans échappatoire.
C'est a dire dans un tres grand nombre fonctions et méthode de l'api.
Du coup je me demande s'il ne vaut pas mieux utiliser les MFloatType au maximum
pour éviter ce genre de galere. Qu'en pense tu ?
Sinon il doit bien avoir moyen de faire la conversion....
En effet...
Tu a regardé du coté de MScriptUtil? C'est un classe de script créé justement pour bricoler dans ce genre de situations. :)
Dis moi si ça peut faire ce que tu souhaite faire. :)
Yep, j'avais utilisé ca pour balancer le resultat d'une fonction dans un double justement. Ca simule l'utilisation des pointers. Mais pour la conversion c'est une autre histoire...
Je te tiens au jus si je trouve, deja je suis en train de me battre avec les multi...
yo
Normalement tu peut utiliser les types direct, sans passer par des pointeurs. :(
beurk, c'est vraiment pas intuitif ce MScriptUtil >:D
tu t'en es servi pour quoi toi de cet api python ?
Principalement pour parcourir rapidement de la géométrie (vertex, face). Et pour profiter de quelques fonctions utiles.
Les possibilités sont assez larges il faut dire. ^^
certes