diff --git a/core/common.py b/core/common.py index 452760c..62dc51f 100644 --- a/core/common.py +++ b/core/common.py @@ -18,6 +18,7 @@ from bpy.utils import register_class from ..core.logging_setup import logger from ..core.translations import t from ..core.dictionaries import bone_names +from .dictionaries import reverse_bone_lookup, bone_names class SceneMatClass(PropertyGroup): mat: PointerProperty(type=Material) @@ -386,6 +387,19 @@ def simplify_bonename(name: str) -> str: """Simplify bone name by removing spaces, underscores, dots and converting to lowercase""" return name.lower().translate(dict.fromkeys(map(ord, u" _."))) + +def identify_bones(arm_data: bpy.types.Armature, context: bpy.types.Context) -> Dict[str,str]: + """Identify bone names in an armature based on our reverse dictionary, so there is no confusion to what a bone is. + Essentially makes a dictionary of keys from dictionaries.bone_names like "hips", and the corosponding value is the bone that can be mapped to that key.""" + returned: Dict[str,str] = {} + for bone in arm_data.bones: + + simplified_name = simplify_bonename(bone.name) + + if simplified_name in reverse_bone_lookup: + returned[reverse_bone_lookup[simplified_name]] = bone.name + return returned + def duplicate_bone_chain(bones: List[EditBone]) -> List[EditBone]: """Duplicate a chain of bones while preserving hierarchy""" new_bones: List[EditBone] = [] diff --git a/core/dictionaries.py b/core/dictionaries.py index d3f8df5..c5525ec 100644 --- a/core/dictionaries.py +++ b/core/dictionaries.py @@ -1,9 +1,12 @@ # GPL Licence - # Bone names from https://github.com/triazo/immersive_scaler/ -# Note from @989onan: Please make sure to make your names are lowercase in this array. I banged my head metaphorically till I figured that out... +# Note from @989onan: Please make sure to make your names are lowercase in this array, or it will never find a match. I banged my head metaphorically till I figured that out... +# Note2: Remove all "_", ".", and " " (space) from your values array or it will also not ever find a match!!!! # Taken from Tuxedo/Cats + +from .common import simplify_bonename + bone_names = { # Right side bones "right_shoulder": [ @@ -254,26 +257,26 @@ bone_names = { # Add VRM bone name variations bone_names.update({ - 'hips': bone_names['hips'] + ['j_bip_c_hips', 'j_hips', 'vrm_hips'], - 'spine': bone_names['spine'] + ['j_bip_c_spine', 'j_spine', 'vrm_spine'], - 'chest': bone_names['chest'] + ['j_bip_c_chest', 'j_chest', 'vrm_chest'], - 'upper_chest': bone_names['upper_chest'] + ['j_bip_c_upper_chest', 'j_upper_chest', 'vrm_upperchest'], - 'neck': bone_names['neck'] + ['j_bip_c_neck', 'j_neck', 'vrm_neck'], - 'head': bone_names['head'] + ['j_bip_c_head', 'j_head', 'vrm_head'], + 'hips': bone_names['hips'] + ['jbipchips', 'jhips', 'vrmhips'], + 'spine': bone_names['spine'] + ['jbipcspine', 'jspine', 'vrmspine'], + 'chest': bone_names['chest'] + ['jbipcchest', 'jchest', 'vrmchest'], + 'upper_chest': bone_names['upperchest'] + ['jbipcupperchest', 'jupperchest', 'vrmupperchest'], + 'neck': bone_names['neck'] + ['jbipcneck', 'jneck', 'vrmneck'], + 'head': bone_names['head'] + ['jbipchead', 'jhead', 'vrmhead'], # VRM specific finger naming - 'thumb_0_l': bone_names['thumb_0_l'] + ['thumb_metacarpal_l', 'j_thumb1_l'], - 'index_0_l': bone_names['index_0_l'] + ['index_metacarpal_l', 'j_index1_l'], - 'middle_0_l': bone_names['middle_0_l'] + ['middle_metacarpal_l', 'j_middle1_l'], - 'ring_0_l': bone_names['ring_0_l'] + ['ring_metacarpal_l', 'j_ring1_l'], - 'pinkie_0_l': bone_names['pinkie_0_l'] + ['little_metacarpal_l', 'j_little1_l'], + 'thumb_0_l': bone_names['thumb_0_l'] + ['thumbmetacarpall', 'jthumb1l'], + 'index_0_l': bone_names['index_0_l'] + ['indexmetacarpall', 'jindex1l'], + 'middle_0_l': bone_names['middle_0_l'] + ['middlemetacarpall', 'jmiddle1l'], + 'ring_0_l': bone_names['ring_0_l'] + ['ringmetacarpall', 'jring1l'], + 'pinkie_0_l': bone_names['pinkie_0_l'] + ['littlemetacarpall', 'jlittle1l'], # Mirror for right side - 'thumb_0_r': bone_names['thumb_0_r'] + ['thumb_metacarpal_r', 'j_thumb1_r'], - 'index_0_r': bone_names['index_0_r'] + ['index_metacarpal_r', 'j_index1_r'], - 'middle_0_r': bone_names['middle_0_r'] + ['middle_metacarpal_r', 'j_middle1_r'], - 'ring_0_r': bone_names['ring_0_r'] + ['ring_metacarpal_r', 'j_ring1_r'], - 'pinkie_0_r': bone_names['pinkie_0_r'] + ['little_metacarpal_r', 'j_little1_r'] + 'thumb_0_r': bone_names['thumb_0_r'] + ['thumbmetacarpalr', 'jthumb1r'], + 'index_0_r': bone_names['index_0_r'] + ['indexmetacarpalr', 'jindex1r'], + 'middle_0_r': bone_names['middle_0_r'] + ['middlemetacarpalr', 'jmiddle1r'], + 'ring_0_r': bone_names['ring_0_r'] + ['ringmetacarpalr', 'jring1r'], + 'pinkie_0_r': bone_names['pinkie_0_r'] + ['littlemetacarpalr', 'jlittle1r'] }) # array taken from cats @@ -355,6 +358,8 @@ resonite_translations = { 'thumb_3_r': "thumb3.R" } + + standard_bones = { # Core Structure 'hips': 'Hips', @@ -940,4 +945,16 @@ for category, mappings in non_standard_mappings.items(): if category in bone_names: bone_names[category].extend(mappings) else: - bone_names[category] = mappings \ No newline at end of file + bone_names[category] = mappings + + +# Since data set is very poisoned by bone names that aren't simplified (And as such will not map properly using the function) we will just force convert them to the proper format at the end here. - @989onan +for standard, mappings in bone_names: + for i in len(mappings): + bone_names[standard][i] = simplify_bonename(mappings[i]) + +# Create reverse lookup dictionary (conversion/translation) +reverse_bone_lookup = {} +for preferred_name, name_list in bone_names.items(): + for name in name_list: + reverse_bone_lookup[name] = preferred_name diff --git a/core/resonite_utils.py b/core/resonite_utils.py index 998e7ff..e5a210b 100644 --- a/core/resonite_utils.py +++ b/core/resonite_utils.py @@ -3,15 +3,16 @@ import bpy import bpy_extras from numpy import double from typing import Set, Dict +import re -from .common import get_active_armature, simplify_bonename, ProgressTracker +from .common import get_active_armature, simplify_bonename, validate_armature, ProgressTracker, identify_bones from bpy.types import Context, Operator from ..core.translations import t from ..core.dictionaries import bone_names, resonite_translations from ..core.logging_setup import logger from ..core.armature_validation import validate_armature -import re + from .resonite_loader import resonite_animx, resonite_types import os @@ -65,30 +66,21 @@ class AvatarToolkit_OT_ConvertResonite(Operator): untranslated_bones: Set[str] = set() simplified_names: Dict[str, str] = {} - # Create reverse lookup dictionary - reverse_bone_lookup = {} - for preferred_name, name_list in bone_names.items(): - for name in name_list: - reverse_bone_lookup[name] = preferred_name - try: context.view_layer.objects.active = armature bpy.ops.object.mode_set(mode='EDIT') bpy.ops.object.mode_set(mode='OBJECT') - + arm_data: bpy.types.Armature = armature.data # Cache simplified bone names - for bone in armature.data.bones: - simplified_names[bone.name] = simplify_bonename(bone.name) + for bone in arm_data.bones: + bone.name = re.compile(re.escape(""), re.IGNORECASE).sub("", bone.name) - total_bones = len(armature.data.bones) + total_bones = len(arm_data.bones) with ProgressTracker(context, total_bones, t("Tools.convert_resonite.operation")) as progress: - for bone in armature.data.bones: - # Remove any existing "" tags - bone.name = re.compile(re.escape(""), re.IGNORECASE).sub("", bone.name) - simplified_name = simplified_names[bone.name] + for key_simple,bone_name in identify_bones(arm_data,context).items(): - if simplified_name in reverse_bone_lookup and reverse_bone_lookup[simplified_name] in resonite_translations: - new_name = resonite_translations[reverse_bone_lookup[simplified_name]] + if key_simple in resonite_translations: + new_name = resonite_translations[key_simple] logger.debug(f"Translating bone: {bone.name} -> {new_name}") bone.name = new_name else: