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)) # select it blender_funcs.select_obj(armature, False, "OBJECT") # check if the armature contains only mesh objects inside for child in armature.children: if (child.type != "MESH"): blender_funcs.disp_msg("\"%s\": contains non-mesh object (%s)." % (armature.name, child.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(mesh, False, "OBJECT") 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 and that the bind is to the actual parent armature 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 if (mesh.modifiers["Armature"].object != armature): blender_funcs.disp_msg("\"%s\": armature modifier was binded to another armature object" % (mesh.name)) mesh.modifiers["Armature"].object = armature; # 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) blender_funcs.select_obj(armature, True, "OBJECT") 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(armature, False, "OBJECT") # 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(armature.children[i], False, "OBJECT") bpy.ops.object.transform_apply(location = True, rotation = True, scale = True) blender_funcs.select_obj(armature, False, "OBJECT") # 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] # 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(armature, True, "OBJECT") 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(armature, False, "OBJECT") 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 the armature", 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)") # register func @bpy.app.handlers.persistent def register(dummy): try: bpy.utils.register_class(export_superbmd_collada) bpy.types.INFO_MT_file_export.append(menu_export_superbmd_collada) except: return # unregister func def unregister(): try: bpy.utils.unregister_class(export_superbmd_collada) bpy.types.INFO_MT_file_export.remove(menu_export_superbmd_collada) except: return