forked from bartvdbraak/blender
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:
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()
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user