diff options
Diffstat (limited to 'collada_bmd_bdl_export.py')
-rw-r--r-- | collada_bmd_bdl_export.py | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/collada_bmd_bdl_export.py b/collada_bmd_bdl_export.py new file mode 100644 index 0000000..4907a73 --- /dev/null +++ b/collada_bmd_bdl_export.py @@ -0,0 +1,313 @@ +''' +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 what is selected +''' + +import bpy, math +from .my_functions import * + +#################################################### +# transform_apply_parent_child function +# transform_apply the parent and its child meshes +# selects the parent object at the end +# +# scene --> Blender scene in which the object exists +# parent_object --> object that has child objects +# to which the transform apply +# operator will be applied +# loc (bool) --> apply location +# rot (bool) --> apply rotation +# sca (bool) --> apply scaling +#################################################### +def transform_apply_parent_child(scene, parent_object, loc, rot, sca): +# + # parent object must be selected and active for the function to work + bpy.ops.object.transform_apply(location = loc, rotation = rot, scale = sca) + + # armature child mesh scaling + for child_mesh in parent_object.children: + + # empty selection and active object + bpy.ops.object.select_all(action = 'DESELECT') + scene.objects.active = None + # select and activate child mesh + child_mesh.select = True + scene.objects.active = child_mesh + # apply scale and rotation + bpy.ops.object.transform_apply(location = loc, rotation = rot, scale = sca) + + # select parent_object + bpy.ops.object.select_all(action='DESELECT') + scene.objects.active = None + parent_object.select = True + scene.objects.active = parent_object +# + + +################################################ +# write_bmd_bdl_collada function (MAIN FUNCTION) +# function to write custom collada file for +# SuperBMD conversion +################################################ +def write_bmd_bdl_collada(context, filepath, triangulate): +# + print("\nWriting Collada file for BMD/BDL conversion\n") + + # 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'): + error_string = "No Armature object selected. Select one and try again." + print("\n### ERROR ###\n" + error_string + "\n### ERROR ###\n") + show_message(error_string, "Error exporting collada file", 'ERROR') + return {'FINISHED'} + + # get armature object + armature = scene.objects.active + print("Armature found: %s" % armature.name) + print() + + # change to object view + bpy.ops.object.mode_set(mode='OBJECT') + + # deselect everything (to be sure nothing weird happens) + bpy.ops.object.select_all(action='DESELECT') + scene.objects.active = None + + # re-select the armature object only + armature.select = True + scene.objects.active = armature + + # start mesh stuff + print("\n### Mesh stuff ###") + + ################################## + # check the meshes on the armature + for object in armature.children: + # + if (object.type == "MESH"): + # + print() + print("Mesh: \"" + object.name + "\"") + print() + + #################################### + # select the mesh and make it active + object.select = True + scene.objects.active = object + + # reset scale, rotation and position of the mesh + bpy.ops.object.transform_apply(location = True, rotation = True, scale = True) + + ############################## + # check mesh armature modifier + has_arm_mod = False + for modifiers in object.modifiers: + if (modifiers.name == "Armature"): + has_arm_mod = True + + if (has_arm_mod): + print("Mesh \"" + object.name + "\" has an Armature Modifier") + if (object.modifiers["Armature"].object != armature): + print("But not assigned to the right Armature Object. Re-assigning...") + object.modifiers["Armature"].object = armature + else: + print("And it is assigned to the right Armature Object: \"" + armature.name + "\"") + else: + print("Mesh \"" + object.name + "\" does not have an Armature Modifier") + print("Creating Modifier...") + bpy.ops.object.modifier_add(type='ARMATURE') + print("Assigning Modifier object to: \"" + armature.name + "\"") + object.modifiers["Armature"].object = armature + + # check if the mesh contains vertex groups + # if not, assign one that links to the main armature bone + # and weight all vertex in the mesh to it, otherwise leave + # the mesh in peace (mesh might not be weighted) + + # probably make a weight checker for each mesh so the exporter is complete + is_weighted = True # variable used later + + if (object.vertex_groups.active == None): + print("Mesh \"" + object.name + "\" does not have any Vertex Group assigned.") + + # change to edit mode (for vertex selection stuff) + bpy.ops.object.mode_set(mode='EDIT') + + # get vertex group name (first armature bone name) + ver_group_name = armature.data.bones[0].name + print("Creating Vertex Group: \"" + ver_group_name + "\"") + + # create new vertex group for mesh + object.vertex_groups.new(name = ver_group_name) + print("Assigning all vertex in mesh to Vertex Group...") + + # select all vertex in mesh + bpy.ops.mesh.select_all(action='SELECT') + #get vertex group created + ver_group = object.vertex_groups[ver_group_name] + # set active vertex group in mesh to new vertex group created + object.vertex_groups.active = ver_group + # assign all vertex of the mesh to said vertex group + bpy.ops.object.vertex_group_assign() + + print("Vertex assigned.") + + # go back to object mode + bpy.ops.object.mode_set(mode='OBJECT') + + else: + + # if the mesh contains vertex groups then they might not + # be correctly linked to the bones on an armature, + # in other words, the mesh might contain a vertex group which name + # isn't the name of a bone in the armature object + # (this will throw a SuperBMD error) + # Assimp.AssimpException: Error importing file: Collada: [DAE filename].dae - Invalid contents in element "n". + + if (len(object.vertex_groups) > len(armature.data.bones)): + error_string = "Mesh has a vertex group that isn't related to any bone of the Armature.\nCheck the meshes and try again." + print("\n### ERROR ###\n" + error_string + "\n### ERROR ###\n") + show_message(error_string, "Error exporting collada file", 'ERROR') + return {'FINISHED'} + + else: + for ver_group in object.vertex_groups: + valid_vertex_group = False + for bone in armature.data.bones: + if (ver_group.name == bone.name): + valid_vertex_group = True + break + + if (valid_vertex_group == False): + error_string = "Mesh has a vertex group that isn't related to any bone of the Armature.\nCheck the meshes and try again." + print("\n### ERROR ###\n" + error_string + "\n### ERROR ###\n") + show_message(error_string, "Error exporting collada file", 'ERROR') + return {'FINISHED'} + + # also the group might be valid but the vertex in + # the mesh might not be weigthed in the vertex group + # print message saying that the mesh might not be weighted + # even if it has a vertex group (set is_weighted to False) + + ######################################## + # make loop to check for weights (later) + ######################################## + + print("Mesh \"" + object.name + "\" has a Vertex Group assigned.") + print("Mesh might not be weighted.") + is_weighted = False + + # deselect mesh at the end of each loop + object.select = False + scene.objects.active = None + # + # + + print("\n### Mesh stuff done ###") + print() + + ################################################################# + # final part of the collada export + # print messages on vertex weight given by the is_weight variable + if (is_weighted): + print("All meshes are weighted") + else: + print("All meshes are probably weighted") + + print("Finalizing export...\n") + + # select armature object and make it active + # do the -90 degree rotation on X axis and scale it to 100 + # then do transform_apply, do transform_apply on the meshes + # inside the armature and finally export the result into a Collada file + + # the 100 scaling is done because SuperBMD isn't able + # to take the scaling factor on the DAE model and apply it to + # the mesh on the BMD/BDL conversion (it just ignores it) + + armature.select = True + scene.objects.active = armature + + # somehow the 2 statements before this comment change + # the armature object into pose mode (???) + # bpy.ops.object.mode_set(mode='OBJECT') + + # armature scale/rotation + print("Rotating Armature -90 degrees on the X axis...") + armature.rotation_euler[0] = math.radians(-90) + print("Scaling to 100...") + armature.scale = (100, 100, 100) + + # transform_apply the armature and its meshes + transform_apply_parent_child(scene, armature, False, True, True) + + # export model (selection only) + print("Exporting Model...") + bpy.ops.wm.collada_export(filepath = filepath, + use_blender_profile = False, + selected = True, + include_children = True, + triangulate = triangulate) + print("Collada file (DAE) exported.") + + # after export reset object rotation and scaling to original state + # i.e. apply a 90 degree rotation on X axis and scale to 0.01 + # then do transform_apply + + # armature scale/rotation + print("Reversing the -90 degrees rotation on the X axis...") + armature.rotation_euler[0] = math.radians(90) + print("Reversing the 100 scaling...") + armature.scale = (0.01, 0.01, 0.01) + + # transform_apply the armature and its meshes + transform_apply_parent_child(scene, armature, False, True, True) + + print("\n### Done! ###\n") + 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_BMD_BDL_Collada(Operator, ExportHelper): +# + """Save a Collada file for BMD/BDL conversion with SuperBMD""" + bl_idname = "export_scene.collada_bmd_bdl" + bl_label = "Export Collada (for BMD/BDL)" + 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) +# + +def menu_export_bmd_bdl_collada(self, context): + self.layout.operator(Export_BMD_BDL_Collada.bl_idname, text="Collada (for BMD/BDL) (.dae)") + +bpy.utils.register_class(Export_BMD_BDL_Collada) +bpy.types.INFO_MT_file_export.append(menu_export_bmd_bdl_collada) + +# test call +bpy.ops.export_scene.collada_bmd_bdl('INVOKE_DEFAULT') |