diff options
Diffstat (limited to 'collada_superbmd_export.py')
-rw-r--r-- | collada_superbmd_export.py | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/collada_superbmd_export.py b/collada_superbmd_export.py new file mode 100644 index 0000000..ba721d5 --- /dev/null +++ b/collada_superbmd_export.py @@ -0,0 +1,168 @@ +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 + armature.rotation_euler[0] = math.radians(-90) + armature.scale = 100 * armature.scale + bpy.ops.object.transforms_to_deltas(mode = 'ALL') + + # 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') |