From cb14c408e56cda75feaf70a2d80e30d2f3e23832 Mon Sep 17 00:00:00 2001 From: REDxEYE Date: Sun, 2 Feb 2020 15:04:40 +0300 Subject: [PATCH] Plugin is now blender ready --- PyWMD | 2 +- __init__.py | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ model_import.py | 72 +++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 __init__.py diff --git a/PyWMD b/PyWMD index fbdde77..62f4979 160000 --- a/PyWMD +++ b/PyWMD @@ -1 +1 @@ -Subproject commit fbdde770cde29cf6885a8f7d547fd0501fcee168 +Subproject commit 62f49798b503a28ecd6da7edaee57f56f62d2dfa diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..bbc3f00 --- /dev/null +++ b/__init__.py @@ -0,0 +1,75 @@ +import os +import sys +from pathlib import Path + +bl_info = { + "name": "Pragma Engine model(.wmd)", + "author": "RED_EYE", + "version": (0, 0, 1), + "blender": (2, 80, 0), + "location": "File > Import-Export > Import Pragma WMD file", + "description": "Import/Export Pragma models", + "category": "Import-Export" +} + +import bpy +from bpy.props import StringProperty, BoolProperty, CollectionProperty, EnumProperty +from model_import import import_model + + +class PyWMDPreferences(bpy.types.AddonPreferences): + bl_idname = __package__ + + sfm_path: StringProperty(default='', name='SFM path') + + def draw(self, context): + layout = self.layout + # layout.label(text='Enter SFM install path:') + # row = layout.row() + # row.prop(self, 'sfm_path') + + +# noinspection PyUnresolvedReferences +class WMD_import_OT_operator(bpy.types.Operator): + """Load Pragma Engine WMD models""" + bl_idname = "py_wmd.wmd" + bl_label = "Import Pragma WMD file" + bl_options = {'UNDO'} + + filepath: StringProperty(subtype="FILE_PATH") + files: CollectionProperty(name='File paths', type=bpy.types.OperatorFileListElement) + + import_textures: BoolProperty(name="Load textures", default=False, subtype='UNSIGNED') + + filter_glob: StringProperty(default="*.wmd", options={'HIDDEN'}) + + def execute(self, context): + + if Path(self.filepath).is_file(): + directory = Path(self.filepath).parent.absolute() + else: + directory = Path(self.filepath).absolute() + for file in self.files: + import_model(file) + return {'FINISHED'} + + def invoke(self, context, event): + wm = context.window_manager + wm.fileselect_add(self) + return {'RUNNING_MODAL'} + + +classes = (PyWMDPreferences, WMD_import_OT_operator) +register_, unregister_ = bpy.utils.register_classes_factory(classes) + + +def register(): + register_() + + +def unregister(): + unregister_() + + +if __name__ == "__main__": + register() diff --git a/model_import.py b/model_import.py index a50eb1a..809f32d 100644 --- a/model_import.py +++ b/model_import.py @@ -1,3 +1,4 @@ +import random from pathlib import Path if __name__ == '__main__': @@ -11,6 +12,41 @@ from mathutils import Vector, Quaternion, Matrix +def get_material(mat_name, model_ob): + if mat_name: + mat_name = mat_name + else: + mat_name = "Material" + mat_ind = 0 + md = model_ob.data + mat = None + for candidate in bpy.data.materials: # Do we have this material already? + if candidate.name == mat_name: + mat = candidate + if mat: + if md.materials.get(mat.name): # Look for it on this mesh_data + for i in range(len(md.materials)): + if md.materials[i].name == mat.name: + mat_ind = i + break + else: # material exists, but not on this mesh_data + md.materials.append(mat) + mat_ind = len(md.materials) - 1 + else: # material does not exist + mat = bpy.data.materials.new(mat_name) + md.materials.append(mat) + # Give it a random colour + rand_col = [] + for i in range(3): + rand_col.append(random.uniform(.4, 1)) + rand_col.append(1.0) + mat.diffuse_color = rand_col + + mat_ind = len(md.materials) - 1 + + return mat_ind + + def create_child_bones(root_bone: PragmaBone, parent, armature): for child in root_bone.childs: bone = armature.edit_bones.new(child.name) @@ -78,7 +114,10 @@ def create_model(model, armature, collection): if len(group.sub_meshes) == 0: continue for sub_mesh in group.sub_meshes: - mesh_obj = bpy.data.objects.new(group.name, bpy.data.meshes.new('{}_MESH'.format(group.name))) + material = model.materials[sub_mesh.material_id] + + mesh_obj = bpy.data.objects.new(group.name + "_" + material, + bpy.data.meshes.new('{}_{}_SUB_MESH'.format(group.name, material))) mesh_obj.parent = armature group_collection.objects.link(mesh_obj) modifier = mesh_obj.modifiers.new( @@ -88,8 +127,37 @@ def create_model(model, armature, collection): mesh_data = mesh_obj.data mesh_data.from_pydata(sub_mesh.vertices, [], sub_mesh.indices) mesh_data.update() + + get_material(material, mesh_obj) + + bpy.ops.object.select_all(action="DESELECT") + mesh_obj.select_set(True) + bpy.context.view_layer.objects.active = mesh_obj + bpy.ops.object.shade_smooth() + mesh_data.use_auto_smooth = True - mesh_data.normals_split_custom_set_from_vertices (sub_mesh.normals) + mesh_data.normals_split_custom_set_from_vertices(sub_mesh.normals) + + mesh_data.uv_layers.new() + uv_data = mesh_data.uv_layers[0].data + for i in range(len(uv_data)): + u = sub_mesh.uvs[mesh_data.loops[i].vertex_index] + uv_data[i].uv = u + + weight_groups = {bone.name: mesh_obj.vertex_groups.new(name=bone.name) for bone in + model.armature.bones} + id2bone_name = {i: bone.name for i, bone in enumerate(model.armature.bones)} + + for n, (bone_ids, weights) in enumerate(sub_mesh.weights): + for bone_id, weight in zip(bone_ids, weights): + if weight == 0.0 or bone_id == -1: + continue + weight_groups[id2bone_name[bone_id]].add([n], weight, 'REPLACE') + for n, (bone_ids, weights) in enumerate(sub_mesh.additional_weights): + for bone_id, weight in zip(bone_ids, weights): + if weight == 0.0 or bone_id == -1: + continue + weight_groups[id2bone_name[bone_id]].add([n], weight, 'REPLACE') def import_model(model_path: str):