diff options
author | Campbell Barton <ideasman42@gmail.com> | 2007-08-29 18:20:56 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2007-08-29 18:20:56 +0400 |
commit | e3861b1d469620f06a1c77b99c74801b95ebac8d (patch) | |
tree | 20ed81762ed63fc20c07ea4429703018dfe71522 | |
parent | 96f9ecbe6566f5b1f28f897b0ca9fe1ddfa7ebbf (diff) |
sync with trunk
-rw-r--r-- | release/scripts/export_fbx.py | 597 |
1 files changed, 358 insertions, 239 deletions
diff --git a/release/scripts/export_fbx.py b/release/scripts/export_fbx.py index 7e472c409c2..8282451b24d 100644 --- a/release/scripts/export_fbx.py +++ b/release/scripts/export_fbx.py @@ -72,6 +72,18 @@ import BPyMessages import sys +## This was used to make V, but faster not to do all that +##valid = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_,.()[]{}' +##v = range(255) +##for c in valid: v.remove(ord(c)) +v = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,42,43,47,58,59,60,61,62,63,64,92,94,96,124,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254] +invalid = ''.join([chr(i) for i in v]) +def cleanName(name): + for ch in invalid: name = name.replace(ch, '_') + return name +del v, i + + def copy_file(source, dest): file = open(source, 'rb') data = file.read() @@ -106,6 +118,8 @@ def copy_images(dest_dir, textures): print '\tCopied %d images' % copyCount +mtx4_identity = Matrix() + mtx_z90 = RotationMatrix(90, 3, 'z') mtx_x90 = RotationMatrix(90, 3, 'x') @@ -171,7 +185,8 @@ def sane_name(data, dct): if not name: name = 'unnamed' # blank string, ASKING FOR TROUBLE! else: - name = BPySys.cleanName(name) + #name = BPySys.cleanName(name) + name = cleanName(name) # use our own while name in dct.itervalues(): name = increment_string(name) @@ -284,6 +299,7 @@ def write(filename, batch_objects = None, \ for data in data_seq: # scene or group newname = BATCH_FILE_PREFIX + BPySys.cleanName(data.name) + if BATCH_OWN_DIR: new_fbxpath = fbxpath + newname + Blender.sys.sep # path may alredy exist @@ -345,9 +361,6 @@ def write(filename, batch_objects = None, \ # end batch support - - - # ---------------------------------------------- # storage classes class my_bone_class: @@ -428,6 +441,10 @@ def write(filename, batch_objects = None, \ else: return (mtx4_z90 * ((self.getPoseMatrix(frame) * arm_mat))) * (mtx4_z90 * (self.parent.getPoseMatrix(frame) * arm_mat)).invert() + # we need thes because cameras and lights modified rotations + def getAnimMatrixRot(self, frame): + return self.getAnimMatrix(frame) + def flushAnimData(self): self.__anim_poselist.clear() @@ -438,15 +455,33 @@ def write(filename, batch_objects = None, \ self.fbxName = sane_obname(ob) self.blenObject = ob self.matrixWorld = ob.matrixWorld * GLOBAL_MATRIX + self.__anim_poselist = {} + + def setPoseFrame(self, f): + self.__anim_poselist[f] = self.blenObject.matrixWorld.copy() + + def getAnimMatrix(self, frame): + return self.__anim_poselist[frame] * GLOBAL_MATRIX + + def getAnimMatrixRot(self, frame): + type = self.blenObject.type + matrix_rot = (self.__anim_poselist[frame] * GLOBAL_MATRIX).rotationPart() + + # Lamps need to be rotated + if type =='Lamp': + matrix_rot = mtx_x90 * matrix_rot + elif ob and type =='Camera': + y = Vector(0,1,0) * matrix_rot + matrix_rot = matrix_rot * RotationMatrix(90, 3, 'r', y) + + return matrix_rot + # ---------------------------------------------- - - - print '\nFBX export starting...', filename start_time = Blender.sys.time() file = open(filename, 'w') @@ -484,6 +519,8 @@ def write(filename, batch_objects = None, \ file.write('\nCreationTime: "%.4i-%.2i-%.2i %.2i:%.2i:%.2i:000"' % curtime) file.write('\nCreator: "Blender3D version %.2f"' % Blender.Get('version')) + pose_items = [] # list of (fbxName, matrix) to write pose data for, easier to collect allong the way + # --------------- funcs for exporting def object_tx(ob, loc, matrix, matrix_mod = None): ''' @@ -518,7 +555,7 @@ def write(filename, batch_objects = None, \ matrix_rot = matrix.rotationPart() # Lamps need to be rotated if ob and ob.type =='Lamp': - matrix_rot = mtx_x90 * matrix.rotationPart() + matrix_rot = mtx_x90 * matrix_rot rot = tuple(matrix_rot.toEuler()) elif ob and ob.type =='Camera': y = Vector(0,1,0) * matrix_rot @@ -645,7 +682,9 @@ def write(filename, batch_objects = None, \ file.write('\n\tModel: "Model::%s", "Limb" {' % my_bone.fbxName) file.write('\n\t\tVersion: 232') - write_object_props(my_bone.blenBone, None, None, my_bone.fbxArm.matrixWorld) + poseMatrix = write_object_props(my_bone.blenBone, None, None, my_bone.fbxArm.matrixWorld)[3] + pose_items.append( (my_bone.fbxName, poseMatrix) ) + # 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') @@ -941,11 +980,11 @@ def write(filename, batch_objects = None, \ file.write('\n\t\t\tProperty: "DrawFrontFacingVolumetricLight", "bool", "",0') file.write('\n\t\t\tProperty: "GoboProperty", "object", ""') file.write('\n\t\t\tProperty: "Color", "Color", "A+",1,1,1') - file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (light.energy*100)) + file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200 file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % light.spotSize) file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50') file.write('\n\t\t\tProperty: "Color", "Color", "A",%.2f,%.2f,%.2f' % tuple(light.col)) - file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (light.energy*100)) + file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200 file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % light.spotSize) file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50') file.write('\n\t\t\tProperty: "LightType", "enum", "",%i' % light_type) @@ -973,15 +1012,24 @@ def write(filename, batch_objects = None, \ file.write('\n\t\tGeometryVersion: 124') file.write('\n\t}') - def write_null(my_null, fbxName = None): + # matrixOnly is not used at the moment + def write_null(my_null = None, fbxName = None, matrixOnly = None): # ob can be null if not fbxName: fbxName = my_null.fbxName file.write('\n\tModel: "Model::%s", "Null" {' % fbxName) file.write('\n\t\tVersion: 232') - if my_null: write_object_props(my_null.blenObject) - else: write_object_props() - + + # only use this for the root matrix at the moment + if matrixOnly: + poseMatrix = write_object_props(None, None, matrixOnly)[3] + + else: # all other Null's + if my_null: poseMatrix = write_object_props(my_null.blenObject)[3] + else: poseMatrix = write_object_props()[3] + + pose_items.append((fbxName, poseMatrix)) + file.write(''' } MultiLayer: 0 @@ -1010,6 +1058,7 @@ def write(filename, batch_objects = None, \ mat_hard = (float(mat.hard)-1)/5.10 mat_spec = mat.spec/2.0 mat_alpha = mat.alpha + mat_emit = mat.emit mat_shadeless = mat.mode & Blender.Material.Modes.SHADELESS if mat_shadeless: mat_shader = 'Lambert' @@ -1027,6 +1076,7 @@ def write(filename, batch_objects = None, \ mat_hard = 20.0 mat_spec = 0.2 mat_alpha = 1.0 + mat_emit = 0.0 mat_shadeless = False mat_shader = 'Phong' @@ -1037,19 +1087,19 @@ def write(filename, batch_objects = None, \ file.write('\n\t\tProperties60: {') file.write('\n\t\t\tProperty: "ShadingModel", "KString", "", "%s"' % mat_shader) file.write('\n\t\t\tProperty: "MultiLayer", "bool", "",0') - file.write('\n\t\t\tProperty: "EmissiveColor", "ColorRGB", "",0,0,0') - file.write('\n\t\t\tProperty: "EmissiveFactor", "double", "",1') + file.write('\n\t\t\tProperty: "EmissiveColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cold) # emit and diffuse color are he same in blender + file.write('\n\t\t\tProperty: "EmissiveFactor", "double", "",%.4f' % mat_dif) - file.write('\n\t\t\tProperty: "AmbientColor", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_colamb) - file.write('\n\t\t\tProperty: "AmbientFactor", "double", "",%.1f' % mat_amb) - file.write('\n\t\t\tProperty: "DiffuseColor", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_cold) - file.write('\n\t\t\tProperty: "DiffuseFactor", "double", "",%.1f' % mat_dif) + file.write('\n\t\t\tProperty: "AmbientColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_colamb) + file.write('\n\t\t\tProperty: "AmbientFactor", "double", "",%.4f' % mat_amb) + file.write('\n\t\t\tProperty: "DiffuseColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cold) + file.write('\n\t\t\tProperty: "DiffuseFactor", "double", "",%.4f' % mat_emit) file.write('\n\t\t\tProperty: "Bump", "Vector3D", "",0,0,0') file.write('\n\t\t\tProperty: "TransparentColor", "ColorRGB", "",1,1,1') - file.write('\n\t\t\tProperty: "TransparencyFactor", "double", "",0') + file.write('\n\t\t\tProperty: "TransparencyFactor", "double", "",%.4f' % (1.0 - mat_alpha)) if not mat_shadeless: - file.write('\n\t\t\tProperty: "SpecularColor", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_cols) - file.write('\n\t\t\tProperty: "SpecularFactor", "double", "",%.1f' % mat_spec) + file.write('\n\t\t\tProperty: "SpecularColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cols) + file.write('\n\t\t\tProperty: "SpecularFactor", "double", "",%.4f' % mat_spec) file.write('\n\t\t\tProperty: "ShininessExponent", "double", "",80.0') file.write('\n\t\t\tProperty: "ReflectionColor", "ColorRGB", "",0,0,0') file.write('\n\t\t\tProperty: "ReflectionFactor", "double", "",1') @@ -1249,16 +1299,41 @@ def write(filename, batch_objects = None, \ file.write('\n\t\tTransformLink: %s' % matstr) file.write('\n\t}') - #def write_mesh(obname, ob, mtx, me, mats, arm, armname): def write_mesh(my_mesh): + + me = my_mesh.blenData + + # if there are non NULL materials on this mesh + if [mat for mat in my_mesh.blenMaterials if mat]: do_materials = True + else: do_materials = False + + if my_mesh.blenTextures: do_textures = True + else: do_textures = False + + file.write('\n\tModel: "Model::%s", "Mesh" {' % my_mesh.fbxName) 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 - # 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(my_mesh.blenObject, None, Matrix()) + if my_mesh.fbxArm: + if my_mesh.origData: + do_tx_write = True + else: + do_tx_write = False + me.transform(my_mesh.matrixWorld) + + else: + do_tx_write = False + + + # When we have an armature... + if my_mesh.fbxArm: + # 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(my_mesh.blenObject, None, mtx4_identity) + else: + write_object_props(my_mesh.blenObject, None, my_mesh.matrixWorld) file.write('\n\t\t}') file.write('\n\t\tMultiLayer: 0') @@ -1266,21 +1341,30 @@ def write(filename, batch_objects = None, \ file.write('\n\t\tShading: Y') file.write('\n\t\tCulling: "CullingOff"') - me = my_mesh.blenData # Write the Real Mesh data here file.write('\n\t\tVertices: ') i=-1 - for v in me.verts: - if i==-1: - file.write('%.6f,%.6f,%.6f' % tuple(v.co * my_mesh.matrixWorld)) - i=0 - else: - if i==7: - file.write('\n\t\t') - i=0 - file.write(',%.6f,%.6f,%.6f'% tuple(v.co * my_mesh.matrixWorld)) - i+=1 + + if do_tx_write :# transform verts on write? + for v in me.verts: + if i==-1: + file.write('%.6f,%.6f,%.6f' % tuple(v.co * my_mesh.matrixWorld)); i=0 + else: + if i==7: + file.write('\n\t\t'); i=0 + file.write(',%.6f,%.6f,%.6f'% tuple(v.co * my_mesh.matrixWorld)) + i+=1 + else: # same as above but has alredy been transformed + for v in me.verts: + if i==-1: + file.write('%.6f,%.6f,%.6f' % tuple(v.co)); i=0 + else: + if i==7: + file.write('\n\t\t'); i=0 + file.write(',%.6f,%.6f,%.6f'% tuple(v.co)) + i+=1 + file.write('\n\t\tPolygonVertexIndex: ') i=-1 for f in me.faces: @@ -1328,21 +1412,32 @@ def write(filename, batch_objects = None, \ ReferenceInformationType: "Direct" Normals: ''') - # wont handle non uniform scaling properly - mtx_rot = my_mesh.matrixWorld.rotationPart() - i=-1 - for v in me.verts: - if i==-1: - file.write('%.15f,%.15f,%.15f' % tuple(v.no * mtx_rot)) - i=0 - else: - if i==2: - file.write('\n ') - i=0 - file.write(',%.15f,%.15f,%.15f' % tuple(v.no * mtx_rot)) - i+=1 - file.write('\n\t\t}') + if do_tx_write: # transform normals on write? + mtx_rot = my_mesh.matrixWorld.rotationPart() + for v in me.verts: + if i==-1: + file.write('%.15f,%.15f,%.15f' % tuple(v.no * mtx_rot)); i=0 + else: + if i==2: + file.write('\n '); i=0 + file.write(',%.15f,%.15f,%.15f' % tuple(v.no * mtx_rot)) + i+=1 + file.write('\n\t\t}') + + + else: # same as above but has alredy been transformed + # wont handle non uniform scaling properly + for v in me.verts: + if i==-1: + file.write('%.15f,%.15f,%.15f' % tuple(v.no)); i=0 + else: + if i==2: + file.write('\n '); i=0 + file.write(',%.15f,%.15f,%.15f' % tuple(v.no)) + i+=1 + file.write('\n\t\t}') + # Write VertexColor Layers @@ -1441,32 +1536,47 @@ def write(filename, batch_objects = None, \ file.write('\n\t\t}') - if textures: + if do_textures: file.write('\n\t\tLayerElementTexture: %i {' % uvindex) file.write('\n\t\t\tVersion: 101') file.write('\n\t\t\tName: "%s"' % uvlayer) - file.write(''' - MappingInformationType: "ByPolygon" - ReferenceInformationType: "IndexToDirect" - BlendMode: "Translucent" - TextureAlpha: 1 - TextureId: ''') - i=-1 - for f in me.faces: - img_key = f.image - if img_key: img_key = img_key.name + if len(my_mesh.blenTextures) == 1: + file.write('\n\t\t\tMappingInformationType: "AllSame"') + else: + file.write('\n\t\t\tMappingInformationType: "ByPolygon"') + + file.write('\n\t\t\tReferenceInformationType: "IndexToDirect"') + file.write('\n\t\t\tBlendMode: "Translucent"') + file.write('\n\t\t\tTextureAlpha: 1') + file.write('\n\t\t\tTextureId: ') + + if len(my_mesh.blenTextures) == 1: + file.write('0') + else: + #texture_mapping_local = {None:0} + texture_mapping_local = {None:-1} - if i==-1: - i=0 - file.write( '%s' % texture_mapping_local[img_key]) - else: - if i==55: - file.write('\n ') - i=0 + i = 0 # 1 for dummy + for tex in my_mesh.blenTextures: + texture_mapping_local[tex] = i + i+=1 + + i=-1 + for f in me.faces: + img_key = f.image - file.write(',%s' % texture_mapping_local[img_key]) - i+=1 + if i==-1: + i=0 + file.write( '%s' % texture_mapping_local[img_key]) + else: + if i==55: + file.write('\n ') + i=0 + + file.write(',%s' % texture_mapping_local[img_key]) + i+=1 + else: file.write(''' LayerElementTexture: 0 { @@ -1483,47 +1593,50 @@ def write(filename, batch_objects = None, \ # Done with UV/textures. - if materials: - file.write(''' - LayerElementMaterial: 0 { - Version: 101 - Name: "" - MappingInformationType: "ByPolygon" - ReferenceInformationType: "IndexToDirect" - Materials: ''') + if do_materials: + file.write('\n\t\tLayerElementMaterial: 0 {') + file.write('\n\t\t\tVersion: 101') + file.write('\n\t\t\tName: ""') - # Build a material mapping for this - material_mapping_local = [-1] * 16 # local-index : global index. - i= 0 - for j, mat in enumerate(my_mesh.blenMaterials): - if mat: - material_mapping_local[j] = i - i+=1 - # else leave as -1 - - if not material_mapping_local: - material_mapping_local[0] = 0 + if len(my_mesh.blenMaterials) == 1: + file.write('\n\t\t\tMappingInformationType: "AllSame"') + else: + file.write('\n\t\t\tMappingInformationType: "ByPolygon"') - len_material_mapping_local = len(material_mapping_local) + file.write('\n\t\t\tReferenceInformationType: "IndexToDirect"') + file.write('\n\t\t\tMaterials: ') - i=-1 - for f in me.faces: - f_mat = f.mat - if f_mat >= len_material_mapping_local: - f_mat = 0 + if len(my_mesh.blenMaterials) == 1: + file.write('0') + else: + # Build a material mapping for this + #material_mapping_local = [0] * 16 # local-index : global index. + material_mapping_local = [-1] * 16 # local-index : global index. + i= 0 # 1 + for j, mat in enumerate(my_mesh.blenMaterials): + if mat: + material_mapping_local[j] = i + i+=1 + # else leave as -1 - if i==-1: - i=0 - file.write( '%s' % (material_mapping_local[f_mat])) - #file.write( '%s' % -1) - else: - if i==55: - file.write('\n\t\t\t\t') - i=0 + len_material_mapping_local = len(material_mapping_local) + + i=-1 + for f in me.faces: + f_mat = f.mat + if f_mat >= len_material_mapping_local: + f_mat = 0 - file.write(',%s' % (material_mapping_local[f_mat])) - #file.write(',%s' % -1) - i+=1 + if i==-1: + i=0 + file.write( '%s' % (material_mapping_local[f_mat])) + else: + if i==55: + file.write('\n\t\t\t\t') + i=0 + + file.write(',%s' % (material_mapping_local[f_mat])) + i+=1 file.write('\n\t\t}') @@ -1535,7 +1648,7 @@ def write(filename, batch_objects = None, \ TypedIndex: 0 }''') - if materials: + if do_materials: file.write(''' LayerElement: { Type: "LayerElementMaterial" @@ -1543,7 +1656,7 @@ def write(filename, batch_objects = None, \ }''') # Always write this - if textures: + if do_textures: file.write(''' LayerElement: { Type: "LayerElementTexture" @@ -1580,7 +1693,7 @@ def write(filename, batch_objects = None, \ file.write('\n\t\t\t\tTypedIndex: %i' % i) file.write('\n\t\t\t}') - if textures: + if do_textures: file.write(''' LayerElement: { @@ -1668,6 +1781,7 @@ def write(filename, batch_objects = None, \ if EXP_EMPTY: ob_null.append(my_object_generic(ob)) elif EXP_MESH: + origData = True if tmp_ob_type != 'Mesh': me = bpy.data.meshes.new() try: me.getFromObject(ob) @@ -1675,6 +1789,7 @@ def write(filename, batch_objects = None, \ if me: meshes_to_clear.append( me ) mats = me.materials + origData = False else: # Mesh Type! if EXP_MESH_APPLY_MOD: @@ -1694,6 +1809,7 @@ def write(filename, batch_objects = None, \ # print ob, me, me.getVertGroupNames() meshes_to_clear.append( me ) + origData = False mats = me.materials else: me = ob.getData(mesh=1) @@ -1719,15 +1835,16 @@ def write(filename, batch_objects = None, \ for mat in mats: # 2.44 use mat.lib too for uniqueness - if mat: materials[mat.name] = mat + if mat: materials[mat] = mat + texture_mapping_local = {} if me.faceUV: uvlayer_orig = me.activeUVLayer for uvlayer in me.getUVLayerNames(): me.activeUVLayer = uvlayer for f in me.faces: img = f.image - if img: textures[img.name] = img + textures[img] = texture_mapping_local[img] = img me.activeUVLayer = uvlayer_orig @@ -1752,11 +1869,16 @@ def write(filename, batch_objects = None, \ else: blenParentBoneName = armob = None - #ob_meshes.append( (obname, ob, mtx, me, mats, armob, armname) ) - my_mesh = my_object_generic(ob) my_mesh.blenData = me + my_mesh.origData = origData my_mesh.blenMaterials = mats + my_mesh.blenTextures = texture_mapping_local.values() + + # if only 1 null texture then empty the list + if len(my_mesh.blenTextures) == 1 and my_mesh.blenTextures[0] == None: + my_mesh.blenTextures = [] + my_mesh.fbxArm = armob # replace with my_object_generic armature instance later my_mesh.fbxBoneParent = blenParentBoneName # replace with my_bone instance later @@ -1835,29 +1957,11 @@ def write(filename, batch_objects = None, \ del my_bone_blenParent - materials = [(sane_matname(mat), mat) for mat in materials.itervalues()] - textures = [(sane_texname(img), img) for img in textures.itervalues()] + materials = [(sane_matname(mat), mat) for mat in materials.itervalues() if mat] + textures = [(sane_texname(img), img) for img in textures.itervalues() if img] materials.sort() # sort by name textures.sort() - if not materials: - materials = [('null', None)] - - material_mapping = {} # blen name : index - if textures: - texture_mapping_local = {None:-1} # ditto - i = 0 - for texname, tex in textures: - texture_mapping_local[tex.name] = i - i+=1 - #textures.insert(0, ('_empty_', None)) - - i = 0 - for matname, mat in materials: - if mat: mat = mat.name - material_mapping[mat] = i - i+=1 - camera_count = 8 file.write(''' @@ -1931,12 +2035,12 @@ Definitions: { del tmp # we could avoid writing this possibly but for now just write it - """ + file.write(''' ObjectType: "Pose" { Count: 1 }''') - """ + file.write(''' ObjectType: "GlobalSettings" { @@ -1955,7 +2059,7 @@ Objects: {''') write_camera_switch() # Write the null object - write_null(None, 'blend_root') + write_null(None, 'blend_root')# , GLOBAL_MATRIX) for my_null in ob_null: write_null(my_null) @@ -1971,7 +2075,6 @@ Objects: {''') write_light(my_light) for my_mesh in ob_meshes: - #write_mesh(obname, ob, mtx, me, mats, arm, armname) write_mesh(my_mesh) #for bonename, bone, obname, me, armob in ob_bones: @@ -2012,7 +2115,7 @@ Objects: {''') # 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 - """ + file.write(''' Pose: "Pose::BIND_POSES", "BindPose" { Type: "BindPose" @@ -2020,21 +2123,17 @@ Objects: {''') Properties60: { } NbPoseNodes: ''') - - file.write(str(\ - len(ob_meshes)+\ - len(ob_bones) - )) + file.write(str(len(pose_items))) - for tmp in (ob_meshes, ob_bones): - for ob in tmp: - file.write('\n\t\tPoseNode: {') - file.write('\n\t\t\tNode: "Model::%s"' % ob[0] ) # the first item is the fbx-name - file.write('\n\t\t\tMatrix: %s' % mat4x4str(object_tx(ob[1], None, None)[3])) # second item is the object or bone - file.write('\n\t\t}') + + for fbxName, matrix in pose_items: + file.write('\n\t\tPoseNode: {') + file.write('\n\t\t\tNode: "Model::%s"' % fbxName ) + if matrix: file.write('\n\t\t\tMatrix: %s' % mat4x4str(matrix)) + else: file.write('\n\t\t\tMatrix: %s' % mat4x4str(mtx4_identity)) + file.write('\n\t\t}') file.write('\n\t}') - """ # Finish Writing Objects @@ -2102,7 +2201,7 @@ Relations: {''') Model: "Model::Camera Switcher", "CameraSwitcher" { }''') - for matname, mat in reversed(materials): + for matname, mat in materials: file.write('\n\tMaterial: "Material::%s", "" {\n\t}' % matname) if textures: @@ -2159,16 +2258,21 @@ Connections: {''') for my_light in ob_lights: file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_light.fbxName) - for my_mesh in ob_meshes: - # Connect all materials to all objects, not good form but ok for now. - for mat in my_mesh.blenMaterials: - if mat: - file.write('\n\tConnect: "OO", "Material::%s", "Model::%s"' % (sane_name_mapping_mat[mat.name], my_mesh.fbxName)) + if materials: + for my_mesh in ob_meshes: + # Connect all materials to all objects, not good form but ok for now. + for mat in my_mesh.blenMaterials: + if mat: + file.write('\n\tConnect: "OO", "Material::%s", "Model::%s"' % (sane_name_mapping_mat[mat.name], my_mesh.fbxName)) + if textures: for my_mesh in ob_meshes: - for texname, tex in textures: - file.write('\n\tConnect: "OO", "Texture::%s", "Model::%s"' % (texname, my_mesh.fbxName)) + if my_mesh.blenTextures: + # file.write('\n\tConnect: "OO", "Texture::_empty_", "Model::%s"' % my_mesh.fbxName) + for tex in my_mesh.blenTextures: + if tex: + file.write('\n\tConnect: "OO", "Texture::%s", "Model::%s"' % (sane_name_mapping_tex[tex.name], my_mesh.fbxName)) for texname, tex in textures: file.write('\n\tConnect: "OO", "Video::%s", "Texture::%s"' % (texname, texname)) @@ -2325,88 +2429,103 @@ Takes: {''') i = act_start while i <= act_end: Blender.Set('curframe', i) - #Blender.Window.RedrawAll() - for my_bone in ob_bones: - my_bone.setPoseFrame(i) + for ob_generic in (ob_bones, ob_meshes, ob_null, ob_cameras, ob_lights): + for my_ob in ob_generic: + #Blender.Window.RedrawAll() + if ob_generic == ob_meshes and my_ob.fbxArm: + # We cant animate armature meshes! + pass + else: + my_ob.setPoseFrame(i) + i+=1 #for bonename, bone, obname, me, armob in ob_bones: - for my_bone in ob_bones: - - 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\tChannel: "Transform" {') - - 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 ob_generic in (ob_bones, ob_meshes, ob_null, ob_cameras, ob_lights): - if TX_CHAN=='T': context_bone_anim_vecs = [mtx.translationPart() for mtx in context_bone_anim_mats] - elif TX_CHAN=='R': context_bone_anim_vecs = [mtx.toEuler() for mtx in context_bone_anim_mats] - else: context_bone_anim_vecs = [mtx.scalePart() for mtx in context_bone_anim_mats] + for my_ob in ob_generic: - file.write('\n\t\t\t\tChannel: "%s" {' % TX_CHAN) # translation - for i in xrange(3): - # Loop on each axis of the bone - file.write('\n\t\t\t\t\tChannel: "%s" {'% ('XYZ'[i])) # translation - file.write('\n\t\t\t\t\t\tDefault: %.15f' % context_bone_anim_vecs[0][i] ) - file.write('\n\t\t\t\t\t\tKeyVer: 4005') + if ob_generic == ob_meshes and my_ob.fbxArm: + # do nothing, + pass + else: + + file.write('\n\t\tModel: "Model::%s" {' % my_ob.fbxName) # ??? - not sure why this is needed + file.write('\n\t\t\tVersion: 1.1') + file.write('\n\t\t\tChannel: "Transform" {') - if not ANIM_OPTIMIZE: - # Just write all frames, simple but in-eficient - file.write('\n\t\t\t\t\t\tKeyCount: %i' % (1 + act_end - act_start)) - file.write('\n\t\t\t\t\t\tKey: ') - frame = act_start - while frame <= act_end: - if frame!=act_start: - file.write(',') - - # Curve types are - # C,n is for bezier? - linear is best for now so we can do simple keyframe removal - file.write('\n\t\t\t\t\t\t\t%i,%.15f,C,n' % (fbx_time(frame-1), context_bone_anim_vecs[frame-act_start][i] )) - #file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame-1), context_bone_anim_vecs[frame-act_start][i] )) - frame+=1 - else: - # remove unneeded keys, j is the frame, needed when some frames are removed. - context_bone_anim_keys = [ (vec[i], j) for j, vec in enumerate(context_bone_anim_vecs) ] + context_bone_anim_mats = [ (my_ob.getAnimMatrix(frame), my_ob.getAnimMatrixRot(frame)) for frame in xrange(act_start, act_end+1) ] + + # ---------------- + # ---------------- + for TX_LAYER, TX_CHAN in enumerate('TRS'): # transform, rotate, scale - # last frame to fisrt frame, missing 1 frame on either side. - # removeing in a backwards loop is faster - for j in xrange( (act_end-act_start)-1, 0, -1 ): - # Is this key reduenant? - if abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j-1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT and\ - abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j+1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT: - del context_bone_anim_keys[j] + if TX_CHAN=='T': context_bone_anim_vecs = [mtx[0].translationPart() for mtx in context_bone_anim_mats] + elif TX_CHAN=='R': context_bone_anim_vecs = [mtx[1].toEuler() for mtx in context_bone_anim_mats] + else: context_bone_anim_vecs = [mtx[0].scalePart() for mtx in context_bone_anim_mats] - if len(context_bone_anim_keys) == 2 and context_bone_anim_keys[0][0] == context_bone_anim_keys[1][0]: - # This axis has no moton, its okay to skip KeyCount and Keys in this case - pass - else: - # We only need to write these if there is at least one - file.write('\n\t\t\t\t\t\tKeyCount: %i' % len(context_bone_anim_keys)) - file.write('\n\t\t\t\t\t\tKey: ') - for val, frame in context_bone_anim_keys: - if frame!=act_start: - file.write(',') - # frame is alredy one less then blenders frame - file.write('\n\t\t\t\t\t\t\t%i,%.15f,C,n' % (fbx_time(frame), val )) - #file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame), val )) + file.write('\n\t\t\t\tChannel: "%s" {' % TX_CHAN) # translation + + for i in xrange(3): + # Loop on each axis of the bone + file.write('\n\t\t\t\t\tChannel: "%s" {'% ('XYZ'[i])) # translation + file.write('\n\t\t\t\t\t\tDefault: %.15f' % context_bone_anim_vecs[0][i] ) + file.write('\n\t\t\t\t\t\tKeyVer: 4005') + + if not ANIM_OPTIMIZE: + # Just write all frames, simple but in-eficient + file.write('\n\t\t\t\t\t\tKeyCount: %i' % (1 + act_end - act_start)) + file.write('\n\t\t\t\t\t\tKey: ') + frame = act_start + while frame <= act_end: + if frame!=act_start: + file.write(',') + + # Curve types are + # C,n is for bezier? - linear is best for now so we can do simple keyframe removal + file.write('\n\t\t\t\t\t\t\t%i,%.15f,C,n' % (fbx_time(frame-1), context_bone_anim_vecs[frame-act_start][i] )) + #file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame-1), context_bone_anim_vecs[frame-act_start][i] )) + frame+=1 + else: + # remove unneeded keys, j is the frame, needed when some frames are removed. + context_bone_anim_keys = [ (vec[i], j) for j, vec in enumerate(context_bone_anim_vecs) ] + + # last frame to fisrt frame, missing 1 frame on either side. + # removeing in a backwards loop is faster + for j in xrange( (act_end-act_start)-1, 0, -1 ): + # Is this key reduenant? + if abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j-1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT and\ + abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j+1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT: + del context_bone_anim_keys[j] + + if len(context_bone_anim_keys) == 2 and context_bone_anim_keys[0][0] == context_bone_anim_keys[1][0]: + # This axis has no moton, its okay to skip KeyCount and Keys in this case + pass + else: + # We only need to write these if there is at least one + file.write('\n\t\t\t\t\t\tKeyCount: %i' % len(context_bone_anim_keys)) + file.write('\n\t\t\t\t\t\tKey: ') + for val, frame in context_bone_anim_keys: + if frame!=act_start: + file.write(',') + # frame is alredy one less then blenders frame + file.write('\n\t\t\t\t\t\t\t%i,%.15f,C,n' % (fbx_time(frame), val )) + #file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame), val )) + + if i==0: file.write('\n\t\t\t\t\t\tColor: 1,0,0') + elif i==1: file.write('\n\t\t\t\t\t\tColor: 0,1,0') + elif i==2: file.write('\n\t\t\t\t\t\tColor: 0,0,1') + + file.write('\n\t\t\t\t\t}') + file.write('\n\t\t\t\t\tLayerType: %i' % (TX_LAYER+1) ) + file.write('\n\t\t\t\t}') - if i==0: file.write('\n\t\t\t\t\t\tColor: 1,0,0') - elif i==1: file.write('\n\t\t\t\t\t\tColor: 0,1,0') - elif i==2: file.write('\n\t\t\t\t\t\tColor: 0,0,1') + # --------------- - file.write('\n\t\t\t\t\t}') - file.write('\n\t\t\t\t\tLayerType: %i' % (TX_LAYER+1) ) - file.write('\n\t\t\t\t}') - - # --------------- - - file.write('\n\t\t\t}') - file.write('\n\t\t}') + file.write('\n\t\t\t}') + file.write('\n\t\t}') # end the take file.write('\n\t}') @@ -2587,7 +2706,7 @@ def fbx_ui_write(filename): Blender.Window.WaitCursor(1) # Make the matrix - GLOBAL_MATRIX = Matrix() + GLOBAL_MATRIX = mtx4_identity GLOBAL_MATRIX[0][0] = GLOBAL_MATRIX[1][1] = GLOBAL_MATRIX[2][2] = GLOBALS['_SCALE'].val if GLOBALS['_XROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_x90n if GLOBALS['_YROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_y90n @@ -2634,10 +2753,10 @@ def fbx_ui(): Draw.EndAlign() Draw.BeginAlign() - GLOBALS['_SCALE'] = Draw.Number('Scale:', EVENT_NONE, x+20, y+120, 140, 20, GLOBALS['_SCALE'].val, 0.01, 1000.0, 'Export empty objects') - GLOBALS['_XROT90'] = Draw.Toggle('Rot X90', EVENT_NONE, x+160, y+120, 60, 20, GLOBALS['_XROT90'].val, 'Export empty objects') - GLOBALS['_YROT90'] = Draw.Toggle('Rot Y90', EVENT_NONE, x+220, y+120, 60, 20, GLOBALS['_YROT90'].val, 'Export empty objects') - GLOBALS['_ZROT90'] = Draw.Toggle('Rot Z90', EVENT_NONE, x+280, y+120, 60, 20, GLOBALS['_ZROT90'].val, 'Export empty objects') + GLOBALS['_SCALE'] = Draw.Number('Scale:', EVENT_NONE, x+20, y+120, 140, 20, GLOBALS['_SCALE'].val, 0.01, 1000.0, 'Scale all data, (Note! some imports dont support scaled armatures)') + GLOBALS['_XROT90'] = Draw.Toggle('Rot X90', EVENT_NONE, x+160, y+120, 60, 20, GLOBALS['_XROT90'].val, 'Rotate all objects 90 degrese about the X axis') + GLOBALS['_YROT90'] = Draw.Toggle('Rot Y90', EVENT_NONE, x+220, y+120, 60, 20, GLOBALS['_YROT90'].val, 'Rotate all objects 90 degrese about the Y axis') + GLOBALS['_ZROT90'] = Draw.Toggle('Rot Z90', EVENT_NONE, x+280, y+120, 60, 20, GLOBALS['_ZROT90'].val, 'Rotate all objects 90 degrese about the Z axis') Draw.EndAlign() y -= 35 @@ -2757,7 +2876,7 @@ def write_ui(): # done setting globals # Used by the user interface - GLOBALS['_SCALE'] = Draw.Create(10.0) + GLOBALS['_SCALE'] = Draw.Create(1.0) GLOBALS['_XROT90'] = Draw.Create(True) GLOBALS['_YROT90'] = Draw.Create(False) GLOBALS['_ZROT90'] = Draw.Create(False) |