summaryrefslogtreecommitdiff
path: root/collada_bmd_bdl_export.py
diff options
context:
space:
mode:
Diffstat (limited to 'collada_bmd_bdl_export.py')
-rw-r--r--collada_bmd_bdl_export.py313
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')