summaryrefslogtreecommitdiff
path: root/collada_superbmd_export.py
diff options
context:
space:
mode:
authorIsaac <isaclien9752@gmail.com>2024-08-14 22:48:16 -0400
committerIsaac <isaclien9752@gmail.com>2024-08-14 22:48:16 -0400
commit17fd2304270b2ef619cceb980b9f49cb656a6d13 (patch)
treedecd5572cf766c781c2bb6a604aa66155041cdb4 /collada_superbmd_export.py
parentb907bcc414eb742f45e2a0c2ea0232256c226a92 (diff)
downloadblenxy-17fd2304270b2ef619cceb980b9f49cb656a6d13.tar.gz
blenxy-17fd2304270b2ef619cceb980b9f49cb656a6d13.zip
updated Collada importer/exporter for SuperBMD
Diffstat (limited to 'collada_superbmd_export.py')
-rw-r--r--collada_superbmd_export.py168
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')