armature animation is not messed up when the mesh and armature objects have transformation.

python 2.4+ without any modules should work.
python 2.3 should work now also (need to import the sets module).
This commit is contained in:
Campbell Barton 2007-08-24 12:13:34 +00:00
parent bba7506598
commit a28bd3adb1

@ -40,16 +40,28 @@ will be exported as mesh data.
# ***** END GPL LICENCE BLOCK ***** # ***** END GPL LICENCE BLOCK *****
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
try:
import time
# import os # only needed for batch export, nbot used yet
except:
time = None # use this to check if they have python modules installed
# for python 2.3 support
try:
set()
except:
try:
from sets import Set as set
except:
set = None # so it complains you dont have a !
from math import degrees, atan, pi
import time
import os # only needed for batch export
import Blender import Blender
import bpy import bpy
from Blender.Mathutils import Matrix, Vector, Euler, RotationMatrix, TranslationMatrix from Blender.Mathutils import Matrix, Vector, Euler, RotationMatrix, TranslationMatrix
import BPyObject import BPyObject
reload(BPyObject)
import BPyMesh import BPyMesh
import BPySys import BPySys
import BPyMessages import BPyMessages
@ -243,10 +255,11 @@ class my_bone_class:
# end # end
def getAnimMatrix(self, frame): def getAnimMatrix(self, frame):
arm_mat = self.blenArmature.matrixWorld
if not self.parent: if not self.parent:
return mtx4_z90 * self.getPoseMatrix(frame) return mtx4_z90 * (self.getPoseMatrix(frame) * arm_mat)
else: else:
return (mtx4_z90 * self.getPoseMatrix(frame)) * (mtx4_z90 * self.parent.getPoseMatrix(frame)).invert() return (mtx4_z90 * ((self.getPoseMatrix(frame) * arm_mat))) * (mtx4_z90 * (self.parent.getPoseMatrix(frame) * arm_mat)).invert()
def flushAnimData(self): def flushAnimData(self):
self.__anim_poselist.clear() self.__anim_poselist.clear()
@ -345,7 +358,10 @@ def write(filename, batch_objects = None, \
# ---------------------------- Write the header first # ---------------------------- Write the header first
file.write(header_comment) file.write(header_comment)
if time:
curtime = time.localtime()[0:6] curtime = time.localtime()[0:6]
else:
curtime = [0,0,0,0,0,0]
# #
file.write(\ file.write(\
'''FBXHeaderExtension: { '''FBXHeaderExtension: {
@ -371,7 +387,6 @@ def write(filename, batch_objects = None, \
file.write('\nCreator: "Blender3D version %.2f"' % Blender.Get('version')) file.write('\nCreator: "Blender3D version %.2f"' % Blender.Get('version'))
# --------------- funcs for exporting # --------------- funcs for exporting
def object_tx(ob, loc, matrix, matrix_mod = None): def object_tx(ob, loc, matrix, matrix_mod = None):
''' '''
@ -380,11 +395,11 @@ def write(filename, batch_objects = None, \
if isinstance(ob, Blender.Types.BoneType): if isinstance(ob, Blender.Types.BoneType):
# we know we have a matrix # we know we have a matrix
matrix = mtx4_z90 * (matrix_mod * ob.matrix['ARMATURESPACE']) matrix = mtx4_z90 * (ob.matrix['ARMATURESPACE'] * matrix_mod)
parent = ob.parent parent = ob.parent
if parent: if parent:
par_matrix = mtx4_z90 * (matrix_mod * parent.matrix['ARMATURESPACE'].copy()) par_matrix = mtx4_z90 * (parent.matrix['ARMATURESPACE'] * matrix_mod)
matrix = matrix * par_matrix.copy().invert() matrix = matrix * par_matrix.copy().invert()
matrix_rot = matrix.rotationPart() matrix_rot = matrix.rotationPart()
@ -536,7 +551,7 @@ def write(filename, batch_objects = None, \
#file.write('\n\t\t\tProperty: "Size", "double", "",%.6f' % ((bone.head['ARMATURESPACE']-bone.tail['ARMATURESPACE']) * matrix_mod).length) #file.write('\n\t\t\tProperty: "Size", "double", "",%.6f' % ((bone.head['ARMATURESPACE']-bone.tail['ARMATURESPACE']) * matrix_mod).length)
file.write('\n\t\t\tProperty: "Size", "double", "",1') file.write('\n\t\t\tProperty: "Size", "double", "",1')
file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' % (bone.head['ARMATURESPACE']-bone.tail['ARMATURESPACE']).length) file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' % ((bone.head['ARMATURESPACE'] * matrix_mod) - (bone.tail['ARMATURESPACE'] * matrix_mod)).length)
#file.write('\n\t\t\tProperty: "LimbLength", "double", "",1') #file.write('\n\t\t\tProperty: "LimbLength", "double", "",1')
file.write('\n\t\t\tProperty: "Color", "ColorRGB", "",0.8,0.8,0.8') file.write('\n\t\t\tProperty: "Color", "ColorRGB", "",0.8,0.8,0.8')
file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8') file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8')
@ -1082,7 +1097,7 @@ def write(filename, batch_objects = None, \
i+=1 i+=1
m = mtx4_z90 * (matrix_mod * bone.matrix['ARMATURESPACE']) m = mtx4_z90 * (bone.matrix['ARMATURESPACE'] * matrix_mod)
matstr = mat4x4str(m) matstr = mat4x4str(m)
matstr_i = mat4x4str(m.invert()) matstr_i = mat4x4str(m.invert())
@ -1097,7 +1112,13 @@ def write(filename, batch_objects = None, \
file.write('\n\tModel: "Model::%s", "Mesh" {' % obname) file.write('\n\tModel: "Model::%s", "Mesh" {' % obname)
file.write('\n\t\tVersion: 232') # newline is added in write_object_props file.write('\n\t\tVersion: 232') # newline is added in write_object_props
write_object_props(ob, None, mtx)
# Apply the mesh matrix because bones arnt applied correctly if we use object transformation
# Other then that, object matricies work well on meshes.
# if this can be fixd, be sure to remove matrix multiplication on the verts.
#write_object_props(ob, None, mtx)
write_object_props(ob, None, Matrix())
file.write('\n\t\t}') file.write('\n\t\t}')
file.write('\n\t\tMultiLayer: 0') file.write('\n\t\tMultiLayer: 0')
file.write('\n\t\tMultiTake: 1') file.write('\n\t\tMultiTake: 1')
@ -1109,13 +1130,13 @@ def write(filename, batch_objects = None, \
i=-1 i=-1
for v in me.verts: for v in me.verts:
if i==-1: if i==-1:
file.write('%.6f,%.6f,%.6f' % tuple(v.co)) file.write('%.6f,%.6f,%.6f' % tuple(v.co * mtx))
i=0 i=0
else: else:
if i==7: if i==7:
file.write('\n\t\t') file.write('\n\t\t')
i=0 i=0
file.write(',%.6f,%.6f,%.6f'% tuple(v.co)) file.write(',%.6f,%.6f,%.6f'% tuple(v.co * mtx))
i+=1 i+=1
file.write('\n\t\tPolygonVertexIndex: ') file.write('\n\t\tPolygonVertexIndex: ')
i=-1 i=-1
@ -1164,16 +1185,18 @@ def write(filename, batch_objects = None, \
ReferenceInformationType: "Direct" ReferenceInformationType: "Direct"
Normals: ''') Normals: ''')
mtx_rot = mtx.rotationPart()
i=-1 i=-1
for v in me.verts: for v in me.verts:
if i==-1: if i==-1:
file.write('%.15f,%.15f,%.15f' % tuple(v.no)) file.write('%.15f,%.15f,%.15f' % tuple(v.no * mtx_rot))
i=0 i=0
else: else:
if i==2: if i==2:
file.write('\n ') file.write('\n ')
i=0 i=0
file.write(',%.15f,%.15f,%.15f' % tuple(v.no)) file.write(',%.15f,%.15f,%.15f' % tuple(v.no * mtx_rot))
i+=1 i+=1
file.write('\n\t\t}') file.write('\n\t\t}')
@ -1515,6 +1538,12 @@ def write(filename, batch_objects = None, \
if EXP_ARMATURE: if EXP_ARMATURE:
armob = BPyObject.getObjectArmature(ob) armob = BPyObject.getObjectArmature(ob)
# Note - Fixed in BPyObject but for now just copy the function because testers wont have up to date modukes,
# TODO - remove this for 2.45 release since getObjectArmature has been fixed
if (not armob) and ob.parent and ob.parent.type == 'Armature' and ob.parentType == Blender.Object.ParentTypes.ARMATURE:
armob = ob.parent
if armob: if armob:
if armob not in ob_arms: ob_arms.append(armob) if armob not in ob_arms: ob_arms.append(armob)
armname = sane_obname(armob) armname = sane_obname(armob)
@ -1692,7 +1721,8 @@ Objects: {''')
write_null(ob, obname) write_null(ob, obname)
for obname, ob, arm_my_bones, blenActions in ob_arms: for obname, ob, arm_my_bones, blenActions in ob_arms:
write_null(ob, obname) # armatures are just null's with bone children. # Dont pass the object because that writes the armature transformation which is alredy applied to the bones.
write_null(None, obname) # armatures are just null's with bone children.
for obname, ob in ob_cameras: for obname, ob in ob_cameras:
write_camera(ob, obname) write_camera(ob, obname)
@ -1976,7 +2006,9 @@ Connections: {''')
action_default = ob.action action_default = ob.action
arm_bone_names = set([mybone.blenName for mybone in arm_my_bones]) arm_bone_names = set([mybone.blenName for mybone in arm_my_bones])
for action in tmp_actions: for action in tmp_actions:
action_chan_names = arm_bone_names.intersection( set(action.getChannelNames()) ) action_chan_names = arm_bone_names.intersection( set(action.getChannelNames()) )
if action_chan_names: # at least one channel matches. if action_chan_names: # at least one channel matches.
@ -2281,6 +2313,8 @@ def fbx_ui_write(filename):
# Keep the order the same as above for simplicity # Keep the order the same as above for simplicity
# the [] is a dummy arg used for objects # the [] is a dummy arg used for objects
Blender.Window.WaitCursor(1)
write(\ write(\
filename, None,\ filename, None,\
GLOBALS['EXP_OBS_SELECTED'].val,\ GLOBALS['EXP_OBS_SELECTED'].val,\
@ -2302,6 +2336,8 @@ def fbx_ui_write(filename):
GLOBALS['BATCH_FILE_PREFIX'].val,\ GLOBALS['BATCH_FILE_PREFIX'].val,\
GLOBALS['BATCH_OWN_DIR'].val,\ GLOBALS['BATCH_OWN_DIR'].val,\
) )
Blender.Window.WaitCursor(0)
GLOBALS.clear() GLOBALS.clear()
@ -2452,6 +2488,10 @@ if __name__ == '__main__':
# Blender.Window.FileSelector(write_ui, 'Export FBX', Blender.sys.makename(ext='.fbx')) # Blender.Window.FileSelector(write_ui, 'Export FBX', Blender.sys.makename(ext='.fbx'))
#write('/scratch/test.fbx') #write('/scratch/test.fbx')
#write_ui('/scratch/test.fbx') #write_ui('/scratch/test.fbx')
if not set:
Draw.PupMenu('Error%t|A full install of python2.3 or python 2.4+ is needed to run this script.')
else:
write_ui() write_ui()