#!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() |