cleanup and fixed more problems with namespace collisions (should be all solved by name)

This commit is contained in:
2007-08-26 01:35:03 +00:00
parent e7a2a175df
commit ba6f02fb29

View File

@@ -61,11 +61,11 @@ 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
import sys
def copy_file(source, dest): def copy_file(source, dest):
file = open(source, 'rb') file = open(source, 'rb')
@@ -102,7 +102,6 @@ def copy_images(dest_dir, textures):
print '\tCopied %d images' % copyCount print '\tCopied %d images' % copyCount
mtx_z90 = RotationMatrix(90, 3, 'z') mtx_z90 = RotationMatrix(90, 3, 'z')
mtx_x90 = RotationMatrix(90, 3, 'x') mtx_x90 = RotationMatrix(90, 3, 'x')
@@ -129,41 +128,19 @@ YVECN = Vector(0, -1, 0)
ZVEC = Vector(0, 0, 1) ZVEC = Vector(0, 0, 1)
ZVECN = Vector(0, 0, -1) ZVECN = Vector(0, 0, -1)
# Used to add the scene name into the filename without using odd chars
def strip_path(p):
return p.split('\\')[-1].split('/')[-1]
# Used to add the scene name into the filename without using odd chars
sane_name_mapping_ob = {} sane_name_mapping_ob = {}
sane_name_mapping_mat = {} sane_name_mapping_mat = {}
sane_name_mapping_tex = {} sane_name_mapping_tex = {}
sane_name_mapping_take = {} sane_name_mapping_take = {}
def strip_path(p): # Make sure reserved names are not used
return p.split('\\')[-1].split('/')[-1] sane_name_mapping_ob['Scene'] = 'Scene_'
sane_name_mapping_ob['blend_root'] = 'blend_root_'
# todo - Disallow the name 'Scene' and 'blend_root' - it will bugger things up.
def sane_name(data, dct):
if not data: return None
name = data.name
try: return dct[name]
except: pass
orig_name = name
if not name:
name = 'unnamed' # blank string, ASKING FOR TROUBLE!
else:
name = BPySys.cleanName(name)
# Unlikely but make sure reserved names arnt used
if name == 'Scene': name = 'Scene_'
elif name == 'blend_root': name = 'blend_root_'
dct[orig_name] = name
return name
def sane_obname(data): return sane_name(data, sane_name_mapping_ob)
def sane_matname(data): return sane_name(data, sane_name_mapping_mat)
def sane_texname(data): return sane_name(data, sane_name_mapping_tex)
def sane_takename(data): return sane_name(data, sane_name_mapping_take)
def increment_string(t): def increment_string(t):
name = t name = t
@@ -174,37 +151,57 @@ def increment_string(t):
if num: return '%s%d' % (name, int(num)+1) if num: return '%s%d' % (name, int(num)+1)
else: return name + '_0' 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
name = data.name
# dont cache, only ever call once for each data type now,
# so as to avoid namespace collision between types - like with objects <-> bones
#try: return dct[name]
#except: pass
orig_name = name
if not name:
name = 'unnamed' # blank string, ASKING FOR TROUBLE!
else:
name = BPySys.cleanName(name)
while name in dct.itervalues(): name = increment_string(name)
dct[orig_name] = name
return name
def sane_obname(data): return sane_name(data, sane_name_mapping_ob)
def sane_matname(data): return sane_name(data, sane_name_mapping_mat)
def sane_texname(data): return sane_name(data, sane_name_mapping_tex)
def sane_takename(data): return sane_name(data, sane_name_mapping_take)
# storage classes # storage classes
class my_bone_class: class my_bone_class:
__slots__ =(\ __slots__ =(\
'blenName',\ 'blenName',\
'blenBone',\ 'blenBone',\
'blenMeshes',\ 'blenMeshes',\
'blenArmature',\
'restMatrix',\ 'restMatrix',\
'parent',\ 'parent',\
'blenName',\ 'blenName',\
'fbxName',\ 'fbxName',\
'fbxArmObName',\ 'fbxArm',\
'__pose_bone',\ '__pose_bone',\
'__anim_poselist') '__anim_poselist')
unique_names = set() def __init__(self, blenBone, fbxArm):
def __init__(self, blenBone, blenArmature, fbxArmObName):
# This is so 2 armatures dont have naming conflicts since FBX bones use object namespace # This is so 2 armatures dont have naming conflicts since FBX bones use object namespace
fbxName = sane_obname(blenBone) self.fbxName = sane_obname(blenBone)
while fbxName in my_bone_class.unique_names: fbxName = increment_string(fbxName)
self.fbxName = fbxName
my_bone_class.unique_names.add(fbxName)
self.fbxArmObName = fbxArmObName
self.blenName = blenBone.name self.blenName = blenBone.name
self.blenBone = blenBone self.blenBone = blenBone
self.blenMeshes = {} # fbxMeshObName : mesh self.blenMeshes = {} # fbxMeshObName : mesh
self.blenArmature = blenArmature self.fbxArm = fbxArm
self.restMatrix = blenBone.matrix['ARMATURESPACE'] self.restMatrix = blenBone.matrix['ARMATURESPACE']
# not used yet # not used yet
@@ -214,7 +211,7 @@ class my_bone_class:
self.parent = None self.parent = None
# not public # not public
pose = blenArmature.getPose() pose = fbxArm.blenObject.getPose()
self.__pose_bone = pose.bones[self.blenName] self.__pose_bone = pose.bones[self.blenName]
# store a list if matricies here, (poseMatrix, head, tail) # store a list if matricies here, (poseMatrix, head, tail)
@@ -255,7 +252,7 @@ class my_bone_class:
# end # end
def getAnimMatrix(self, frame): def getAnimMatrix(self, frame):
arm_mat = self.blenArmature.matrixWorld arm_mat = self.fbxArm.matrixWorld
if not self.parent: if not self.parent:
return mtx4_z90 * (self.getPoseMatrix(frame) * arm_mat) return mtx4_z90 * (self.getPoseMatrix(frame) * arm_mat)
else: else:
@@ -265,6 +262,14 @@ class my_bone_class:
self.__anim_poselist.clear() 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): 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 ]) 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 ])
@@ -543,15 +548,21 @@ def write(filename, batch_objects = None, \
# -------------------------------------------- Armatures # -------------------------------------------- Armatures
def write_bone(bone, name, matrix_mod): #def write_bone(bone, name, matrix_mod):
file.write('\n\tModel: "Model::%s", "Limb" {' % name) def write_bone(my_bone):
file.write('\n\tModel: "Model::%s", "Limb" {' % my_bone.fbxName)
file.write('\n\t\tVersion: 232') file.write('\n\t\tVersion: 232')
write_object_props(bone, None, None, matrix_mod) write_object_props(my_bone.blenBone, None, None, my_bone.fbxArm.matrixWorld)
#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' % ((my_bone.blenData.head['ARMATURESPACE'] - my_bone.blenData.tail['ARMATURESPACE']) * my_bone.fbxArm.matrixWorld).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'] * matrix_mod) - (bone.tail['ARMATURESPACE'] * matrix_mod)).length)
#((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' %\
((my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']) * my_bone.fbxArm.matrixWorld).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')
@@ -685,7 +696,7 @@ def write(filename, batch_objects = None, \
write_camera_dummy('Producer Right', (4000,0,0), 1, 30000, 1, (0,1,0)) write_camera_dummy('Producer Right', (4000,0,0), 1, 30000, 1, (0,1,0))
write_camera_dummy('Producer Left', (-4000,0,0), 1, 30000, 1, (0,1,0)) write_camera_dummy('Producer Left', (-4000,0,0), 1, 30000, 1, (0,1,0))
def write_camera(ob, name): def write_camera(my_cam):
''' '''
Write a blender camera Write a blender camera
''' '''
@@ -694,11 +705,11 @@ def write(filename, batch_objects = None, \
height = render.sizeY height = render.sizeY
aspect = float(width)/height aspect = float(width)/height
data = ob.data data = my_cam.blenObject.data
file.write('\n\tModel: "Model::%s", "Camera" {' % name ) file.write('\n\tModel: "Model::%s", "Camera" {' % my_cam.fbxName )
file.write('\n\t\tVersion: 232') file.write('\n\t\tVersion: 232')
loc, rot, scale, matrix, matrix_rot = write_object_props(ob) loc, rot, scale, matrix, matrix_rot = write_object_props(my_cam.blenObject)
file.write('\n\t\t\tProperty: "Roll", "Roll", "A+",0') file.write('\n\t\t\tProperty: "Roll", "Roll", "A+",0')
file.write('\n\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",%.6f' % data.angle) file.write('\n\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",%.6f' % data.angle)
@@ -798,12 +809,12 @@ def write(filename, batch_objects = None, \
file.write('\n\t\tCameraOrthoZoom: 1') file.write('\n\t\tCameraOrthoZoom: 1')
file.write('\n\t}') file.write('\n\t}')
def write_light(ob, name): def write_light(my_light):
light = ob.data light = my_light.blenObject.data
file.write('\n\tModel: "Model::%s", "Light" {' % name) file.write('\n\tModel: "Model::%s", "Light" {' % my_light.fbxName)
file.write('\n\t\tVersion: 232') file.write('\n\t\tVersion: 232')
write_object_props(ob) write_object_props(my_light.blenObject)
# Why are these values here twice?????? - oh well, follow the holy sdk's output # Why are these values here twice?????? - oh well, follow the holy sdk's output
@@ -843,7 +854,7 @@ def write(filename, batch_objects = None, \
file.write('\n\t\t\tProperty: "EnableFarAttenuation", "bool", "",0') file.write('\n\t\t\tProperty: "EnableFarAttenuation", "bool", "",0')
file.write('\n\t\t\tProperty: "FarAttenuationStart", "double", "",0') file.write('\n\t\t\tProperty: "FarAttenuationStart", "double", "",0')
file.write('\n\t\t\tProperty: "FarAttenuationEnd", "double", "",0') file.write('\n\t\t\tProperty: "FarAttenuationEnd", "double", "",0')
file.write('\n\t\t\tProperty: "CastShadows", "bool", "",0') file.write('\n\t\t\tProperty: "CastShadows", "bool", "",0') # TODO
file.write('\n\t\t\tProperty: "ShadowColor", "ColorRGBA", "",0,0,0,1') file.write('\n\t\t\tProperty: "ShadowColor", "ColorRGBA", "",0,0,0,1')
file.write('\n\t\t}') file.write('\n\t\t}')
file.write('\n\t\tMultiLayer: 0') file.write('\n\t\tMultiLayer: 0')
@@ -854,11 +865,15 @@ def write(filename, batch_objects = None, \
file.write('\n\t\tGeometryVersion: 124') file.write('\n\t\tGeometryVersion: 124')
file.write('\n\t}') file.write('\n\t}')
def write_null(ob, name): def write_null(my_null, fbxName = None):
# ob can be null # ob can be null
file.write('\n\tModel: "Model::%s", "Null" {' % name) if not fbxName: fbxName = my_null.fbxName
file.write('\n\tModel: "Model::%s", "Null" {' % fbxName)
file.write('\n\t\tVersion: 232') file.write('\n\t\tVersion: 232')
write_object_props(ob) if my_null: write_object_props(my_null.blenObject)
else: write_object_props()
file.write(''' file.write('''
} }
MultiLayer: 0 MultiLayer: 0
@@ -1041,7 +1056,9 @@ def write(filename, batch_objects = None, \
# in the example was 'Bip01 L Thigh_2' # in the example was 'Bip01 L Thigh_2'
#def write_sub_deformer_skin(obname, group_name, bone, me, matrix_mod): #def write_sub_deformer_skin(obname, group_name, bone, me, matrix_mod):
def write_sub_deformer_skin(obname, group_name, bone, weights, matrix_mod): #def write_sub_deformer_skin(obname, group_name, bone, weights, matrix_mod):
def write_sub_deformer_skin(my_mesh, my_bone, weights):
''' '''
Each subdeformer is spesific to a mesh, but the bone it links to can be used by many sub-deformers Each subdeformer is spesific to a mesh, but the bone it links to can be used by many sub-deformers
So the SubDeformer needs the mesh-object name as a prefix to make it unique So the SubDeformer needs the mesh-object name as a prefix to make it unique
@@ -1049,8 +1066,8 @@ def write(filename, batch_objects = None, \
Its possible that there is no matching vgroup in this mesh, in that case no verts are in the subdeformer, Its possible that there is no matching vgroup in this mesh, in that case no verts are in the subdeformer,
a but silly but dosnt really matter a but silly but dosnt really matter
''' '''
file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {' % (my_mesh.fbxName, my_bone.fbxName))
file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {' % (obname, group_name))
file.write(''' file.write('''
Version: 100 Version: 100
MultiLayer: 0 MultiLayer: 0
@@ -1064,7 +1081,7 @@ def write(filename, batch_objects = None, \
try: try:
# Before we used normalized wright list # Before we used normalized wright list
#vgroup_data = me.getVertsFromGroup(bone.name, 1) #vgroup_data = me.getVertsFromGroup(bone.name, 1)
group_index = weights[0].index(bone.name) group_index = weights[0].index(my_bone.blenName)
vgroup_data = [(j, weight[group_index]) for j, weight in enumerate(weights[1]) if weight[group_index]] vgroup_data = [(j, weight[group_index]) for j, weight in enumerate(weights[1]) if weight[group_index]]
except: except:
vgroup_data = [] vgroup_data = []
@@ -1097,27 +1114,24 @@ def write(filename, batch_objects = None, \
i+=1 i+=1
m = mtx4_z90 * (bone.matrix['ARMATURESPACE'] * matrix_mod) m = mtx4_z90 * (my_bone.restMatrix * my_bone.fbxArm.matrixWorld)
matstr = mat4x4str(m) matstr = mat4x4str(m)
matstr_i = mat4x4str(m.invert()) matstr_i = mat4x4str(m.invert())
# --- try more here
# It seems fine to have these matricies the same! - worldspace bone or pose locations?
file.write('\n\t\tTransform: %s' % matstr_i) # THIS IS __NOT__ THE GLOBAL MATRIX AS DOCUMENTED :/ file.write('\n\t\tTransform: %s' % matstr_i) # THIS IS __NOT__ THE GLOBAL MATRIX AS DOCUMENTED :/
file.write('\n\t\tTransformLink: %s' % matstr) file.write('\n\t\tTransformLink: %s' % matstr)
file.write('\n\t}') file.write('\n\t}')
def write_mesh(obname, ob, mtx, me, mats, arm, armname): #def write_mesh(obname, ob, mtx, me, mats, arm, armname):
def write_mesh(my_mesh):
file.write('\n\tModel: "Model::%s", "Mesh" {' % obname) file.write('\n\tModel: "Model::%s", "Mesh" {' % my_mesh.fbxName)
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
# Apply the mesh matrix because bones arnt applied correctly if we use object transformation # Apply the mesh matrix because bones arnt applied correctly if we use object transformation
# Other then that, object matricies work well on meshes. # Other then that, object matricies work well on meshes.
# if this can be fixd, be sure to remove matrix multiplication on the verts. # 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, mtx)
write_object_props(ob, None, Matrix()) write_object_props(my_mesh.blenObject, None, Matrix())
file.write('\n\t\t}') file.write('\n\t\t}')
file.write('\n\t\tMultiLayer: 0') file.write('\n\t\tMultiLayer: 0')
@@ -1125,18 +1139,20 @@ def write(filename, batch_objects = None, \
file.write('\n\t\tShading: Y') file.write('\n\t\tShading: Y')
file.write('\n\t\tCulling: "CullingOff"') file.write('\n\t\tCulling: "CullingOff"')
me = my_mesh.blenData
# Write the Real Mesh data here # Write the Real Mesh data here
file.write('\n\t\tVertices: ') file.write('\n\t\tVertices: ')
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 * mtx)) file.write('%.6f,%.6f,%.6f' % tuple(v.co * my_mesh.matrix))
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 * mtx)) file.write(',%.6f,%.6f,%.6f'% tuple(v.co * my_mesh.matrix))
i+=1 i+=1
file.write('\n\t\tPolygonVertexIndex: ') file.write('\n\t\tPolygonVertexIndex: ')
i=-1 i=-1
@@ -1185,7 +1201,8 @@ def write(filename, batch_objects = None, \
ReferenceInformationType: "Direct" ReferenceInformationType: "Direct"
Normals: ''') Normals: ''')
mtx_rot = mtx.rotationPart() # wont handle non uniform scaling properly
mtx_rot = my_mesh.matrix.rotationPart()
i=-1 i=-1
for v in me.verts: for v in me.verts:
@@ -1350,7 +1367,7 @@ def write(filename, batch_objects = None, \
# Build a material mapping for this # Build a material mapping for this
material_mapping_local = {} # local-index : global index. material_mapping_local = {} # local-index : global index.
for i, mat in enumerate(mats): for i, mat in enumerate(my_mesh.blenMaterials):
if mat: if mat:
material_mapping_local[i] = material_mapping[mat.name] material_mapping_local[i] = material_mapping[mat.name]
else: else:
@@ -1488,17 +1505,17 @@ def write(filename, batch_objects = None, \
tmp_ob_type = ob.type tmp_ob_type = ob.type
if tmp_ob_type == 'Camera': if tmp_ob_type == 'Camera':
if EXP_CAMERA: if EXP_CAMERA:
ob_cameras.append((sane_obname(ob), ob)) ob_cameras.append(my_object_generic(ob))
elif tmp_ob_type == 'Lamp': elif tmp_ob_type == 'Lamp':
if EXP_LAMP: if EXP_LAMP:
ob_lights.append((sane_obname(ob), ob)) ob_lights.append(my_object_generic(ob))
elif tmp_ob_type == 'Armature': elif tmp_ob_type == 'Armature':
if EXP_ARMATURE: if EXP_ARMATURE:
if ob not in ob_arms: ob_arms.append(ob) if ob not in ob_arms: ob_arms.append(ob)
# ob_arms.append(ob) # replace later. was "ob_arms.append(sane_obname(ob), ob)" # ob_arms.append(ob) # replace later. was "ob_arms.append(sane_obname(ob), ob)"
elif tmp_ob_type == 'Empty': elif tmp_ob_type == 'Empty':
if EXP_EMPTY: if EXP_EMPTY:
ob_null.append((sane_obname(ob), ob)) ob_null.append(my_object_generic(ob))
elif EXP_MESH: elif EXP_MESH:
if EXP_MESH_APPLY_MOD: if EXP_MESH_APPLY_MOD:
me = BPyMesh.getMeshFromObject(ob) me = BPyMesh.getMeshFromObject(ob)
@@ -1512,7 +1529,6 @@ def write(filename, batch_objects = None, \
meshes_to_clear.append( me ) meshes_to_clear.append( me )
if me: if me:
# This WILL modify meshes in blender if EXP_MESH_APPLY_MOD is disabled. # This WILL modify meshes in blender if EXP_MESH_APPLY_MOD is disabled.
# so strictly this is bad. but only in rare cases would it have negative results # so strictly this is bad. but only in rare cases would it have negative results
# say with dupliverts the objects would rotate a bit differently # say with dupliverts the objects would rotate a bit differently
@@ -1534,8 +1550,6 @@ def write(filename, batch_objects = None, \
me.activeUVLayer = uvlayer_orig me.activeUVLayer = uvlayer_orig
obname = sane_obname(ob)
if EXP_ARMATURE: if EXP_ARMATURE:
armob = BPyObject.getObjectArmature(ob) armob = BPyObject.getObjectArmature(ob)
@@ -1545,56 +1559,75 @@ def write(filename, batch_objects = None, \
armob = ob.parent armob = ob.parent
if armob: if armob:
if armob not in ob_arms: ob_arms.append(armob) if armob not in ob_arms:
armname = sane_obname(armob) ob_arms.append(armob)
else:
armname = None
else: else:
armob = armname = None armob = None
ob_meshes.append( (obname, ob, mtx, me, mats, armob, armname) ) #ob_meshes.append( (obname, ob, mtx, me, mats, armob, armname) )
my_mesh = my_object_generic(ob)
my_mesh.matrix = mtx
my_mesh.blenData = me
my_mesh.blenMaterials = mats
my_mesh.fbxArm = armob # replace with my_armature class later
ob_meshes.append( my_mesh )
del tmp_ob_type, tmp_objects del tmp_ob_type, tmp_objects
# now we have collected all armatures, add bones # now we have collected all armatures, add bones
for i, ob in enumerate(ob_arms): for i, ob in enumerate(ob_arms):
fbxArmObName = sane_obname(ob)
arm_my_bones = []
# fbxName, blenderObject, myBones, blenderActions ob_arms[i] = my_arm = my_object_generic(ob)
ob_arms[i] = fbxArmObName, ob, arm_my_bones, (ob.action, [])
for bone in ob.data.bones.values(): my_arm.fbxBones = []
mybone = my_bone_class(bone, ob, fbxArmObName) my_arm.blenData = ob.data
my_arm.blenAction = ob.action
my_arm.blenActionList = []
arm_my_bones.append( mybone ) # fbxName, blenderObject, my_bones, blenderActions
ob_bones.append( mybone ) #ob_arms[i] = fbxArmObName, ob, arm_my_bones, (ob.action, [])
# add the meshes to the bones for bone in my_arm.blenData.bones.values():
for obname, ob, mtx, me, mats, arm, armname in ob_meshes: my_bone = my_bone_class(bone, my_arm)
for mybone in ob_bones: my_arm.fbxBones.append( my_bone )
if mybone.blenArmature == arm: ob_bones.append( my_bone )
mybone.blenMeshes[obname] = me
# add the meshes to the bones and replace the meshes armature with own armature class
#for obname, ob, mtx, me, mats, arm, armname in ob_meshes:
for my_mesh in ob_meshes:
# Replace
# ...this could be sped up with dictionary mapping but its unlikely for
# it ever to be a bottleneck - (would need 100+ meshes using armatures)
if my_mesh.fbxArm:
for my_arm in ob_arms:
if my_arm.blenObject == my_mesh.fbxArm:
my_mesh.fbxArm = my_arm
break
for my_bone in ob_bones:
if my_bone.fbxArm == my_mesh.fbxArm:
my_bone.blenMeshes[my_mesh.fbxName] = me
bone_deformer_count = 0 # count how many bones deform a mesh bone_deformer_count = 0 # count how many bones deform a mesh
mybone_blenParent = None my_bone_blenParent = None
for mybone in ob_bones: for my_bone in ob_bones:
mybone_blenParent = mybone.blenBone.parent my_bone_blenParent = my_bone.blenBone.parent
if mybone_blenParent: if my_bone_blenParent:
for mybone_parent in ob_bones: for my_bone_parent in ob_bones:
# Note 2.45rc2 you can compare bones normally # Note 2.45rc2 you can compare bones normally
if mybone_blenParent.name == mybone_parent.blenName and mybone.blenArmature == mybone_parent.blenArmature: if my_bone_blenParent.name == my_bone_parent.blenName and my_bone.fbxArm == my_bone_parent.fbxArm:
mybone.parent = mybone_parent my_bone.parent = my_bone_parent
break break
# Not used at the moment # Not used at the moment
# mybone.calcRestMatrixLocal() # my_bone.calcRestMatrixLocal()
bone_deformer_count += len(mybone.blenMeshes) bone_deformer_count += len(my_bone.blenMeshes)
del mybone_blenParent del my_bone_blenParent
materials = [(sane_matname(mat), mat) for mat in materials.itervalues()] materials = [(sane_matname(mat), mat) for mat in materials.itervalues()]
textures = [(sane_texname(img), img) for img in textures.itervalues()] textures = [(sane_texname(img), img) for img in textures.itervalues()]
@@ -1676,12 +1709,13 @@ Definitions: {
tmp = 0 tmp = 0
# Add deformer nodes # Add deformer nodes
for obname, ob, mtx, me, mats, arm, armname in ob_meshes: for my_mesh in ob_meshes:
if arm: if my_mesh.fbxArm:
tmp+=1 tmp+=1
# Add subdeformers # Add subdeformers
for mybone in ob_bones: for my_bone in ob_bones:
tmp += len(mybone.blenMeshes) tmp += len(my_bone.blenMeshes)
if tmp: if tmp:
file.write(''' file.write('''
@@ -1717,26 +1751,26 @@ Objects: {''')
# Write the null object # Write the null object
write_null(None, 'blend_root') write_null(None, 'blend_root')
for obname, ob in ob_null: for my_null in ob_null:
write_null(ob, obname) write_null(my_null)
for obname, ob, arm_my_bones, blenActions in ob_arms: for my_arm in ob_arms:
# Dont pass the object because that writes the armature transformation which is alredy applied to the bones. # 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. write_null(None, my_arm.fbxName) # armatures are just null's with bone children.
for obname, ob in ob_cameras: for my_cam in ob_cameras:
write_camera(ob, obname) write_camera(my_cam)
for obname, ob in ob_lights: for my_light in ob_lights:
write_light(ob, obname) write_light(my_light)
for obname, ob, mtx, me, mats, arm, armname in ob_meshes: for my_mesh in ob_meshes:
write_mesh(obname, ob, mtx, me, mats, arm, armname) #write_mesh(obname, ob, mtx, me, mats, arm, armname)
write_mesh(my_mesh)
#for bonename, bone, obname, me, armob in ob_bones: #for bonename, bone, obname, me, armob in ob_bones:
for mybone in ob_bones: for my_bone in ob_bones:
#write_bone(bone, bonename, armob.matrixWorld) write_bone(my_bone)
write_bone(mybone.blenBone, mybone.fbxName, mybone.blenArmature.matrixWorld)
write_camera_default() write_camera_default()
@@ -1751,22 +1785,22 @@ Objects: {''')
write_texture(texname, tex, i) write_texture(texname, tex, i)
i+=1 i+=1
# Get normalized weights for temorary use
# NOTE - c4d and motionbuilder dont need normalized weights, but deep-exploration 5 does and (max?) do. # NOTE - c4d and motionbuilder dont need normalized weights, but deep-exploration 5 does and (max?) do.
tmp_normalized_weights = dict([(me.name, meshNormalizedWeights(me)) for obname, ob, mtx, me, mats, arm, armname in ob_meshes])
# Write armature modifiers # Write armature modifiers
# TODO - add another MODEL? - because of this skin definition. # TODO - add another MODEL? - because of this skin definition.
for obname, ob, mtx, me, mats, arm, armname in ob_meshes: for my_mesh in ob_meshes:
if armname: if my_mesh.fbxArm:
write_deformer_skin(obname) write_deformer_skin(my_mesh.fbxName)
# Get normalized weights for temorary use
weights = meshNormalizedWeights(my_mesh.blenData)
#for bonename, bone, obname, bone_mesh, armob in ob_bones: #for bonename, bone, obname, bone_mesh, armob in ob_bones:
for mybone in ob_bones: for my_bone in ob_bones:
if me in mybone.blenMeshes.itervalues(): if me in my_bone.blenMeshes.itervalues():
#write_sub_deformer_skin(obname, bonename, bone, me, armob.matrixWorld) #write_sub_deformer_skin(my_mesh.fbxName, my_bone.fbxName, my_bone.blenBone, meshNormalizedWeights, my_bone.fbxArm.matrixWorld)
#write_sub_deformer_skin(obname, mybone.fbxName, mybone.blenBone, me, mybone.blenArmature.matrixWorld) write_sub_deformer_skin(my_mesh, my_bone, weights)
write_sub_deformer_skin(obname, mybone.fbxName, mybone.blenBone, tmp_normalized_weights[me.name], mybone.blenArmature.matrixWorld)
# Write pose's really weired, only needed when an armature and mesh are used together # Write pose's really weired, only needed when an armature and mesh are used together
# each by themselves dont need pose data. for now only pose meshes and bones # each by themselves dont need pose data. for now only pose meshes and bones
@@ -1795,7 +1829,6 @@ Objects: {''')
""" """
# Finish Writing Objects # Finish Writing Objects
# Write global settings # Write global settings
file.write(''' file.write('''
@@ -1823,25 +1856,25 @@ Relations: {''')
file.write('\n\tModel: "Model::blend_root", "Null" {\n\t}') file.write('\n\tModel: "Model::blend_root", "Null" {\n\t}')
for obname, ob in ob_null: for my_null in ob_null:
file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % obname) file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % my_null.fbxName)
for obname, ob, arm_my_bones, blenActions in ob_arms: for my_arm in ob_arms:
file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % obname) file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % my_arm.fbxName)
for obname, ob, mtx, me, mats, arm, armname in ob_meshes: for my_mesh in ob_meshes:
file.write('\n\tModel: "Model::%s", "Mesh" {\n\t}' % obname) file.write('\n\tModel: "Model::%s", "Mesh" {\n\t}' % my_mesh.fbxName)
# TODO - limbs can have the same name for multiple armatures, should prefix. # TODO - limbs can have the same name for multiple armatures, should prefix.
#for bonename, bone, obname, me, armob in ob_bones: #for bonename, bone, obname, me, armob in ob_bones:
for mybone in ob_bones: for my_bone in ob_bones:
file.write('\n\tModel: "Model::%s", "Limb" {\n\t}' % mybone.fbxName) file.write('\n\tModel: "Model::%s", "Limb" {\n\t}' % my_bone.fbxName)
for obname, ob in ob_cameras: for my_cam in ob_cameras:
file.write('\n\tModel: "Model::%s", "Camera" {\n\t}' % obname) file.write('\n\tModel: "Model::%s", "Camera" {\n\t}' % my_cam.fbxName)
for obname, ob in ob_lights: for my_light in ob_lights:
file.write('\n\tModel: "Model::%s", "Light" {\n\t}' % obname) file.write('\n\tModel: "Model::%s", "Light" {\n\t}' % my_light.fbxName)
file.write(''' file.write('''
Model: "Model::Producer Perspective", "Camera" { Model: "Model::Producer Perspective", "Camera" {
@@ -1871,16 +1904,15 @@ Relations: {''')
file.write('\n\tVideo: "Video::%s", "Clip" {\n\t}' % texname) file.write('\n\tVideo: "Video::%s", "Clip" {\n\t}' % texname)
# deformers - modifiers # deformers - modifiers
for obname, ob, mtx, me, mats, arm, armname in ob_meshes: for my_mesh in ob_meshes:
if arm: if my_mesh.fbxArm:
file.write('\n\tDeformer: "Deformer::Skin %s", "Skin" {\n\t}' % obname) file.write('\n\tDeformer: "Deformer::Skin %s", "Skin" {\n\t}' % my_mesh.fbxName)
#for bonename, bone, obname, me, armob in ob_bones: #for bonename, bone, obname, me, armob in ob_bones:
for mybone in ob_bones: for my_bone in ob_bones:
for fbxMeshObName in mybone.blenMeshes: # .keys() - fbxMeshObName for fbxMeshObName in my_bone.blenMeshes: # .keys() - fbxMeshObName
# is this bone effecting a mesh? # is this bone effecting a mesh?
file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {\n\t}' % (fbxMeshObName, mybone.fbxName)) file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {\n\t}' % (fbxMeshObName, my_bone.fbxName))
# This should be at the end # This should be at the end
# file.write('\n\tPose: "Pose::BIND_POSES", "BindPose" {\n\t}') # file.write('\n\tPose: "Pose::BIND_POSES", "BindPose" {\n\t}')
@@ -1901,66 +1933,61 @@ Connections: {''')
# write the fake root node # write the fake root node
file.write('\n\tConnect: "OO", "Model::blend_root", "Model::Scene"') file.write('\n\tConnect: "OO", "Model::blend_root", "Model::Scene"')
for obname, ob in ob_null: for my_null in ob_null:
if ob.parent: #if ob.parent:
file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (obname, sane_obname(ob.parent))) # file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (obname, sane_name_mapping_ob[ob.parent.name]))
else: #else:
file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % obname) file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_null.fbxName)
for obname, ob, mtx, me, mats, arm, armname in ob_meshes: for my_mesh in ob_meshes:
file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % obname) file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_mesh.fbxName)
for obname, ob, arm_my_bones, blenActions in ob_arms: for my_arm in ob_arms:
file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % obname) file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_arm.fbxName)
for obname, ob in ob_cameras: for my_cam in ob_cameras:
file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % obname) file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_cam.fbxName)
for obname, ob in ob_cameras: for my_light in ob_lights:
file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % obname) file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_light.fbxName)
for obname, ob in ob_lights: for my_mesh in ob_meshes:
file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % obname)
for obname, ob, mtx, me, mats, arm, armname in ob_meshes:
# Connect all materials to all objects, not good form but ok for now. # Connect all materials to all objects, not good form but ok for now.
for mat in mats: for mat in my_mesh.blenMaterials:
file.write('\n\tConnect: "OO", "Material::%s", "Model::%s"' % (sane_obname(mat), obname)) file.write('\n\tConnect: "OO", "Material::%s", "Model::%s"' % (sane_name_mapping_mat[mat.name], my_mesh))
if textures: if textures:
for obname, ob, mtx, me, mats, arm, armname in ob_meshes: for my_mesh in ob_meshes:
for texname, tex in textures: for texname, tex in textures:
file.write('\n\tConnect: "OO", "Texture::%s", "Model::%s"' % (texname, obname)) file.write('\n\tConnect: "OO", "Texture::%s", "Model::%s"' % (texname, my_mesh.fbxName))
for texname, tex in textures: for texname, tex in textures:
file.write('\n\tConnect: "OO", "Video::%s", "Texture::%s"' % (texname, texname)) file.write('\n\tConnect: "OO", "Video::%s", "Texture::%s"' % (texname, texname))
for my_mesh in ob_meshes:
for obname, ob, mtx, me, mats, arm, armname in ob_meshes: if my_mesh.fbxArm:
if arm: file.write('\n\tConnect: "OO", "Deformer::Skin %s", "Model::%s"' % (my_mesh.fbxName, my_mesh.fbxName))
file.write('\n\tConnect: "OO", "Deformer::Skin %s", "Model::%s"' % (obname, obname))
#for bonename, bone, obname, me, armob in ob_bones: #for bonename, bone, obname, me, armob in ob_bones:
for mybone in ob_bones: for my_bone in ob_bones:
for fbxMeshObName in mybone.blenMeshes: # .keys() for fbxMeshObName in my_bone.blenMeshes: # .keys()
file.write('\n\tConnect: "OO", "SubDeformer::Cluster %s %s", "Deformer::Skin %s"' % (fbxMeshObName, mybone.fbxName, fbxMeshObName)) file.write('\n\tConnect: "OO", "SubDeformer::Cluster %s %s", "Deformer::Skin %s"' % (fbxMeshObName, my_bone.fbxName, fbxMeshObName))
# limbs -> deformers # limbs -> deformers
# for bonename, bone, obname, me, armob in ob_bones: # for bonename, bone, obname, me, armob in ob_bones:
for mybone in ob_bones: for my_bone in ob_bones:
for fbxMeshObName in mybone.blenMeshes: # .keys() for fbxMeshObName in my_bone.blenMeshes: # .keys()
file.write('\n\tConnect: "OO", "Model::%s", "SubDeformer::Cluster %s %s"' % (mybone.fbxName, fbxMeshObName, mybone.fbxName)) file.write('\n\tConnect: "OO", "Model::%s", "SubDeformer::Cluster %s %s"' % (my_bone.fbxName, fbxMeshObName, my_bone.fbxName))
#for bonename, bone, obname, me, armob in ob_bones: #for bonename, bone, obname, me, armob in ob_bones:
for mybone in ob_bones: for my_bone in ob_bones:
# Always parent to armature now # Always parent to armature now
if mybone.parent: if my_bone.parent:
file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (mybone.fbxName, mybone.parent.fbxName) ) file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_bone.fbxName, my_bone.parent.fbxName) )
else: else:
# the armature object is written as an empty and all root level bones connect to it # the armature object is written as an empty and all root level bones connect to it
file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (mybone.fbxName, mybone.fbxArmObName) ) file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_bone.fbxName, my_bone.fbxArm.fbxName) )
file.write('\n}') file.write('\n}')
@@ -1988,7 +2015,7 @@ Connections: {''')
# default action, when no actions are avaioable # default action, when no actions are avaioable
tmp_actions = [None] # None is the default action tmp_actions = [None] # None is the default action
action_default = None blenActionDefault = None
action_lastcompat = None action_lastcompat = None
if ANIM_ACTION_ALL: if ANIM_ACTION_ALL:
@@ -1999,20 +2026,20 @@ Connections: {''')
# find which actions are compatible with the armatures # find which actions are compatible with the armatures
# blenActions is not yet initialized so do it now. # blenActions is not yet initialized so do it now.
tmp_act_count = 0 tmp_act_count = 0
for obname, ob, arm_my_bones, blenActions in ob_arms: for my_arm in ob_arms:
# get the default name # get the default name
if not action_default: if not blenActionDefault:
action_default = ob.action blenActionDefault = my_arm.blenAction
arm_bone_names = set([mybone.blenName for mybone in arm_my_bones]) arm_bone_names = set([my_bone.blenName for my_bone in my_arm.fbxBones])
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.
blenActions[1].append(action) my_arm.blenActionList.append(action)
action.tag = True action.tag = True
tmp_act_count += 1 tmp_act_count += 1
@@ -2021,8 +2048,8 @@ Connections: {''')
if tmp_act_count: if tmp_act_count:
# unlikely to ever happen but if no actions applied to armatures, just use the last compatible armature. # unlikely to ever happen but if no actions applied to armatures, just use the last compatible armature.
if not action_default: if not blenActionDefault:
action_default = action_lastcompat blenActionDefault = action_lastcompat
del action_lastcompat del action_lastcompat
@@ -2032,8 +2059,8 @@ Connections: {''')
Takes: {''') Takes: {''')
if action_default: if blenActionDefault:
file.write('\n\tCurrent: "%s"' % sane_takename(action_default)) file.write('\n\tCurrent: "%s"' % sane_takename(blenActionDefault))
else: else:
file.write('\n\tCurrent: "Default Take"') file.write('\n\tCurrent: "Default Take"')
@@ -2051,16 +2078,21 @@ Takes: {''')
file.write('\n\tTake: "Default Take" {') file.write('\n\tTake: "Default Take" {')
act_start = start act_start = start
act_end = end act_end = end
else:
# use existing name
if blenAction == blenActionDefault: # have we alredy got the name
file.write('\n\tTake: "%s" {' % sane_name_mapping_take[blenAction.name])
else: else:
file.write('\n\tTake: "%s" {' % sane_takename(blenAction)) file.write('\n\tTake: "%s" {' % sane_takename(blenAction))
tmp = blenAction.getFrameNumbers() tmp = blenAction.getFrameNumbers()
act_start = min(tmp) act_start = min(tmp)
act_end = max(tmp) act_end = max(tmp)
del tmp del tmp
# Set the action active # Set the action active
for obname, ob, arm_my_bones, blenActions in ob_arms: for my_bone in ob_arms:
if blenAction in blenActions[1]: if blenAction in my_bone.blenActionList:
ob.action = blenAction ob.action = blenAction
# print '\t\tSetting Action!', blenAction # print '\t\tSetting Action!', blenAction
# sce.update(1) # sce.update(1)
@@ -2078,26 +2110,26 @@ Takes: {''')
# set pose data for all bones # set pose data for all bones
# do this here incase the action changes # do this here incase the action changes
''' '''
for mybone in ob_bones: for my_bone in ob_bones:
mybone.flushAnimData() my_bone.flushAnimData()
''' '''
i = act_start i = act_start
while i <= act_end: while i <= act_end:
Blender.Set('curframe', i) Blender.Set('curframe', i)
#Blender.Window.RedrawAll() #Blender.Window.RedrawAll()
for mybone in ob_bones: for my_bone in ob_bones:
mybone.setPoseFrame(i) my_bone.setPoseFrame(i)
i+=1 i+=1
#for bonename, bone, obname, me, armob in ob_bones: #for bonename, bone, obname, me, armob in ob_bones:
for mybone in ob_bones: for my_bone in ob_bones:
file.write('\n\t\tModel: "Model::%s" {' % mybone.fbxName) # ??? - not sure why this is needed file.write('\n\t\tModel: "Model::%s" {' % my_bone.fbxName) # ??? - not sure why this is needed
file.write('\n\t\t\tVersion: 1.1') file.write('\n\t\t\tVersion: 1.1')
file.write('\n\t\t\tChannel: "Transform" {') file.write('\n\t\t\tChannel: "Transform" {')
context_bone_anim_mats = [ mybone.getAnimMatrix(frame) for frame in xrange(act_start, act_end+1) ] context_bone_anim_mats = [ my_bone.getAnimMatrix(frame) for frame in xrange(act_start, act_end+1) ]
# ---------------- # ----------------
for TX_LAYER, TX_CHAN in enumerate('TRS'): # transform, rotate, scale for TX_LAYER, TX_CHAN in enumerate('TRS'): # transform, rotate, scale
@@ -2172,8 +2204,8 @@ Takes: {''')
# end action loop. set original actions # end action loop. set original actions
# do this after every loop incase actions effect eachother. # do this after every loop incase actions effect eachother.
for obname, ob, arm_my_bones, blenActions in ob_arms: for my_bone in ob_arms:
ob.action = blenActions[0] my_bone.blenObject.action = my_bone.blenAction
file.write('\n}') file.write('\n}')
@@ -2247,6 +2279,9 @@ Takes: {''')
if EXP_IMAGE_COPY: if EXP_IMAGE_COPY:
copy_images( Blender.sys.dirname(filename), [ tex[1] for tex in textures if tex[1] != None ]) copy_images( Blender.sys.dirname(filename), [ tex[1] for tex in textures if tex[1] != None ])
print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time) print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time)