From ff3a517312029c03bcc3e292b1739f7ee3695417 Mon Sep 17 00:00:00 2001 From: Will Snyder Date: Fri, 16 Oct 2020 13:56:03 -0500 Subject: [PATCH] Menu anim export option, minor reorg --- addons/io_scene_swbf_msh/__init__.py | 12 ++++- addons/io_scene_swbf_msh/msh_anim_gather.py | 34 +++++++++--- addons/io_scene_swbf_msh/msh_model.py | 2 +- addons/io_scene_swbf_msh/msh_model_gather.py | 13 ++--- .../io_scene_swbf_msh/msh_model_utilities.py | 23 ++++++++ addons/io_scene_swbf_msh/msh_scene_save.py | 54 +++++++++++-------- 6 files changed, 98 insertions(+), 40 deletions(-) diff --git a/addons/io_scene_swbf_msh/__init__.py b/addons/io_scene_swbf_msh/__init__.py index 200b48f..2d25e73 100644 --- a/addons/io_scene_swbf_msh/__init__.py +++ b/addons/io_scene_swbf_msh/__init__.py @@ -97,14 +97,24 @@ class ExportMSH(Operator, ExportHelper): default=True ) + export_anims: BoolProperty( + name="Export Animations", + description="Action export test", + default=False + ) + + def execute(self, context): + with open(self.filepath, 'wb') as output_file: save_scene( output_file=output_file, scene=create_scene( generate_triangle_strips=self.generate_triangle_strips, apply_modifiers=self.apply_modifiers, - export_target=self.export_target)) + export_target=self.export_target), + separate_anims=self.export_anims + ) return {'FINISHED'} diff --git a/addons/io_scene_swbf_msh/msh_anim_gather.py b/addons/io_scene_swbf_msh/msh_anim_gather.py index 86de953..bf7ef8c 100644 --- a/addons/io_scene_swbf_msh/msh_anim_gather.py +++ b/addons/io_scene_swbf_msh/msh_anim_gather.py @@ -35,12 +35,8 @@ def gather_animdata(armature: bpy.types.Armature) -> List[Animation]: for bone in armature.pose.bones: xform = ModelTransform() - xform.translation = convert_vector_space(bone.location) - xform.translation.x *= -1.0 - xform.rotation = convert_rotation_space(bone.rotation_quaternion) - xform.rotation.x *= -1.0 - xform.rotation.y *= -1.0 - xform.rotation.z *= -1.0 + xform.translation = to_skeleton_vector_space(bone.location) + xform.rotation = to_skeleton_rotation_space(bone.rotation_quaternion) anim_data.bone_transforms[bone.name].append(xform) @@ -48,6 +44,32 @@ def gather_animdata(armature: bpy.types.Armature) -> List[Animation]: return [anim_data] +def get_basepose(armature: bpy.types.Armature) -> Animation: + + anim_data = Animation(); + anim_data.name = "basepose" + + bpy.context.scene.frame_set(0.0) + + anim_data.bone_transforms[armature.parent.name] = [] + for bone in armature.data.bones: + anim_data.bone_transforms[bone.name] = [] + + for frame in range(2): + + anim_data.bone_transforms[armature.parent.name].append(ModelTransform()) #for testing + + for bone in armature.pose.bones: + + xform = ModelTransform() + xform.translation = to_skeleton_vector_space(bone.location) + xform.rotation = to_skeleton_rotation_space(bone.rotation_quaternion) + + anim_data.bone_transforms[bone.name].append(xform) + + + return anim_data + diff --git a/addons/io_scene_swbf_msh/msh_model.py b/addons/io_scene_swbf_msh/msh_model.py index cdcc2e4..0af2932 100644 --- a/addons/io_scene_swbf_msh/msh_model.py +++ b/addons/io_scene_swbf_msh/msh_model.py @@ -80,6 +80,6 @@ class Model: class Animation: """ Class representing 'CYCL' + 'KFR3' sections in a .msh file """ - name: str = "open" + name: str = "wiggle" bone_transforms: Dict[str, List[ModelTransform]] = field(default_factory=dict) diff --git a/addons/io_scene_swbf_msh/msh_model_gather.py b/addons/io_scene_swbf_msh/msh_model_gather.py index 2119dbc..c189e5d 100644 --- a/addons/io_scene_swbf_msh/msh_model_gather.py +++ b/addons/io_scene_swbf_msh/msh_model_gather.py @@ -36,6 +36,7 @@ def gather_models(apply_modifiers: bool, export_target: str) -> List[Model]: if obj.type == "ARMATURE": models_list += expand_armature(obj) + continue local_translation, local_rotation, _ = obj.matrix_local.decompose() @@ -47,6 +48,7 @@ def gather_models(apply_modifiers: bool, export_target: str) -> List[Model]: model.transform.translation = convert_vector_space(local_translation) if obj.type in MESH_OBJECT_TYPES: + mesh = obj.to_mesh() model.geometry = create_mesh_geometry(mesh, obj.vertex_groups) obj.to_mesh_clear() @@ -353,7 +355,7 @@ def expand_armature(obj: bpy.types.Object) -> List[Model]: transform = bone.parent.matrix_local.inverted() @ transform model.parent = bone.parent.name else: - model.parent = obj.name + model.parent = "DummyRoot" # obj.name local_translation, local_rotation, _ = transform.decompose() @@ -365,12 +367,3 @@ def expand_armature(obj: bpy.types.Object) -> List[Model]: bones.append(model) return bones - -def convert_vector_space(vec: Vector) -> Vector: - return Vector((-vec.x, vec.z, vec.y)) - -def convert_scale_space(vec: Vector) -> Vector: - return Vector(vec.xzy) - -def convert_rotation_space(quat: Quaternion) -> Quaternion: - return Quaternion((-quat.w, quat.x, -quat.z, -quat.y)) diff --git a/addons/io_scene_swbf_msh/msh_model_utilities.py b/addons/io_scene_swbf_msh/msh_model_utilities.py index 1547697..e33e9f4 100644 --- a/addons/io_scene_swbf_msh/msh_model_utilities.py +++ b/addons/io_scene_swbf_msh/msh_model_utilities.py @@ -114,3 +114,26 @@ def is_model_name_unused(name: str, models: List[Model]) -> bool: return False return True + + +def convert_vector_space(vec: Vector) -> Vector: + return Vector((-vec.x, vec.z, vec.y)) + +def convert_scale_space(vec: Vector) -> Vector: + return Vector(vec.xzy) + +def convert_rotation_space(quat: Quaternion) -> Quaternion: + return Quaternion((-quat.w, quat.x, -quat.z, -quat.y)) + + +def to_skeleton_vector_space(vec : Vector): + vnew = convert_vector_space(vec) + vnew.x *= -1.0 + return vnew + +def to_skeleton_rotation_space(quat : Quaternion): + qnew = convert_rotation_space(quat) + qnew.x *= -1.0 + qnew.y *= -1.0 + qnew.z *= -1.0 + return qnew diff --git a/addons/io_scene_swbf_msh/msh_scene_save.py b/addons/io_scene_swbf_msh/msh_scene_save.py index a049bf1..dc3a2ae 100644 --- a/addons/io_scene_swbf_msh/msh_scene_save.py +++ b/addons/io_scene_swbf_msh/msh_scene_save.py @@ -10,7 +10,7 @@ from .msh_utilities import * from .crc import * -def save_scene(output_file, scene: Scene): +def save_scene(output_file, scene: Scene, separate_anims: bool): """ Saves scene to the supplied file. """ with Writer(file=output_file, chunk_id="HEDR") as hedr: @@ -26,12 +26,15 @@ def save_scene(output_file, scene: Scene): material_index = _write_matl_and_get_material_index(matl, scene) for index, model in enumerate(scene.models): + if separate_anims and (model.model_type not in {ModelType.NULL, ModelType.BONE}): + continue with msh2.create_child("MODL") as modl: _write_modl(modl, model, index, material_index, model_index) - with hedr.create_child("ANM2") as anm2: #simple for now - for anim in scene.anims: - _write_anm2(anm2, anim) + if separate_anims: + with hedr.create_child("ANM2") as anm2: #simple for now + for anim in scene.anims: + _write_anm2(anm2, anim) with hedr.create_child("CL1L"): pass @@ -205,7 +208,32 @@ def _write_segm(segm: Writer, segment: GeometrySegment, material_index: Dict[str for index in islice(strip, 2, len(strip)): strp.write_u16(index) +''' +SKINNING CHUNKS +''' +def _write_wght(wght: Writer, weights: List[List[VertexWeight]]): + wght.write_u32(len(weights)) + for weight_list in weights: + weight_list += [VertexWeight(0.0, 0)] * 4 + weight_list = sorted(weight_list, key=lambda w: w.weight, reverse=True) + weight_list = weight_list[:4] + + total_weight = max(sum(map(lambda w: w.weight, weight_list)), 1e-5) + + for weight in weight_list: + wght.write_i32(weight.bone) + wght.write_f32(weight.weight / total_weight) + +def _write_envl(envl: Writer, model: Model, model_index: Dict[str, int]): + envl.write_u32(len(model.bone_map)) + + for bone_name in model.bone_map: + envl.write_u32(model_index[bone_name]) + +''' +ANIMATION CHUNKS +''' def _write_anm2(anm2: Writer, anim: Animation): with anm2.create_child("CYCL") as cycl: @@ -240,22 +268,4 @@ def _write_anm2(anm2: Writer, anim: Animation): kfr3.write_f32(xform.rotation.x, xform.rotation.y, xform.rotation.z, xform.rotation.w) -def _write_wght(wght: Writer, weights: List[List[VertexWeight]]): - wght.write_u32(len(weights)) - for weight_list in weights: - weight_list += [VertexWeight(0.0, 0)] * 4 - weight_list = sorted(weight_list, key=lambda w: w.weight, reverse=True) - weight_list = weight_list[:4] - - total_weight = max(sum(map(lambda w: w.weight, weight_list)), 1e-5) - - for weight in weight_list: - wght.write_i32(weight.bone) - wght.write_f32(weight.weight / total_weight) - -def _write_envl(envl: Writer, model: Model, model_index: Dict[str, int]): - envl.write_u32(len(model.bone_map)) - - for bone_name in model.bone_map: - envl.write_u32(model_index[bone_name])