Blender (jusqu'à 2.49)
Python
scripts/macro python 
Copie miroir des actions 
    Début   Index
précédentScript Python
Script Python Suivant

Le projet de ce script est d'ajouter une série de poses directement sur les ipos action en recopiant de manière symétrique celles  qui sont   déjà en place de façon à inverser le mouvement de l'action sur tous les bones de l'armature.

    Le script peut faire les choses suivantes :
    1. reconnaitre une armature
    2. identifier les bones qui sont utilisés dans les actions
    3.  pour chaque bone de l'armature, atteindre les données correspondant à ces actions.
    4. les trier et les récupérer pour en faire un dictionnaire frame par frame.
    5. réinjecter ces données sur les courbes ipos des actions.
Télécharger un fichier d'exemple
 
#!BPY

# """
# Name: 'copy and mirror actions'
# Blender: 244
# Group: 'Animation'
# Tooltip: 'copy and mirror all the selected actions for the current armature.'
# """

# -*- coding: Latin-1 -*-

__author__ = 'Jm Soler'
__version__ = '0.1.2 2008/05/25'
__url__ = ["""jms's site, http://jmsoler.free.fr/didacticiel/blender/tutor/bpy_copy_mirror_action.htm""",
    """Support forum, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender""" ]
__email__ = ["jms, jmsoler:free.fr"]
__bpydoc__ = """\

 """ 

import Blender
from Blender import *

arm_ob=None

def doc_dpose(icu,Dpose,u,v):
  #-----
  # On doit vérifier tous les points pour au moins récupérer 
  # le numero de frame/cell  qui se  trouve dans la seconde liste 
  # de nombres à virgule flottante qui constitue un bezierpoint .
  #----- 
  for b in icu.bezierPoints:
   b0,b1,b2=b.vec
   #----- 
   # Si cette frame n'existe pas on la crée completement.
   #-----
   if int(b1[0]) not in Dpose:
    #----
    # L'entrée est constituée de trois listes : la première pour
    # les coordonnées x,y,z la seconde pour les valeurs du 
    # quaternion, la dernière pour les valeur de scale.
    #----
    Dpose[int(b1[0])]=[['a','a','a'],['a','a','a','a'],['a','a','a']]
    #----
    # Comme il nous faut un test pour savoir si une clé
    # existe sur cette courbe à ce moment précis, on charge
    # les listes avec des caractères ascii. Pour l'instant, dans
    # ce prototypage de procédure, la présence d'un 'a' exclu
    # la création du bezier point sur toutes les courbes. Il sera
    # toujours temps d'affiner l'analyse plus tard pour traiter
    # chaque courbe.
    #---- 
   Dpose[int(b1[0])][u][v]=b1[1] 
 

def mir_curve(CURFRAME,ipo,pb,arm_ob):
 #----- 
 # On filtre toutes les courbes liées à ce bone, pb, pour 
 # en extraire toutes les coordonnées de pose que l'on doit 
 # réutiliser par lasuite. La variable Dpose contient un
 # dictionnaire dont les entrée sont des numéro de frame/cell.
 #----- 
 Dpose={}
 for icu in ipo: 
  if icu != None and len(icu.bezierPoints) > 0: 
   #-----
   # On suppose que les ipos ont toutes le même nombre de clés 
   # placées sur la même frame...mais ce n'est pas obligatoirement
   # vrai.
   #-----
   #----- 
   # On ne sait pas quelle ipo peut avoir été remplie
   # 'LocX','LocY','LocZ', 'QuatX','QuatY','QuatZ',ScaleX,ScaleY,
   #  ScaleZ,  ou 'QuatW' et on n'a aucune idée du nom de la 
   # courbe courante donc on traite tous les cas
   #-----
   name=icu.name

   if name=='LocX':
    doc_dpose(icu,Dpose,0,0)
   elif name=='LocY':
    doc_dpose(icu,Dpose,0,1)
   elif name=='LocZ':
    doc_dpose(icu,Dpose,0,2)
   elif name=='QuatX':
    doc_dpose(icu,Dpose,1,0) 
   elif name=='QuatY':
    doc_dpose(icu,Dpose,1,1) 
   elif name=='QuatZ':
    doc_dpose(icu,Dpose,1,2)
   elif name=='QuatW':
    doc_dpose(icu,Dpose,1,3)
   elif name=='ScaleX':
    doc_dpose(icu,Dpose,2,0)
   elif name=='ScaleY':
    doc_dpose(icu,Dpose,2,1)
   elif name=='ScaleZ':
    doc_dpose(icu,Dpose,2,2)

 #----- 
 # S'il y en a...
 #----- 
 if Dpose:
  #----- 
  # ...on récupère les numéros de frame ....
  #
  #----- 
  frame=[f for f in Dpose]
  #----- 
  # ... on les met dans l'ordre...
  #----- 
  frame.sort()
  #----- 
  # ... on inverse la liste car on doit comment par la dernière.
  #----- 
  frame.reverse() 
  #----- 
  # Pour chaque pose on construit son symétrique par rapport 
  # à CURFRAME : CURFRAME+(CURFRAME-int(f))
  #----- 
  for f in frame:
   #-----
   # Les variables loc,quat,size permettent de savoir si on 
   # crée ou pas une clé à ce niveau.
   #-----
   loc=quat=size=0
   #----- 
   # On calcule la position de la nouvelle frame/cell.
   #----- 
   nf=CURFRAME+(CURFRAME-int(f))
   #----- 
   # on positionne le bone en fonction des paramètres récoltés .
   # ATTENTION c'est la procédure la moins évidente dans la 
   # documention.  Cette orientation doit précéder la création
   # de la pose.
   #----- 
   if 'a' not in Dpose[f][0]:
    pb.loc[:] = Dpose[f][0][0],Dpose[f][0][1],Dpose[f][0][2]
    loc=1
   if 'a' not in Dpose[f][1]:
    #----- 
    # on fait très attention au place des canaux z et w
    #----- 
    pb.quat[:] = Dpose[f][1][3],Dpose[f][1][0],Dpose[f][1][1],Dpose[f][1][2]
    quat=1
   if 'a' not in Dpose[f][2]:
    pb.size[:] = Dpose[f][2][0],Dpose[f][2][1],Dpose[f][2][2]
    size=1 
   #----- 
   # et pour finir on inserre une clé 
   #----- 
   if loc  : pb.insertKey(arm_ob, nf, Object.Pose.LOC)
   if quat : pb.insertKey(arm_ob, nf, Object.Pose.ROT)
   if size : pb.insertKey(arm_ob, nf, Object.Pose.SIZE) 

def mirror_actions():
 #---------------------------
 # 1/ on sélectionne la scène.
 #---------------------------
 scn= Scene.GetCurrent()

 #---------------------------
 # 2/ on récupère l'armature.
 #---------------------------
 arm_ob = scn.objects.active

 #---------------------------
 # 3/ on contrôle si c'est bien 
 #    une armature.
 #---------------------------
 if arm_ob and arm_ob.getType()=='Armature':
  #---------------------------
  #  4/ si c'est bien le cas, on récupère le numéro 
  #     de frame courant dont on aura besoin pour
  #     effectuer les constructions des actions "symétriques"
  #--------------------------- 
  CURFRAME = Blender.Get('curframe')

  #---------------------------
  #  5/ on récupère les poses et les actions. 
  #--------------------------- 
  pose = arm_ob.getPose()
  actions = arm_ob.getAction() 
  #---------------------------
  #   ... Comme on peut le constater les 
  # fonctions sont reliées au conteneur objet et non pas
  # aux données. 
  #---------------------------

  channel = actions.getChannelNames()
  print 'actions Channel', channel

  val=pose.bones.values()
  print 'pose.bones.values()', val

  #--------------------------- 
  # On a besoin de savoir comment les poses et les actions sont 
  # liées et cette information  n'est disponible que par 
  # l'intermédiaire des "channel"
  #
  # Les informations de positions sont enregistrées sur les ipos des 
  # actions mais il n'est pas possible de  les modifier directement 
  # ce qui serait infiniment  plus simple. On est obligé de 
  # passer par  le module pose pour inséerer des clés dont il 
  # faudra modifier les valeurs partir des ipos actions... 
  #--------------------------- 

  #--------------------------- 
  # On ne s'interesse qu'aux bones qui ont  un canal 
  # acions...
  #--------------------------- 
  for pb in val:

   if  pb.name  in  channel :
    IPO=actions.getChannelIpo(pb.name)

    mir_curve(CURFRAME,IPO,pb,arm_ob)

   else:
    print 'no ',pb.name

 else: 
  Draw.PupMenu('not an armature object')
  return

if __name__=='__main__': 
 mirror_actions()
 Blender.Window.RedrawAll() 


 
 
 
précédentScript Python
Script Python Suivant
Vers le  Haut de page

Les questions concernant cette page  peuvent être posées sur  :
 news://news.zoo-logique.org/3D.Blender


 

 

Livre en français
Blender : apprenez, pratiquez, Créez, livre, Ed. Campus Press, coll. Starter Kit
Blender Starter Kit

Forum
FAQ
Lexique
Didacticiels
Compilations
Blender2KT
Débuter
Modelage
Blender python
Materiaux
Lumière
Animation
API python (eng)
Archives nzn
Statistiques
Doc flash Sculptris
Galerie Sculptris

mon site de démos sur youtube