From 6a44a5aec67baede870a5a3435175578e68cf647 Mon Sep 17 00:00:00 2001 From: UuuNyaa Date: Tue, 23 Apr 2024 06:35:04 -0700 Subject: [PATCH] Remove bone_groups --- mmd_tools/core/bone.py | 61 +++++++++++++++++++++++--- mmd_tools/core/pmx/importer.py | 2 +- mmd_tools/operators/display_item.py | 50 ++------------------- mmd_tools/operators/model.py | 67 ++++++++++++++++------------- 4 files changed, 96 insertions(+), 84 deletions(-) diff --git a/mmd_tools/core/bone.py b/mmd_tools/core/bone.py index 94769518..05a13391 100644 --- a/mmd_tools/core/bone.py +++ b/mmd_tools/core/bone.py @@ -3,13 +3,18 @@ # This file is part of MMD Tools. import math -from typing import Iterable, Optional +from typing import TYPE_CHECKING, Iterable, Optional, Set import bpy from mathutils import Vector from mmd_tools import bpyutils from mmd_tools.bpyutils import TransformConstraintOp +import mmd_tools.utils + +if TYPE_CHECKING: + from mmd_tools.properties.root import MMDRoot, MMDDisplayItemFrame + from mmd_tools.properties.pose_bone import MMDBone def remove_constraint(constraints, name): @@ -74,7 +79,7 @@ def __get_selected_pose_bones(armature_object: bpy.types.Object) -> Iterable[bpy @staticmethod def load_bone_fixed_axis(armature_object: bpy.types.Object, enable=True): for b in FnBone.__get_selected_pose_bones(armature_object): - mmd_bone = b.mmd_bone + mmd_bone: MMDBone = b.mmd_bone mmd_bone.enabled_fixed_axis = enable lock_rotation = b.lock_rotation[:] if enable: @@ -143,14 +148,14 @@ def __unassign_mmd_tools_bone_collections(edit_bone: bpy.types.EditBone) -> bpy. return edit_bone @staticmethod - def sync_bone_collections_from_armature(armature_object: bpy.types.Object): + def sync_bone_collections_from_display_item_frames(armature_object: bpy.types.Object): armature: bpy.types.Armature = armature_object.data bone_collections = armature.collections from mmd_tools.core.model import FnModel root_object: bpy.types.Object = FnModel.find_root_object(armature_object) - mmd_root = root_object.mmd_root + mmd_root: MMDRoot = root_object.mmd_root bones = armature.bones used_groups = set() @@ -186,13 +191,55 @@ def sync_bone_collections_from_armature(armature_object: bpy.types.Object): continue bone_collections.remove(bone_collection) + @staticmethod + def sync_display_item_frames_from_bone_collections(armature_object: bpy.types.Object): + armature: bpy.types.Armature = armature_object.data + bone_collections: bpy.types.BoneCollections = armature.collections + + from mmd_tools.core.model import FnModel + + root_object: bpy.types.Object = FnModel.find_root_object(armature_object) + mmd_root: MMDRoot = root_object.mmd_root + display_item_frames = mmd_root.display_item_frames + + used_frame_index: Set[int] = set() + + bone_collection: bpy.types.BoneCollection + for bone_collection in bone_collections: + if len(bone_collection.bones) == 0 or FnBone.__is_special_bone_collection(bone_collection): + continue + + bone_collection_name = bone_collection.name + display_item_frame: Optional[MMDDisplayItemFrame] = display_item_frames.get(bone_collection_name) + if display_item_frame is None: + display_item_frame = display_item_frames.add() + display_item_frame.name = bone_collection_name + display_item_frame.name_e = bone_collection_name + used_frame_index.add(display_item_frames.find(bone_collection_name)) + + mmd_tools.utils.ItemOp.resize(display_item_frame.data, len(bone_collection.bones)) + for display_item, bone in zip(display_item_frame.data, bone_collection.bones): + display_item.type = "BONE" + display_item.name = bone.name + + for i in reversed(range(len(display_item_frames))): + if i in used_frame_index: + continue + display_item_frame = display_item_frames[i] + if display_item_frame.is_special: + if display_item_frame.name != "表情": + display_item_frame.data.clear() + else: + display_item_frames.remove(i) + mmd_root.active_display_item_frame = 0 + @staticmethod def apply_bone_fixed_axis(armature_object: bpy.types.Object): bone_map = {} for b in armature_object.pose.bones: if b.is_mmd_shadow_bone or not b.mmd_bone.enabled_fixed_axis: continue - mmd_bone = b.mmd_bone + mmd_bone: MMDBone = b.mmd_bone parent_tip = b.parent and not b.parent.is_mmd_shadow_bone and b.parent.mmd_bone.is_tip bone_map[b.name] = (mmd_bone.fixed_axis.normalized(), mmd_bone.is_tip, parent_tip) @@ -238,7 +285,7 @@ def apply_bone_fixed_axis(armature_object: bpy.types.Object): @staticmethod def load_bone_local_axes(armature_object: bpy.types.Object, enable=True): for b in FnBone.__get_selected_pose_bones(armature_object): - mmd_bone = b.mmd_bone + mmd_bone: MMDBone = b.mmd_bone mmd_bone.enabled_local_axes = enable if enable: axes = b.bone.matrix_local.to_3x3().transposed() @@ -251,7 +298,7 @@ def apply_bone_local_axes(armature_object: bpy.types.Object): for b in armature_object.pose.bones: if b.is_mmd_shadow_bone or not b.mmd_bone.enabled_local_axes: continue - mmd_bone = b.mmd_bone + mmd_bone: MMDBone = b.mmd_bone bone_map[b.name] = (mmd_bone.local_axis_x, mmd_bone.local_axis_z) with bpyutils.edit_object(armature_object) as data: diff --git a/mmd_tools/core/pmx/importer.py b/mmd_tools/core/pmx/importer.py index b9086e69..48d9b1ac 100644 --- a/mmd_tools/core/pmx/importer.py +++ b/mmd_tools/core/pmx/importer.py @@ -778,7 +778,7 @@ def __importDisplayFrames(self): else: raise Exception("Unknown display item type.") - DisplayItemQuickSetup.apply_bone_groups(root.mmd_root, self.__armObj) + FnBone.sync_bone_collections_from_display_item_frames(self.__armObj) def __addArmatureModifier(self, meshObj, armObj): # TODO: move to model.py diff --git a/mmd_tools/operators/display_item.py b/mmd_tools/operators/display_item.py index ab7013ad..0117a8ad 100644 --- a/mmd_tools/operators/display_item.py +++ b/mmd_tools/operators/display_item.py @@ -258,8 +258,8 @@ class DisplayItemQuickSetup(Operator): items=[ ("RESET", "Reset", "Clear all items and frames, reset to default", "X", 0), ("FACIAL", "Load Facial Items", "Load all morphs to faical frame", "SHAPEKEY_DATA", 1), - ("GROUP_LOAD", "Load Bone Groups", "Load armature's bone groups to display item frames", "GROUP_BONE", 2), - ("GROUP_APPLY", "Apply Bone Groups", "Apply display item frames to armature's bone groups", "GROUP_BONE", 3), + ("GROUP_LOAD", "Sync from Bone Collections", "Sync armature's bone collections to display item frames", "GROUP_BONE", 2), + ("GROUP_APPLY", "Sync to Bone Collections", "Sync display item frames to armature's bone collections", "GROUP_BONE", 3), ], default="FACIAL", ) @@ -274,10 +274,10 @@ def execute(self, context): rig.initialDisplayFrames(reset=False) # ensure default frames self.load_facial_items(root.mmd_root) elif self.type == "GROUP_LOAD": - self.load_bone_groups(root.mmd_root, rig.armature()) + FnBone.sync_display_item_frames_from_bone_collections(rig.armature()) rig.initialDisplayFrames(reset=False) # ensure default frames elif self.type == "GROUP_APPLY": - self.apply_bone_groups(root.mmd_root, rig.armature()) + FnBone.sync_bone_collections_from_display_item_frames(rig.armature()) return {"FINISHED"} @staticmethod @@ -303,45 +303,3 @@ def load_facial_items(mmd_root): item.type = "MORPH" item.morph_type, item.name = data frame.active_item = 0 - - @staticmethod - def load_bone_groups(mmd_root, armature): - bone_groups = OrderedDict((i.name, []) for i in armature.pose.bone_groups) - for b in armature.pose.bones: - if b.bone_group: - bone_groups[b.bone_group.name].append(b.name) - - frames = mmd_root.display_item_frames - used_index = set() - for group_name, bone_names in bone_groups.items(): - if len(bone_names) < 1: # skip empty group - continue - - frame = frames.get(group_name) - if frame is None: - frame = frames.add() - frame.name = group_name - frame.name_e = group_name - used_index.add(frames.find(group_name)) - - items = frame.data - ItemOp.resize(items, len(bone_names)) - for item, name in zip(items, bone_names): - item.type = "BONE" - item.name = name - frame.active_item = 0 - - # remove unused frames - for i in reversed(range(len(frames))): - if i not in used_index: - frame = frames[i] - if frame.is_special: - if frame.name != "表情": - frame.data.clear() - else: - frames.remove(i) - mmd_root.active_display_item_frame = 0 - - @staticmethod - def apply_bone_groups(mmd_root, armature): - FnBone.sync_bone_collections_from_armature(armature) diff --git a/mmd_tools/operators/model.py b/mmd_tools/operators/model.py index ff1b0e5d..dc41beb1 100644 --- a/mmd_tools/operators/model.py +++ b/mmd_tools/operators/model.py @@ -2,12 +2,17 @@ # Copyright 2014 MMD Tools authors # This file is part of MMD Tools. +from typing import TYPE_CHECKING, cast + import bpy from bpy.types import Operator -import mmd_tools.core.model as mmd_model from mmd_tools.bpyutils import SceneOp, activate_layer_collection from mmd_tools.core.bone import FnBone, MigrationFnBone +from mmd_tools.core.model import FnModel, Model + +if TYPE_CHECKING: + from mmd_tools.properties.root import MMDRoot class MorphSliderSetup(Operator): @@ -29,10 +34,10 @@ class MorphSliderSetup(Operator): def execute(self, context): obj = context.active_object - root = mmd_model.Model.findRoot(context.active_object) + root = FnModel.find_root_object(context.active_object) with activate_layer_collection(root): - rig = mmd_model.Model(root) + rig = Model(root) if self.type == "BIND": rig.morph_slider.bind() elif self.type == "UNBIND": @@ -51,8 +56,8 @@ class CleanRiggingObjects(Operator): bl_options = {"REGISTER", "UNDO", "INTERNAL"} def execute(self, context): - root = mmd_model.Model.findRoot(context.active_object) - rig = mmd_model.Model(root) + root = FnModel.find_root_object(context.active_object) + rig = Model(root) rig.clean() SceneOp(context).active_object = root return {"FINISHED"} @@ -82,10 +87,10 @@ class BuildRig(Operator): ) def execute(self, context): - root = mmd_model.Model.findRoot(context.active_object) + root = FnModel.find_root_object(context.active_object) with activate_layer_collection(root): - rig = mmd_model.Model(root) + rig = Model(root) rig.build(self.non_collision_distance_scale, self.collision_margin) SceneOp(context).active_object = root @@ -100,8 +105,8 @@ class CleanAdditionalTransformConstraints(Operator): def execute(self, context): obj = context.active_object - root = mmd_model.Model.findRoot(obj) - rig = mmd_model.Model(root) + root = FnModel.find_root_object(obj) + rig = Model(root) FnBone.clean_additional_transformation(rig.armature()) SceneOp(context).active_object = obj return {"FINISHED"} @@ -115,8 +120,8 @@ class ApplyAdditionalTransformConstraints(Operator): def execute(self, context): obj = context.active_object - root = mmd_model.Model.findRoot(obj) - rig = mmd_model.Model(root) + root = FnModel.find_root_object(obj) + rig = Model(root) MigrationFnBone.fix_mmd_ik_limit_override(rig.armature()) FnBone.apply_additional_transformation(rig.armature()) @@ -200,17 +205,18 @@ class AddMissingVertexGroupsFromBones(Operator): @classmethod def poll(cls, context: bpy.types.Context): - return mmd_model.FnModel.find_root_object(context.active_object) is not None + return FnModel.find_root_object(context.active_object) is not None def execute(self, context: bpy.types.Context): active_object: bpy.types.Object = context.active_object - root_object = mmd_model.FnModel.find_root_object(active_object) + root_object = FnModel.find_root_object(active_object) + assert root_object is not None - bone_order_mesh_object = mmd_model.FnModel.find_bone_order_mesh_object(root_object) + bone_order_mesh_object = FnModel.find_bone_order_mesh_object(root_object) if bone_order_mesh_object is None: return {"CANCELLED"} - mmd_model.FnModel.add_missing_vertex_groups_from_bones(root_object, bone_order_mesh_object, self.search_in_all_meshes) + FnModel.add_missing_vertex_groups_from_bones(root_object, bone_order_mesh_object, self.search_in_all_meshes) return {"FINISHED"} @@ -238,7 +244,7 @@ class CreateMMDModelRoot(Operator): ) def execute(self, context): - rig = mmd_model.Model.create(self.name_j, self.name_e, self.scale, add_root_bone=True) + rig = Model.create(self.name_j, self.name_e, self.scale, add_root_bone=True) rig.initialDisplayFrames() return {"FINISHED"} @@ -310,12 +316,12 @@ def execute(self, context): scale = self.scale model_name = "New MMD Model" - root = mmd_model.Model.findRoot(armature) + root = FnModel.find_root_object(armature) if root is None or root != armature.parent: - rig = mmd_model.Model.create(model_name, model_name, scale, armature=armature) + Model.create(model_name, model_name, scale, armature=armature) self.__attach_meshes_to(armature, SceneOp(context).id_objects) - self.__configure_rig(context, mmd_model.Model(armature.parent)) + self.__configure_rig(context, Model(armature.parent)) return {"FINISHED"} def __attach_meshes_to(self, armature, objects): @@ -379,7 +385,7 @@ def __configure_rig(self, context, rig): FnMaterial.set_nodes_are_readonly(False) from mmd_tools.operators.display_item import DisplayItemQuickSetup - DisplayItemQuickSetup.load_bone_groups(root.mmd_root, armature) + FnBone.sync_display_item_frames_from_bone_collections(armature) rig.initialDisplayFrames(reset=False) # ensure default frames DisplayItemQuickSetup.load_facial_items(root.mmd_root) root.mmd_root.active_display_item_frame = 0 @@ -393,24 +399,25 @@ class ResetObjectVisibility(bpy.types.Operator): @classmethod def poll(cls, context: bpy.types.Context): active_object: bpy.types.Object = context.active_object - return mmd_model.Model.findRoot(active_object) is not None + return FnModel.find_root_object(active_object) is not None def execute(self, context: bpy.types.Context): active_object: bpy.types.Object = context.active_object - mmd_root_object = mmd_model.Model.findRoot(active_object) - mmd_root = mmd_root_object.mmd_root + mmd_root_object = FnModel.find_root_object(active_object) + assert mmd_root_object is not None + mmd_root = cast(MMDRoot, mmd_root_object.mmd_root) mmd_root_object.hide_set(False) - rigid_group_object = mmd_model.FnModel.find_rigid_group_object(mmd_root_object) + rigid_group_object = FnModel.find_rigid_group_object(mmd_root_object) if rigid_group_object: rigid_group_object.hide_set(True) - joint_group_object = mmd_model.FnModel.find_joint_group_object(mmd_root_object) + joint_group_object = FnModel.find_joint_group_object(mmd_root_object) if joint_group_object: joint_group_object.hide_set(True) - temporary_group_object = mmd_model.FnModel.find_temporary_group_object(mmd_root_object) + temporary_group_object = FnModel.find_temporary_group_object(mmd_root_object) if temporary_group_object: temporary_group_object.hide_set(True) @@ -432,10 +439,10 @@ class AssembleAll(Operator): def execute(self, context): active_object = context.active_object - root_object = mmd_model.Model.findRoot(active_object) + root_object = FnModel.find_root_object(active_object) with activate_layer_collection(root_object): - rig = mmd_model.Model(root_object) + rig = Model(root_object) MigrationFnBone.fix_mmd_ik_limit_override(rig.armature()) FnBone.apply_additional_transformation(rig.armature()) @@ -458,10 +465,10 @@ class DisassembleAll(Operator): def execute(self, context): active_object = context.active_object - root_object = mmd_model.Model.findRoot(active_object) + root_object = FnModel.find_root_object(active_object) with activate_layer_collection(root_object): - rig = mmd_model.Model(root_object) + rig = Model(root_object) root_object.mmd_root.use_property_driver = False with bpy.context.temp_override(selected_objects=[active_object]):