From 8b000b1060df3ae43f743f453f10404089acda90 Mon Sep 17 00:00:00 2001 From: wikid24 Date: Tue, 30 Apr 2024 16:25:58 -0700 Subject: [PATCH] new translate method prep,import custom bonemorphs --- ffxiv_mmd_tools_helper/__init__.py | 2 + ffxiv_mmd_tools_helper/bone_conversion.py | 8 +- ffxiv_mmd_tools_helper/bone_morphs.py | 70 ++- .../bone_retargeting_addon.py | 368 +++++++++++++- ffxiv_mmd_tools_helper/bone_tools.py | 22 +- .../data/bones_dictionary.csv | 158 +++--- .../data/bones_fingers_dictionary.csv | 62 +-- .../data/bones_metadata_ffxiv_dictionary.csv | 454 +++++++++--------- ffxiv_mmd_tools_helper/import_csv.py | 10 +- ffxiv_mmd_tools_helper/miscellaneous_tools.py | 14 + ffxiv_mmd_tools_helper/panels.py | 2 + .../panels_retargeting_addon.py | 44 +- ffxiv_mmd_tools_helper/translate.py | 205 ++++++++ 13 files changed, 1001 insertions(+), 418 deletions(-) create mode 100644 ffxiv_mmd_tools_helper/translate.py diff --git a/ffxiv_mmd_tools_helper/__init__.py b/ffxiv_mmd_tools_helper/__init__.py index 947c11e..c8c9225 100644 --- a/ffxiv_mmd_tools_helper/__init__.py +++ b/ffxiv_mmd_tools_helper/__init__.py @@ -67,6 +67,7 @@ def register_wrap(cls): importlib.reload(shaders_colorsetter) importlib.reload(shaders_mektools) importlib.reload(shaders) + importlib.reload(translate) importlib.reload(tex_converter) importlib.reload(panels) importlib.reload(panels_retargeting_addon) @@ -107,6 +108,7 @@ def register_wrap(cls): from . import shaders_colorsetter from . import shaders_mektools from . import shaders + from . import translate from . import tex_converter from . import panels from . import panels_retargeting_addon diff --git a/ffxiv_mmd_tools_helper/bone_conversion.py b/ffxiv_mmd_tools_helper/bone_conversion.py index 132b7b2..1069f28 100644 --- a/ffxiv_mmd_tools_helper/bone_conversion.py +++ b/ffxiv_mmd_tools_helper/bone_conversion.py @@ -691,11 +691,11 @@ def add_shoulder_control_bones(): shoulder_R = armature.data.edit_bones["shoulder_R"] arm_L = armature.data.edit_bones["arm_L"] arm_R = armature.data.edit_bones["arm_R"] - j_sebo_c = armature.data.edit_bones["j_sebo_c"] + upper_body_3 = armature.data.edit_bones["upper body 3"] #create new bones - shoulder_P_L = bone_tools.add_bone(armature, 'shoulder_P_L',parent_bone=j_sebo_c,length=shoulder_L.length,head=shoulder_L.head ,tail=shoulder_L.head) - shoulder_P_R = bone_tools.add_bone(armature, 'shoulder_P_R',parent_bone=j_sebo_c,length=shoulder_R.length,head=shoulder_R.head ,tail=shoulder_R.head) + shoulder_P_L = bone_tools.add_bone(armature, 'shoulder_P_L',parent_bone=upper_body_3,length=shoulder_L.length,head=shoulder_L.head ,tail=shoulder_L.head) + shoulder_P_R = bone_tools.add_bone(armature, 'shoulder_P_R',parent_bone=upper_body_3,length=shoulder_R.length,head=shoulder_R.head ,tail=shoulder_R.head) shoulder_C_L = bone_tools.add_bone(armature, 'shoulder_C_L',parent_bone=shoulder_L,length=shoulder_L.length,head=shoulder_L.tail ,tail=shoulder_L.tail) shoulder_C_R = bone_tools.add_bone(armature, 'shoulder_C_R',parent_bone=shoulder_R,length=shoulder_R.length,head=shoulder_R.tail ,tail=shoulder_R.tail) @@ -862,7 +862,7 @@ def convert_ffxiv_boobs_to_genshin_boobs(context,armature): boob_core.length = 0 boob_core.length = j_mune_l.length #upper_body_2_name = bone_tools.get_armature_bone_name_by_mmd_english_bone_name(armature,'upper body 3') - j_sebo_c = armature.data.edit_bones.get('j_sebo_c') + j_sebo_c = armature.data.edit_bones.get(bone_tools.get_armature_bone_name_by_mmd_english_bone_name(armature,'upper body 3')) boob_core.parent = j_sebo_c bone_list = [j_mune_l,j_mune_r] diff --git a/ffxiv_mmd_tools_helper/bone_morphs.py b/ffxiv_mmd_tools_helper/bone_morphs.py index 13440fb..0621a4a 100644 --- a/ffxiv_mmd_tools_helper/bone_morphs.py +++ b/ffxiv_mmd_tools_helper/bone_morphs.py @@ -213,13 +213,6 @@ def parse_bone_morphs_data_from_csv (csv_data): return bone_morphs_dictionary -def read_bone_morphs_dict_file(ffxiv_race): - - BONE_MORPHS_DICTIONARY = None - BONE_MORPHS_DICTIONARY = import_csv.use_csv_bone_morphs_dictionary(ffxiv_race) - - return BONE_MORPHS_DICTIONARY - def read_bone_morphs_list_file(): BONE_MORPHS_LIST = None @@ -239,22 +232,19 @@ def change_face_rotation_mode(rotation_mode): bone.rotation_mode = rotation_mode -def main(context): +def main(context,file_path): + + print("the filepath for the selected file is:",file_path) + armature = bpy.context.active_object #model.find_MMD_Armature(bpy.context.object) bpy.context.view_layer.objects.active = armature clear_bone_morph() - - #print(bone_morph) - - if bpy.context.scene.bone_morph_ffxiv_model_list == 'none': - pass - else: - BONE_MORPH_DICTIONARY = read_bone_morphs_dict_file(bpy.context.scene.bone_morph_ffxiv_model_list) - bone_morphs = parse_bone_morphs_data_from_csv(BONE_MORPH_DICTIONARY) - for bone_morph in bone_morphs: - generate_bone_morph(armature,bone_morph,bone_morphs[bone_morph]) + BONE_MORPH_DICTIONARY = import_csv.use_csv_bone_morphs_dictionary(file_path) + bone_morphs = parse_bone_morphs_data_from_csv(BONE_MORPH_DICTIONARY) + for bone_morph in bone_morphs: + generate_bone_morph(armature,bone_morph,bone_morphs[bone_morph]) @@ -276,8 +266,6 @@ class AddBoneMorphs(bpy.types.Operator): , ("roegadyn", "Roegadyn","Import Roegadyn Bone Morphs") \ , ("viera", "Viera","Import Viera Bone Morphs") \ ], name = "Race", default = 'hyur') - - bpy.types.Scene.alternate_folder_cbx = bpy.props.BoolProperty(name="Use Alternate Folder for CSVs", default=False) @@ -288,9 +276,45 @@ def poll(cls, context): return obj is not None and obj.type == 'ARMATURE' and root is not None def execute(self, context): - main(context) + + if bpy.context.scene.bone_morph_ffxiv_model_list == 'none': + pass + else: + ffxiv_race = bpy.context.scene.bone_morph_ffxiv_model_list + file_path = (__file__ + r"data\bone_morphs_" + ffxiv_race +".csv").replace("bone_morphs.py" , "") + + + main(context,file_path) #context.scene.bone_morph_ffxiv_model_list = self.bone_morph_ffxiv_model_list return {'FINISHED'} + + +from bpy_extras.io_utils import ImportHelper +@register_wrap +class ImportCustomBoneMorphsFile(bpy.types.Operator, ImportHelper): + """Import a custom Bone Morphs CSV File""" + bl_idname = "ffxiv_mmd.import_custom_bone_morphs_file" + bl_label = "Import CSV" + bl_options = {'REGISTER', 'UNDO'} + + filename_ext = ".csv" + filter_glob: bpy.props.StringProperty( + default="*.csv", + options={'HIDDEN'}, + ) + + @classmethod + def poll(cls, context): + obj = context.active_object + root = mmd_model.Model.findRoot(obj) + return obj is not None and obj.type == 'ARMATURE' and root is not None + + def execute(self, context): + filepath = self.filepath + + main (context,filepath) + + return {'FINISHED'} @register_wrap class OpenBoneMorphsFile(bpy.types.Operator): @@ -301,7 +325,11 @@ class OpenBoneMorphsFile(bpy.types.Operator): def execute(self, context): import_csv.open_bone_morphs_dictionary(context.scene.bone_morph_ffxiv_model_list) return {'FINISHED'} + + + + @register_wrap class ChangeFaceBoneRotationMode(bpy.types.Operator): """Changes all Face Bones to the selected Rotation Mode""" diff --git a/ffxiv_mmd_tools_helper/bone_retargeting_addon.py b/ffxiv_mmd_tools_helper/bone_retargeting_addon.py index a5ac8b3..668aef6 100644 --- a/ffxiv_mmd_tools_helper/bone_retargeting_addon.py +++ b/ffxiv_mmd_tools_helper/bone_retargeting_addon.py @@ -2,6 +2,7 @@ import addon_utils from . import register_wrap from . import bone_tools +from . import translate """ import sys @@ -75,8 +76,8 @@ def is_source_and_target_mapped(armature): def compare_str(string1,string2): if string1 and string2: - cleaned_string1 = string1.strip().lower() - cleaned_string2 = string2.strip().lower() + cleaned_string1 = translate.parseJp(string1.strip().lower()) + cleaned_string2 = translate.parseJp(string2.strip().lower()) return cleaned_string1 == cleaned_string2 else: @@ -139,7 +140,7 @@ def add_bone_mapping(target_armature, source_bone,target_bone): art_mapping_controls.active_mapping = len(read_only_mapping_data) - # Garbage cleanup, iterating backward + # Garbage cleanup for i,mapping in enumerate(read_only_mapping_data): art_mapping_controls.active_mapping = i @@ -182,7 +183,7 @@ def get_mapping_bone_group_list(bone_group): if bone_group in bone_group_dictionary: #get ALL bones names from ALL target_columns where animation_retargeting_group is not blank - target_columns = ['mmd_english', 'mmd_japanese', 'mmd_japaneseLR', 'blender_rigify', 'ffxiv','mmd_kaito'] + target_columns = ['mmd_english','mmd_english_alt', 'mmd_japanese', 'mmd_japaneseLR', 'blender_rigify', 'ffxiv','mmd_kaito'] FFXIV_BONE_METADATA_DICTIONARY = bone_tools.get_csv_metadata_by_bone_type('animation_retargeting_group', target_columns) bone_list = [] @@ -220,7 +221,69 @@ def get_mapping_target_bones(bone_group,target_armature): return None +####################### DEREK PICK UP FROM HERE################################################ +# NEED TO FINISH OPERATOR FOR ffxiv_mmd.art_autofix_bone_mapping AND THIS FUNCTION #################### +def get_bone_from_index(context,index): + active_object = context.active_object + #active_pose_bone = context.active_pose_bone + rtc = active_object.get('retargeting_context') + source_arm = rtc.get('source') + #target_arm = rtc.get('target') + #mapping_data = active_object.get('retargeting_context').get('mappings') + index = int(active_object.retargeting_context.active_mapping) + + target_bone_name = active_object.retargeting_context.mappings[index]['target'] + + mmd_e_bone_name = bone_tools.get_mmd_english_equivalent_bone_name(target_bone_name) + source_bone_name = bone_tools.get_armature_bone_name_by_mmd_english_bone_name(source_arm,mmd_e_bone_name) + + active_object.retargeting_context.mappings[index]['source'] = source_bone_name + +@register_wrap +class ART_AutoFixBoneMapping(bpy.types.Operator): + """Autofix Bone Mapping""" + bl_idname = "ffxiv_mmd.art_autofix_bone_mapping" + bl_label = "Fixes mappings and removes bones that do not exist" + bl_options = {'REGISTER', 'UNDO'} + + def execute(self, context): + + if is_addon_installed(): + active_object = context.active_object + # THERE IS A DIFFERENCE BETWEEN active_object.retargeting_context and active_object.get('retargeting_context') + rtc = active_object.get('retargeting_context') + + source_arm = rtc.get('source') + target_arm = rtc.get('target') + + if is_source_and_target_mapped(active_object): + + get_mapping_target_bones() + + + armatures = [source_arm, target_arm] + + for armature in armatures: + + for bone in armature.pose.bones: + print (bone.name) + + #get all bones, if equivalent bone exists on armature + + + #if equivalent bone exists on armature, map it + + #if equivalent bone exists does not exist on armature, remove it + + + #garbage cleanup for when both the source mapping and target mapping don't exist + + + + + return {'FINISHED'} +####################### DEREK FINISHED EVERYTHING UP FROM HERE################################################ @register_wrap class ART_AddBoneMapping(bpy.types.Operator): @@ -251,15 +314,17 @@ def execute(self, context): elif self.bone_group =='all_verbatim': for target_bone in target_arm.pose.bones: - source_bone = None - source_bone = source_arm.pose.bones.get(target_bone.name) + if not(target_bone.name.startswith('_dummy_') or target_bone.name.startswith('_shadow_')): + source_bone = None + + source_bone = source_arm.pose.bones.get(target_bone.name) - if not(source_bone): - source_bone = bone_tools.get_equivalent_bone_from_armature(target_arm,target_bone,source_arm) + if not(source_bone): + source_bone = bone_tools.get_equivalent_bone_from_armature(target_arm,target_bone,source_arm) - if source_bone and target_bone: - add_bone_mapping(target_arm, source_bone,target_bone) + if source_bone and target_bone: + add_bone_mapping(target_arm, source_bone,target_bone) else: target_bone_list = get_mapping_target_bones(self.bone_group,target_arm) @@ -491,6 +556,7 @@ def execute(self, context): return {'FINISHED'} + def select_pose_bones_by_index(context,armature_type): @@ -549,6 +615,7 @@ def select_pose_bones_by_index(context,armature_type): bpy.app.handlers.depsgraph_update_post.append(stored_handler) + @register_wrap class ART_SelectBoneInMapping(bpy.types.Operator): """Select the bone""" @@ -569,4 +636,283 @@ def execute(self, context): if is_source_and_target_mapped(active_object): select_pose_bones_by_index(context,self.armature_type) - return {'FINISHED'} \ No newline at end of file + return {'FINISHED'} + + +@register_wrap +class ART_Adjust_Kaito_Bone_Angle(bpy.types.Operator): + """Select the bone""" + bl_idname = "ffxiv_mmd.adjust_kaito_bone_angle" + bl_label = "" + bl_options = {'REGISTER', 'UNDO'} + + #bone_name = bpy.props.StringProperty(name="bone_name", update=None, get=None, set=None) + #armature_type = bpy.props.StringProperty(name="bone_name", update=None, get=None, set=None) + + def execute(self, context): + + if is_addon_installed(): + active_object = context.active_object + # THERE IS A DIFFERENCE BETWEEN active_object.retargeting_context and active_object.get('retargeting_context') + rtc = active_object.get('retargeting_context') + + if is_source_and_target_mapped(active_object): + + # Find and store the handle_edit_change function + stored_handler = None + for handler in bpy.app.handlers.depsgraph_update_post: + if '