Dorian Fevrier a déjà écrit un article similaire sur l’utilisation des commandes maya versus l’API dans ce billet: Récupérer rapidement la position des vertices d’un mesh Maya
Pour résumer:
pSphere 50×50 smoothée 4 (soit 633602 vertices):
iteration xform: 39 sec (xform(« mesh.pt[n] »))
iteration API: 4 sec (MFnMesh.getPoints())
xform sans itération: 2 sec (xform(« mesh.pt[*] »)

Ici je vais parler d’une optimisation liée à l’utilisation d’un wrapper Python -> C++ (l’API python de maya quoi).

On est tombés, avec mon compère, vendredi dernier, en codant un algo de copie de poids de deformer indépendant d’une topologie, sur un petit souci de temps: récupération pour chaque vertex d’un mesh des vertex connectés: 45 secondes de process pour 1 000 000 de vertices… Après divers optimisations (suppression des boucles pour passer en récupération d’infos par pack puis traitement en pur python) nous sommes passés ) à une vingtaine de secondes… Mieux mais toujours énorme! Le process qui apparaissait comme long était le suivant:

it = MItMeshVertex(node.asMObject())
while not it.isDone():
    vtxList = MIntArray()
    it.getConnectedVertices(vtxList)
    related.append([vtxList[i] for i in xrange(vtxList.length())])
    it.next()

17.04 secondes pour 1002001 points

J’avais déjà été confronté à un problème de la sorte pour un wrapper purement Python, pour énormément d’objets, l’accès aux attributs pouvait être horriblement long… Idem pour la création de leurs instances! Donc que pouvait-on optimiser ici?
Sachant que la partie C++ remplit le tableau de points lui-même, il gère directement son traitement dans la sous couche C++, donc laissons le faire!

vtxList = MIntArray()
while not it.isDone():
    it.getConnectedVertices(vtxList)
    related.append([vtxList[i] for i in xrange(vtxList.length())])
    it.next()

Et bim! On passe à 8.15 secondes pour 1002001 points

Si on veut pousser mémé dans les orties et descendre à 6.60 secondes:

vtxList = MIntArray()
appd = related.append
size = vtxList.length
acces = vtxList.__getitem__
t = time.time()
while not it.isDone():
    it.getConnectedVertices(vtxList)
    appd([acces(i) for i in xrange(size())])
    it.next()

On pourrait utiliser map(acces, range(size())) qui ferait gagner un chouia, mais range supporte très mal les grands tableaux, donc on restera sur une liste compréhension et un xrange.

Edit:

Depuis peu, j’essaie d’utiliser au maximum l’API 2 qui s’avère bien plus rapide lors des post traitement des objets python (ex: conversion MIntArray -> list):

On descends à 3.20 secondes pour les mêmes nodes.

it = MItMeshVertex(ob)
while not it.isDone():
    vtxList = it.getConnectedVertices()
    related.append(list(vtxList))
    # related.append(vtxList)  # On descend à 1.09 sec
    it.next()