123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- import bpy, math
- from . import blender_funcs
- # just a DAE exporter.
- # it was supposed to only rotate the meshes around the X axis by -90 degrees
- # but above that it now checks for armature and vertex group stuff
- # only exports the armature object selected
- # write_bmd_bdl_collada function
- # function to write custom collada file for
- # SuperBMD conversion
- def write_bmd_bdl_collada(context, filepath, triangulate):
-
- # this thing is always needed for stuff
- scene = bpy.context.scene
-
- # if nothing is selected end the exporter
- if (scene.objects.active == None or scene.objects.active.type != 'ARMATURE'):
- if (scene.objects.active == None):
- blender_funcs.disp_msg("No Armature selected. Select one and try again.")
- else:
- blender_funcs.disp_msg("No Armature selected. Currently selecting: \"%s\""
- % (scene.objects.active.name))
- return {'FINISHED'}
-
- # get armature object
- armature = scene.objects.active
- print("\nArmature found: \"%s\"" % (armature.name))
-
- # check if the armature contains only mesh objects inside
- for obj in armature.children:
- if (obj.type != 'MESH'):
- blender_funcs.disp_msg("\"%s\": contains non-mesh object (%s)."
- % (armature.name, obj.name))
- return {'FINISHED'}
-
- # check if all meshes have an armature modifier that is
- # assigned to the armature object and it is binded to
- # vertex groups if none of those are just create them,
- # I don't think it is bad to automate that
- for mesh in armature.children:
- if("Armature" not in mesh.modifiers):
- blender_funcs.disp_msg("\"%s\": has no armature modifier. Adding one..." % (mesh.name))
- blender_funcs.select_obj(scene, mesh, False)
- bpy.ops.object.modifier_add(type = 'ARMATURE')
- mesh.modifiers["Armature"].object = armature
- mesh.modifiers["Armature"].use_vertex_groups = True
- else: # ensure bind is to a vertex group
- if (mesh.modifiers["Armature"].use_vertex_groups == False):
- blender_funcs.disp_msg("\"%s\": armature modifier wasn't binded to vertex groups"
- % (mesh.name))
- mesh.modifiers["Armature"].use_vertex_groups = True
-
- # check if all the vertex groups in each mesh correspond to the name of a skeleton bone
- bone_name_list = []
- for bone in armature.data.bones:
- bone_name_list.append(bone.name)
- # vertex group check
- for mesh in armature.children:
- for v_group in mesh.vertex_groups:
- if (v_group.name not in bone_name_list):
- blender_funcs.disp_msg(("\"%s\": contains non-valid vert group \"%s\"."
- % (mesh.name, v_group.name)) + " Unable to continue.")
- return {'FINISHED'}
- # vertex weight check
- for mesh in armature.children:
- for vertex in mesh.data.vertices:
- if (len(vertex.groups) == 0):
- blender_funcs.disp_msg(("\"%s\": contains unweighted vertices."
- % (mesh.name)) + " Unable to continue.")
- return {'FINISHED'}
-
- # get the object names
- obj_name = armature.name
- child_names = []
- for child in armature.children:
- child_names.append(child.name)
-
- # change to object view and make a copy of the armature object (with its children)
- bpy.ops.object.mode_set(mode='OBJECT')
- blender_funcs.select_obj(scene, armature, True)
- bpy.ops.object.duplicate(linked = True)
- bpy.ops.object.make_single_user(type = 'SELECTED_OBJECTS', object = True, obdata = True)
- old_armature = armature
- armature = scene.objects.active
- blender_funcs.select_obj(scene, armature, False)
-
- # apply the transformations to the armature
- armature.rotation_euler[0] = math.radians(-90)
- armature.scale = 100 * armature.scale
- bpy.ops.object.transform_apply(location = True, rotation = True, scale = True)
-
- # apply the transformations to the meshes inside the armature
- for i in range(0, len(armature.children)):
- blender_funcs.select_obj(scene, armature.children[i], False)
- bpy.ops.object.transform_apply(location = True, rotation = True, scale = True)
- blender_funcs.select_obj(scene, armature, False)
-
- # handle the object names so that they match the original model names
- armature.name = obj_name
- armature.data.name = obj_name
- for i in range(0, len(armature.children)):
- armature.children[i].name = child_names[i]
- armature.children[i].data.name = child_names[i]
-
- # store the new bind_mat and rest_mat (the user might want to update them)
- for data_bone in armature.data.bones:
- # related pose bone
- pose_bone = armature.pose.bones[data_bone.name]
- # bind matrix
- bpy.data.armatures[armature.data.name].pose_position = 'REST'
- bpy.context.scene.update() # update scene
- blender_funcs.set_bone_bind_mat(data_bone, pose_bone.matrix)
- # rest matrix
- bpy.data.armatures[armature.data.name].pose_position = 'POSE'
- bpy.context.scene.update() # update scene
- mat = None
- if (pose_bone.parent != None):
- mat = pose_bone.parent.matrix.inverted() * pose_bone.matrix
- else:
- mat = pose_bone.matrix
- blender_funcs.set_bone_rest_mat(data_bone, mat)
-
- # export the object
- bpy.ops.wm.collada_export(filepath = filepath, use_blender_profile = False,
- selected = True, include_children = True,
- triangulate = triangulate)
-
- # delete the duplicate object
- blender_funcs.select_obj(scene, armature, True)
- bpy.ops.object.delete(use_global = False)
-
- # re-assign the original object names
- armature = old_armature
- armature.name = obj_name
- armature.data.name = obj_name
- for i in range(0, len(armature.children)):
- armature.children[i].name = child_names[i]
- armature.children[i].data.name = child_names[i]
-
- # done!
- blender_funcs.select_obj(scene, armature, False)
- blender_funcs.disp_msg("Armature \"%s\" exported!" % (armature.name))
- return {'FINISHED'}
- # Stuff down is for the menu appending
- # of the exporter to work plus some setting stuff
- # comes from a Blender importer template
- from bpy_extras.io_utils import ExportHelper
- from bpy.props import StringProperty, BoolProperty, EnumProperty
- from bpy.types import Operator
- class export_superbmd_collada(Operator, ExportHelper):
- """Export a Collada file for SuperBMD (SuperBMD only)"""
- bl_idname = "export_scene.superbmd_collada"
- bl_label = "Export SuperBMD Collada (.DAE)"
- filename_ext = ".dae"
- filter_glob = StringProperty(default = "*.dae", options = {'HIDDEN'}, maxlen = 255)
-
- triangulate = BoolProperty(name = "Triangulate meshes",
- description = "Triangulate meshes inside armatures",
- default = False)
- def execute(self, context):
- return write_bmd_bdl_collada(context, self.filepath, self.triangulate)
- # Only needed if you want to add into a dynamic menu
- def menu_export_superbmd_collada(self, context):
- self.layout.operator(export_superbmd_collada.bl_idname, text="SuperBMD Collada (.dae)")
- bpy.utils.register_class(export_superbmd_collada)
- bpy.types.INFO_MT_file_export.append(menu_export_superbmd_collada)
- # test call
- bpy.ops.export_scene.superbmd_collada('INVOKE_DEFAULT')
|