123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- '''
- 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 an armature object selection
- '''
- 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
-
- # change mesh to object view (in case it isn't)
- bpy.ops.object.mode_set(mode='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')
|