[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [11853] trunk/blender/release/scripts/ export_fbx.py: Fixes
Campbell Barton
cbarton at metavr.com
Tue Aug 28 04:11:51 CEST 2007
Revision: 11853
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=11853
Author: campbellbarton
Date: 2007-08-28 04:11:49 +0200 (Tue, 28 Aug 2007)
Log Message:
-----------
Fixes
* material indicies were incorrectly exported
* export object materials using colbits
* scaled armatures would scale bones twice
* scenes with no world would raise an error
Additions
* added options for global scaling and rotating, defaults will load correctly in MotionBuilder
* modifiers can be applied to skinned meshes, the armatures are set to their rest positions for python to get the un-deformed mesh. This makes exporting a mesh with subsurf and armature applied work as expected.
* meshes with parent bones are exported as weighted meshes.
* use lamp modes for cast light and cast shadow FBX settings.
* batch exporter, scenes or groups can be exporter to a file each.
* help button to load the wiki exporter page.
Modified Paths:
--------------
trunk/blender/release/scripts/export_fbx.py
Modified: trunk/blender/release/scripts/export_fbx.py
===================================================================
--- trunk/blender/release/scripts/export_fbx.py 2007-08-27 21:45:18 UTC (rev 11852)
+++ trunk/blender/release/scripts/export_fbx.py 2007-08-28 02:11:49 UTC (rev 11853)
@@ -55,13 +55,22 @@
except:
set = None # so it complains you dont have a !
+try:
+ import os
+except:
+ os = None
+
+
+
+
import Blender
import bpy
from Blender.Mathutils import Matrix, Vector, Euler, RotationMatrix, TranslationMatrix
import BPyObject
import BPyMesh
+reload(BPyMesh)
import BPySys
import BPyMessages
@@ -152,6 +161,7 @@
else: return name + '_0'
+
# todo - Disallow the name 'Scene' and 'blend_root' - it will bugger things up.
def sane_name(data, dct):
#if not data: return None
@@ -179,97 +189,8 @@
def sane_takename(data): return sane_name(data, sane_name_mapping_take)
-# storage classes
-class my_bone_class:
- __slots__ =(\
- 'blenName',\
- 'blenBone',\
- 'blenMeshes',\
- 'restMatrix',\
- 'parent',\
- 'blenName',\
- 'fbxName',\
- 'fbxArm',\
- '__pose_bone',\
- '__anim_poselist')
-
- def __init__(self, blenBone, fbxArm):
-
- # This is so 2 armatures dont have naming conflicts since FBX bones use object namespace
- self.fbxName = sane_obname(blenBone)
-
- self.blenName = blenBone.name
- self.blenBone = blenBone
- self.blenMeshes = {} # fbxMeshObName : mesh
- self.fbxArm = fbxArm
- self.restMatrix = blenBone.matrix['ARMATURESPACE']
-
- # not used yet
- # self.restMatrixInv = self.restMatrix.copy().invert()
- # self.restMatrixLocal = None # set later, need parent matrix
-
- self.parent = None
-
- # not public
- pose = fbxArm.blenObject.getPose()
- self.__pose_bone = pose.bones[self.blenName]
-
- # store a list if matricies here, (poseMatrix, head, tail)
- # {frame:posematrix, frame:posematrix, ...}
- self.__anim_poselist = {}
-
- '''
- def calcRestMatrixLocal(self):
- if self.parent:
- self.restMatrixLocal = self.restMatrix * self.parent.restMatrix.copy().invert()
- else:
- self.restMatrixLocal = self.restMatrix.copy()
- '''
- def setPoseFrame(self, f):
- # cache pose info here, frame must be set beforehand
-
- # Didnt end up needing head or tail, if we do - here it is.
- '''
- self.__anim_poselist[f] = (\
- self.__pose_bone.poseMatrix.copy(),\
- self.__pose_bone.head.copy(),\
- self.__pose_bone.tail.copy() )
- '''
-
- self.__anim_poselist[f] = self.__pose_bone.poseMatrix.copy()
-
- # get pose from frame.
- def getPoseMatrix(self, f):
- return self.__anim_poselist[f]
- '''
- def getPoseHead(self, f):
- #return self.__pose_bone.head.copy()
- return self.__anim_poselist[f][1].copy()
- def getPoseTail(self, f):
- #return self.__pose_bone.tail.copy()
- return self.__anim_poselist[f][2].copy()
- '''
- # end
-
- def getAnimMatrix(self, frame):
- arm_mat = self.fbxArm.matrixWorld
- if not self.parent:
- return mtx4_z90 * (self.getPoseMatrix(frame) * arm_mat)
- else:
- return (mtx4_z90 * ((self.getPoseMatrix(frame) * arm_mat))) * (mtx4_z90 * (self.parent.getPoseMatrix(frame) * arm_mat)).invert()
-
- def flushAnimData(self):
- self.__anim_poselist.clear()
-class my_object_generic:
- # Other settings can be applied for each type - mesh, armature etc.
- def __init__(self, ob):
- self.fbxName = sane_obname(ob)
- self.blenObject = ob
- self.matrixWorld = ob.matrixWorld
-
-
def mat4x4str(mat):
return '%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f' % tuple([ f for v in mat for f in v ])
@@ -312,48 +233,225 @@
EXP_CAMERA = True,
EXP_EMPTY = True,
EXP_IMAGE_COPY = False,
+ GLOBAL_MATRIX = Matrix(),
ANIM_ENABLE = True,
ANIM_OPTIMIZE = True,
ANIM_OPTIMIZE_PRECISSION = 6,
- ANIM_ACTION_ALL = True,
+ ANIM_ACTION_ALL = False,
BATCH_ENABLE = False,
BATCH_GROUP = True,
BATCH_SCENE = False,
BATCH_FILE_PREFIX = '',
BATCH_OWN_DIR = False
):
+
- """
+
+
# ----------------- Batch support!
if BATCH_ENABLE:
+ if os == None: BATCH_OWN_DIR = False
+
+ fbxpath = filename
+
# get the path component of filename
+ tmp_exists = Blender.sys.exists(fbxpath)
+ if tmp_exists != 2: # a file, we want a path
+ while fbxpath and fbxpath[-1] not in ('/', '\\'):
+ fbxpath = fbxpath[:-1]
+ if not filename:
+ Draw.PupMenu('Error%t|Directory does not exist!')
+ return
+
+ tmp_exists = Blender.sys.exists(fbxpath)
- # call this function within a loop with BATCH_ENABLE == False
+ if tmp_exists != 2:
+ Draw.PupMenu('Error%t|Directory does not exist!')
+ return
+
+ if not fbxpath.endswith(Blender.sys.sep):
+ fbxpath += Blender.sys.sep
+ del tmp_exists
+
+
if BATCH_GROUP:
data_seq = bpy.data.groups
- else: # must be scene
+ else:
data_seq = bpy.data.scenes
+ # call this function within a loop with BATCH_ENABLE == False
+ orig_sce = bpy.data.scenes.active
-
-
+ new_fbxpath = fbxpath # own dir option modifies, we need to keep an original
for data in data_seq: # scene or group
- newname = BATCH_FILE_PREFIX + BPySys.cleanName(data)
+ newname = BATCH_FILE_PREFIX + BPySys.cleanName(data.name)
if BATCH_OWN_DIR:
- # make dir
-
- return
+ new_fbxpath = fbxpath + newname + Blender.sys.sep
+ # path may alredy exist
+ # TODO - might exist but be a file. unlikely but should probably account for it.
+
+ if Blender.sys.exists(new_fbxpath) == 0:
+ os.mkdir(new_fbxpath)
+
+
+ filename = new_fbxpath + newname + '.fbx'
+
+ print '\nBatch exporting %s as...\n\t"%s"' % (data, filename)
+
+ if BATCH_GROUP: #group
+ # group, so objects update properly, add a dummy scene.
+ sce = bpy.data.scenes.new()
+ sce.Layers = (1<<20) -1
+ bpy.data.scenes.active = sce
+ for ob_base in data.objects:
+ sce.objects.link(ob_base)
+
+ sce.update(1)
+
+ # TODO - BUMMER! Armatures not in the group wont animate the mesh
+
+ else:# scene
+
+
+ data_seq.active = data
+
+
+ # Call self with modified args
+ # Dont pass batch options since we alredy usedt them
+ write(filename, data.objects,
+ False,
+ EXP_MESH,
+ EXP_MESH_APPLY_MOD,
+ EXP_MESH_HQ_NORMALS,
+ EXP_ARMATURE,
+ EXP_LAMP,
+ EXP_CAMERA,
+ EXP_EMPTY,
+ EXP_IMAGE_COPY,
+ GLOBAL_MATRIX,
+ ANIM_ENABLE,
+ ANIM_OPTIMIZE,
+ ANIM_OPTIMIZE_PRECISSION,
+ ANIM_ACTION_ALL
+ )
+
+ if BATCH_GROUP:
+ # remove temp group scene
+ bpy.data.scenes.unlink(sce)
+
+ bpy.data.scenes.active = orig_sce
+
+ return # so the script wont run after we have batch exported.
# end batch support
- """
+
+ # ----------------------------------------------
+ # storage classes
+ class my_bone_class:
+ __slots__ =(\
+ 'blenName',\
+ 'blenBone',\
+ 'blenMeshes',\
+ 'restMatrix',\
+ 'parent',\
+ 'blenName',\
+ 'fbxName',\
+ 'fbxArm',\
+ '__pose_bone',\
+ '__anim_poselist')
+
+ def __init__(self, blenBone, fbxArm):
+
+ # This is so 2 armatures dont have naming conflicts since FBX bones use object namespace
+ self.fbxName = sane_obname(blenBone)
+
+ self.blenName = blenBone.name
+ self.blenBone = blenBone
+ self.blenMeshes = {} # fbxMeshObName : mesh
+ self.fbxArm = fbxArm
+ self.restMatrix = blenBone.matrix['ARMATURESPACE']
+
+ # not used yet
+ # self.restMatrixInv = self.restMatrix.copy().invert()
+ # self.restMatrixLocal = None # set later, need parent matrix
+
+ self.parent = None
+
+ # not public
+ pose = fbxArm.blenObject.getPose()
+ self.__pose_bone = pose.bones[self.blenName]
+
+ # store a list if matricies here, (poseMatrix, head, tail)
+ # {frame:posematrix, frame:posematrix, ...}
+ self.__anim_poselist = {}
+
+ '''
+ def calcRestMatrixLocal(self):
+ if self.parent:
+ self.restMatrixLocal = self.restMatrix * self.parent.restMatrix.copy().invert()
+ else:
+ self.restMatrixLocal = self.restMatrix.copy()
+ '''
+ def setPoseFrame(self, f):
+ # cache pose info here, frame must be set beforehand
+
+ # Didnt end up needing head or tail, if we do - here it is.
+ '''
+ self.__anim_poselist[f] = (\
+ self.__pose_bone.poseMatrix.copy(),\
+ self.__pose_bone.head.copy(),\
+ self.__pose_bone.tail.copy() )
+ '''
+
+ self.__anim_poselist[f] = self.__pose_bone.poseMatrix.copy()
+
+ # get pose from frame.
+ def getPoseMatrix(self, f):# ----------------------------------------------
+ return self.__anim_poselist[f]
+ '''
+ def getPoseHead(self, f):
+ #return self.__pose_bone.head.copy()
+ return self.__anim_poselist[f][1].copy()
+ def getPoseTail(self, f):
+ #return self.__pose_bone.tail.copy()
+ return self.__anim_poselist[f][2].copy()
+ '''
+ # end
+
+ def getAnimMatrix(self, frame):
+ arm_mat = self.fbxArm.matrixWorld
+ if not self.parent:
+ return mtx4_z90 * (self.getPoseMatrix(frame) * arm_mat)
+ else:
+ return (mtx4_z90 * ((self.getPoseMatrix(frame) * arm_mat))) * (mtx4_z90 * (self.parent.getPoseMatrix(frame) * arm_mat)).invert()
+
+ def flushAnimData(self):
+ self.__anim_poselist.clear()
+
+
+ class my_object_generic:
+ # Other settings can be applied for each type - mesh, armature etc.
+ def __init__(self, ob):
+ self.fbxName = sane_obname(ob)
+ self.blenObject = ob
+ self.matrixWorld = ob.matrixWorld * GLOBAL_MATRIX
+ # ----------------------------------------------
+
+
+
+
+
+
+
+
print '\nFBX export starting...', filename
start_time = Blender.sys.time()
file = open(filename, 'w')
@@ -391,7 +489,6 @@
file.write('\nCreationTime: "%.4i-%.2i-%.2i %.2i:%.2i:%.2i:000"' % curtime)
file.write('\nCreator: "Blender3D version %.2f"' % Blender.Get('version'))
-
# --------------- funcs for exporting
def object_tx(ob, loc, matrix, matrix_mod = None):
'''
@@ -414,7 +511,7 @@
rot = tuple(matrix_rot.toEuler())
else:
- if ob and not matrix: matrix = ob.matrixWorld
+ if ob and not matrix: matrix = ob.matrixWorld * GLOBAL_MATRIX
matrix_rot = matrix
#if matrix:
# matrix = matrix_scale * matrix
@@ -560,9 +657,14 @@
#((my_bone.blenData.head['ARMATURESPACE'] * my_bone.fbxArm.matrixWorld) - (my_bone.blenData.tail['ARMATURESPACE'] * my_bone.fbxArm.matrixWorld)).length)
+ """
file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' %\
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list