Create centralized method for identifying bones

- also fixes an issue where VRM bones would never be identified due to the names having "_" in them.
This commit is contained in:
989onan
2025-03-31 18:28:04 -04:00
parent 08f37d3202
commit feb2f5ac85
3 changed files with 52 additions and 36 deletions
+14
View File
@@ -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 ProgressTracker:
"""Universal progress tracking for Avatar Toolkit operations"""
@@ -412,6 +413,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] = []
+28 -18
View File
@@ -1,8 +1,8 @@
# 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
bone_names = {
# Right side bones
@@ -254,26 +254,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
@@ -354,3 +354,13 @@ resonite_translations = {
'thumb_2_r': "thumb2.R",
'thumb_3_r': "thumb3.R"
}
# 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
+10 -18
View File
@@ -3,14 +3,15 @@ import bpy
import bpy_extras
from numpy import double
from typing import Set, Dict
import re
from .common import get_active_armature, simplify_bonename, validate_armature, 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
import re
from .resonite_loader import resonite_animx, resonite_types
import os
@@ -64,30 +65,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("<noik>"), 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 "<noik>" tags
bone.name = re.compile(re.escape("<noik>"), 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: