Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 929cadd596 | |||
| 15ce911256 | |||
| 7b58f25913 | |||
| d25543d95b | |||
| ba9a7a8af3 | |||
| 408d3f24f7 | |||
| bd33efe7ae | |||
| e5e09e2cf3 | |||
| 8c2c52f882 | |||
| 6f5e7a394d | |||
| 6eb253be17 | |||
| 5276aa0fe0 | |||
| c830938dce | |||
| 60ba1b363f | |||
| e3052d867d | |||
| 08082501c9 | |||
| a8482a87f3 |
@@ -3,7 +3,7 @@
|
|||||||
schema_version = "1.0.0"
|
schema_version = "1.0.0"
|
||||||
|
|
||||||
id = "avatar_toolkit"
|
id = "avatar_toolkit"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
name = "Avatar Toolkit"
|
name = "Avatar Toolkit"
|
||||||
tagline = "A modern tool for importing and optimizing models for VRChat, Resonite, and other similar games."
|
tagline = "A modern tool for importing and optimizing models for VRChat, Resonite, and other similar games."
|
||||||
maintainer = "Team NekoNeo"
|
maintainer = "Team NekoNeo"
|
||||||
|
|||||||
+215
-21
@@ -10,7 +10,8 @@ from ..core.dictionaries import (
|
|||||||
bone_hierarchy,
|
bone_hierarchy,
|
||||||
finger_hierarchy,
|
finger_hierarchy,
|
||||||
acceptable_bone_hierarchy,
|
acceptable_bone_hierarchy,
|
||||||
acceptable_bone_names
|
acceptable_bone_names,
|
||||||
|
simplify_bonename
|
||||||
)
|
)
|
||||||
from ..core.logging_setup import logger
|
from ..core.logging_setup import logger
|
||||||
|
|
||||||
@@ -104,17 +105,41 @@ def validate_armature(armature: Object, detailed_messages: bool = False) -> Unio
|
|||||||
|
|
||||||
# Non-standard bones check
|
# Non-standard bones check
|
||||||
non_standard_bones = []
|
non_standard_bones = []
|
||||||
required_patterns = [
|
|
||||||
'Hips', 'Spine', 'Chest', 'Neck', 'Head',
|
# Bones to ignore
|
||||||
'Upper', 'Lower', 'Hand', 'Foot', 'Toe',
|
ignore_patterns = [
|
||||||
'Thumb', 'Index', 'Middle', 'Ring', 'Pinky',
|
'tail', 'skirt', 'dress', 'hair', 'ribbon', 'bow', 'hat', 'cap',
|
||||||
'Eye'
|
'butt', 'breast', 'boob', 'chest_', 'belly', 'stomach',
|
||||||
|
'wing', 'fin', 'horn', 'ear_', 'accessory', 'extra',
|
||||||
|
'cloth', 'fabric', 'cape', 'coat', 'jacket', 'shirt',
|
||||||
|
'pants', 'shoe', 'boot', 'sock', 'glove', 'mitten',
|
||||||
|
'belt', 'strap', 'buckle', 'button', 'zipper',
|
||||||
|
'jewel', 'gem', 'ring', 'necklace', 'earring',
|
||||||
|
'flower', 'leaf', 'feather', 'fur', 'scale',
|
||||||
|
'bangs', 'sideburn', 'bell', 'leash', 'ears', 'chain',
|
||||||
|
'headband', 'necklace', 'necktie', 'strapNeck', 'ring',
|
||||||
|
'pin', 'hair',
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Create normalized lookup sets for faster comparison
|
||||||
|
normalized_standard_bones = {simplify_bonename(name) for name in standard_bones.values()}
|
||||||
|
normalized_acceptable_bones = set()
|
||||||
|
for names in acceptable_bone_names.values():
|
||||||
|
normalized_acceptable_bones.update(simplify_bonename(name) for name in names)
|
||||||
|
|
||||||
for bone_name in found_bones:
|
for bone_name in found_bones:
|
||||||
if any(pattern in bone_name for pattern in required_patterns):
|
# Normalize bone name for comparison
|
||||||
is_standard = bone_name in standard_bones.values()
|
normalized_bone_name = simplify_bonename(bone_name)
|
||||||
is_acceptable_bone = any(bone_name in names for names in acceptable_bone_names.values())
|
|
||||||
|
# Check if bone should be ignored (accessory bone)
|
||||||
|
is_ignored = any(pattern in normalized_bone_name for pattern in ignore_patterns)
|
||||||
|
|
||||||
|
if not is_ignored:
|
||||||
|
# Check if bone is in standard or acceptable lists
|
||||||
|
is_standard = normalized_bone_name in normalized_standard_bones
|
||||||
|
is_acceptable_bone = normalized_bone_name in normalized_acceptable_bones
|
||||||
|
|
||||||
if not (is_standard or is_acceptable_bone):
|
if not (is_standard or is_acceptable_bone):
|
||||||
non_standard_bones.append(bone_name)
|
non_standard_bones.append(bone_name)
|
||||||
|
|
||||||
@@ -186,31 +211,188 @@ def validate_bone_hierarchy(bones: Dict[str, Bone], parent_name: str, child_name
|
|||||||
return False
|
return False
|
||||||
return bones[child_name].parent == bones[parent_name]
|
return bones[child_name].parent == bones[parent_name]
|
||||||
|
|
||||||
|
def extract_bone_side_info(bone_name: str) -> Tuple[str, str]:
|
||||||
|
"""
|
||||||
|
Extract base bone name and side indicator from a bone name.
|
||||||
|
Returns (base_name, side) where side is 'L', 'R', or ''
|
||||||
|
"""
|
||||||
|
normalized = simplify_bonename(bone_name)
|
||||||
|
original = bone_name
|
||||||
|
|
||||||
|
# Common left/right patterns to check
|
||||||
|
left_patterns = [
|
||||||
|
'left', 'l', 'lft', 'lt',
|
||||||
|
'.l', '_l', '-l', ' l',
|
||||||
|
'左', 'ひだり'
|
||||||
|
]
|
||||||
|
|
||||||
|
right_patterns = [
|
||||||
|
'right', 'r', 'rgt', 'rt',
|
||||||
|
'.r', '_r', '-r', ' r',
|
||||||
|
'右', 'みぎ'
|
||||||
|
]
|
||||||
|
|
||||||
|
# Check for left patterns
|
||||||
|
for pattern in left_patterns:
|
||||||
|
pattern_norm = simplify_bonename(pattern)
|
||||||
|
if normalized.startswith(pattern_norm):
|
||||||
|
base = normalized[len(pattern_norm):]
|
||||||
|
if base: # Make sure there's something left
|
||||||
|
return base, 'L'
|
||||||
|
elif normalized.endswith(pattern_norm):
|
||||||
|
base = normalized[:-len(pattern_norm)]
|
||||||
|
if base:
|
||||||
|
return base, 'L'
|
||||||
|
elif pattern_norm in normalized:
|
||||||
|
# Handle cases like ArmLeft
|
||||||
|
parts = normalized.split(pattern_norm)
|
||||||
|
if len(parts) == 2:
|
||||||
|
base = parts[0] + parts[1]
|
||||||
|
if base:
|
||||||
|
return base, 'L'
|
||||||
|
|
||||||
|
# Check for right patterns
|
||||||
|
for pattern in right_patterns:
|
||||||
|
pattern_norm = simplify_bonename(pattern)
|
||||||
|
if normalized.startswith(pattern_norm):
|
||||||
|
base = normalized[len(pattern_norm):]
|
||||||
|
if base:
|
||||||
|
return base, 'R'
|
||||||
|
elif normalized.endswith(pattern_norm):
|
||||||
|
base = normalized[:-len(pattern_norm)]
|
||||||
|
if base:
|
||||||
|
return base, 'R'
|
||||||
|
elif pattern_norm in normalized:
|
||||||
|
parts = normalized.split(pattern_norm)
|
||||||
|
if len(parts) == 2:
|
||||||
|
base = parts[0] + parts[1]
|
||||||
|
if base:
|
||||||
|
return base, 'R'
|
||||||
|
|
||||||
|
return normalized, ''
|
||||||
|
|
||||||
|
def find_symmetric_bone_pairs(bones: Dict[str, Bone]) -> Dict[str, Tuple[List[str], List[str]]]:
|
||||||
|
"""
|
||||||
|
Automatically find symmetric bone pairs in the armature.
|
||||||
|
Returns dict mapping base_name to (left_bones, right_bones)
|
||||||
|
"""
|
||||||
|
bone_groups = {}
|
||||||
|
|
||||||
|
for bone_name in bones.keys():
|
||||||
|
base, side = extract_bone_side_info(bone_name)
|
||||||
|
|
||||||
|
if side:
|
||||||
|
if base not in bone_groups:
|
||||||
|
bone_groups[base] = {'L': [], 'R': []}
|
||||||
|
bone_groups[base][side].append(bone_name)
|
||||||
|
|
||||||
|
symmetric_pairs = {}
|
||||||
|
for base, sides in bone_groups.items():
|
||||||
|
if sides['L'] and sides['R']:
|
||||||
|
symmetric_pairs[base] = (sides['L'], sides['R'])
|
||||||
|
|
||||||
|
return symmetric_pairs
|
||||||
|
|
||||||
|
def validate_armature_symmetry(armature: Object) -> Tuple[bool, List[str]]:
|
||||||
|
"""
|
||||||
|
Comprehensive symmetry validation that provides detailed feedback
|
||||||
|
"""
|
||||||
|
if not armature or armature.type != 'ARMATURE':
|
||||||
|
return False, ["Invalid armature"]
|
||||||
|
|
||||||
|
bones = {bone.name: bone for bone in armature.data.bones}
|
||||||
|
symmetric_pairs = find_symmetric_bone_pairs(bones)
|
||||||
|
|
||||||
|
messages = []
|
||||||
|
is_symmetric = True
|
||||||
|
|
||||||
|
if symmetric_pairs:
|
||||||
|
messages.append("Found symmetric bone pairs:")
|
||||||
|
for base, (left_bones, right_bones) in symmetric_pairs.items():
|
||||||
|
left_count = len(left_bones)
|
||||||
|
right_count = len(right_bones)
|
||||||
|
|
||||||
|
if left_count == right_count:
|
||||||
|
messages.append(f" ✓ {base}: {left_count} bones on each side")
|
||||||
|
for l_bone, r_bone in zip(sorted(left_bones), sorted(right_bones)):
|
||||||
|
messages.append(f" {l_bone} ↔ {r_bone}")
|
||||||
|
else:
|
||||||
|
is_symmetric = False
|
||||||
|
messages.append(f" ✗ {base}: {left_count} left, {right_count} right bones")
|
||||||
|
messages.append(f" Left: {', '.join(sorted(left_bones))}")
|
||||||
|
messages.append(f" Right: {', '.join(sorted(right_bones))}")
|
||||||
|
else:
|
||||||
|
messages.append("No symmetric bone pairs detected")
|
||||||
|
is_symmetric = False
|
||||||
|
|
||||||
|
return is_symmetric, messages
|
||||||
|
|
||||||
def validate_symmetry(bones: Dict[str, Bone], base: str, left: str, right: str) -> bool:
|
def validate_symmetry(bones: Dict[str, Bone], base: str, left: str, right: str) -> bool:
|
||||||
"""Validate if matching left and right bones exist for a given base bone name"""
|
"""Validate if matching left and right bones exist for a given base bone name"""
|
||||||
# Extract left and right bone names from both hierarchies
|
# First try the new intelligent detection
|
||||||
|
symmetric_pairs = find_symmetric_bone_pairs(bones)
|
||||||
|
|
||||||
|
# Look for bones that match the requested base type
|
||||||
|
matching_left_bones = []
|
||||||
|
matching_right_bones = []
|
||||||
|
|
||||||
|
# Check each detected symmetric pair
|
||||||
|
for pair_base, (left_bones, right_bones) in symmetric_pairs.items():
|
||||||
|
if base.lower() in pair_base.lower() or pair_base.lower() in base.lower():
|
||||||
|
matching_left_bones.extend(left_bones)
|
||||||
|
matching_right_bones.extend(right_bones)
|
||||||
|
|
||||||
|
if matching_left_bones or matching_right_bones:
|
||||||
|
left_bases = {}
|
||||||
|
right_bases = {}
|
||||||
|
|
||||||
|
for bone_name in matching_left_bones:
|
||||||
|
bone_base, side = extract_bone_side_info(bone_name)
|
||||||
|
if bone_base not in left_bases:
|
||||||
|
left_bases[bone_base] = []
|
||||||
|
left_bases[bone_base].append(bone_name)
|
||||||
|
|
||||||
|
for bone_name in matching_right_bones:
|
||||||
|
bone_base, side = extract_bone_side_info(bone_name)
|
||||||
|
if bone_base not in right_bases:
|
||||||
|
right_bases[bone_base] = []
|
||||||
|
right_bases[bone_base].append(bone_name)
|
||||||
|
|
||||||
|
all_bases = set(left_bases.keys()) | set(right_bases.keys())
|
||||||
|
for bone_base in all_bases:
|
||||||
|
left_count = len(left_bases.get(bone_base, []))
|
||||||
|
right_count = len(right_bases.get(bone_base, []))
|
||||||
|
if left_count != right_count:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return len(all_bases) > 0
|
||||||
|
|
||||||
|
# Fallback to original dictionary-based method
|
||||||
left_bone_names = set()
|
left_bone_names = set()
|
||||||
right_bone_names = set()
|
right_bone_names = set()
|
||||||
|
|
||||||
|
# Normalize bone names in the bones dict for comparison
|
||||||
|
normalized_bones = {simplify_bonename(name): name for name in bones.keys()}
|
||||||
|
|
||||||
# Add standard bones
|
# Add standard bones
|
||||||
for key, value in standard_bones.items():
|
for key, value in standard_bones.items():
|
||||||
if base in key.lower():
|
if base in key.lower():
|
||||||
if '_l' in key.lower():
|
if '_l' in key.lower():
|
||||||
left_bone_names.add(value)
|
left_bone_names.add(simplify_bonename(value))
|
||||||
elif '_r' in key.lower():
|
elif '_r' in key.lower():
|
||||||
right_bone_names.add(value)
|
right_bone_names.add(simplify_bonename(value))
|
||||||
|
|
||||||
# Add acceptable bones
|
# Add acceptable bones
|
||||||
for key, names in acceptable_bone_names.items():
|
for key, names in acceptable_bone_names.items():
|
||||||
if base in key.lower():
|
if base in key.lower():
|
||||||
if '_l' in key.lower():
|
if '_l' in key.lower():
|
||||||
left_bone_names.update(names)
|
left_bone_names.update(simplify_bonename(name) for name in names)
|
||||||
elif '_r' in key.lower():
|
elif '_r' in key.lower():
|
||||||
right_bone_names.update(names)
|
right_bone_names.update(simplify_bonename(name) for name in names)
|
||||||
|
|
||||||
# Check if at least one pair exists and matches
|
# Check if at least one pair exists and matches
|
||||||
left_exists = any(name in bones for name in left_bone_names)
|
left_exists = any(name in normalized_bones for name in left_bone_names)
|
||||||
right_exists = any(name in bones for name in right_bone_names)
|
right_exists = any(name in normalized_bones for name in right_bone_names)
|
||||||
|
|
||||||
return left_exists == right_exists
|
return left_exists == right_exists
|
||||||
|
|
||||||
@@ -224,22 +406,34 @@ def validate_finger_chain(bones: Dict[str, Bone], chain: Tuple[str, ...]) -> boo
|
|||||||
def check_acceptable_standards(bones: Dict[str, Bone]) -> bool:
|
def check_acceptable_standards(bones: Dict[str, Bone]) -> bool:
|
||||||
"""Check if armature matches acceptable non-standard hierarchy"""
|
"""Check if armature matches acceptable non-standard hierarchy"""
|
||||||
logger.debug("Checking for acceptable standards")
|
logger.debug("Checking for acceptable standards")
|
||||||
|
|
||||||
|
# Create normalized lookup for existing bones
|
||||||
|
normalized_bones = {simplify_bonename(name): name for name in bones.keys()}
|
||||||
|
|
||||||
# Check if bones exist in acceptable list
|
# Check if bones exist in acceptable list
|
||||||
for bone_category, acceptable_names in acceptable_bone_names.items():
|
for bone_category, acceptable_names in acceptable_bone_names.items():
|
||||||
found = False
|
found = False
|
||||||
for name in acceptable_names:
|
for name in acceptable_names:
|
||||||
if name in bones:
|
normalized_name = simplify_bonename(name)
|
||||||
|
if normalized_name in normalized_bones:
|
||||||
found = True
|
found = True
|
||||||
break
|
break
|
||||||
if not found:
|
if not found:
|
||||||
logger.debug(f"Missing acceptable bone for category: {bone_category}")
|
logger.debug(f"Missing acceptable bone for category: {bone_category}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Validate acceptable hierarchy
|
# Validate acceptable hierarchy using normalized names
|
||||||
for parent, child in acceptable_bone_hierarchy:
|
for parent, child in acceptable_bone_hierarchy:
|
||||||
if parent in bones and child in bones:
|
parent_normalized = simplify_bonename(parent)
|
||||||
if not validate_bone_hierarchy(bones, parent, child):
|
child_normalized = simplify_bonename(child)
|
||||||
logger.debug(f"Invalid acceptable hierarchy: {parent} -> {child}")
|
|
||||||
|
# Find actual bone names from normalized names
|
||||||
|
actual_parent = normalized_bones.get(parent_normalized)
|
||||||
|
actual_child = normalized_bones.get(child_normalized)
|
||||||
|
|
||||||
|
if actual_parent and actual_child:
|
||||||
|
if not validate_bone_hierarchy(bones, actual_parent, actual_child):
|
||||||
|
logger.debug(f"Invalid acceptable hierarchy: {actual_parent} -> {actual_child}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
logger.debug("Armature meets acceptable standards")
|
logger.debug("Armature meets acceptable standards")
|
||||||
|
|||||||
@@ -653,6 +653,9 @@ def store_breaking_settings_armature(armature: bpy.types.Object) -> ArmatureData
|
|||||||
return (armature_data.use_mirror_x, armature.pose.use_mirror_x)
|
return (armature_data.use_mirror_x, armature.pose.use_mirror_x)
|
||||||
|
|
||||||
def restore_breaking_settings_armature(armature: bpy.types.Object, data: ArmatureData) -> None:
|
def restore_breaking_settings_armature(armature: bpy.types.Object, data: ArmatureData) -> None:
|
||||||
|
# Check if armature object is still valid (not removed)
|
||||||
|
if not armature or armature.name not in bpy.data.objects:
|
||||||
|
return
|
||||||
armature_data: bpy.types.Armature = armature.data
|
armature_data: bpy.types.Armature = armature.data
|
||||||
armature_data.use_mirror_x, armature.pose.use_mirror_x = data
|
armature_data.use_mirror_x, armature.pose.use_mirror_x = data
|
||||||
|
|
||||||
|
|||||||
+190
-134
@@ -372,60 +372,62 @@ standard_bones = {
|
|||||||
'head': 'Head',
|
'head': 'Head',
|
||||||
|
|
||||||
# Arms
|
# Arms
|
||||||
'left_arm': 'UpperArm.L',
|
'left_shoulder': 'Shoulder_L',
|
||||||
'left_elbow': 'LowerArm.L',
|
'left_arm': 'UpperArm_L',
|
||||||
'left_wrist': 'Hand.L',
|
'left_elbow': 'LowerArm_L',
|
||||||
'right_arm': 'UpperArm.R',
|
'left_wrist': 'Hand_L',
|
||||||
'right_elbow': 'LowerArm.R',
|
'right_shoulder': 'Shoulder_R',
|
||||||
'right_wrist': 'Hand.R',
|
'right_arm': 'UpperArm_R',
|
||||||
|
'right_elbow': 'LowerArm_R',
|
||||||
|
'right_wrist': 'Hand_R',
|
||||||
|
|
||||||
# Legs
|
# Legs
|
||||||
'left_leg': 'UpperLeg.L',
|
'left_leg': 'UpperLeg_L',
|
||||||
'left_knee': 'LowerLeg.L',
|
'left_knee': 'LowerLeg_L',
|
||||||
'left_ankle': 'Foot.L',
|
'left_ankle': 'Foot_L',
|
||||||
'left_toe': 'Toes.L',
|
'left_toe': 'Toe_L',
|
||||||
'right_leg': 'UpperLeg.R',
|
'right_leg': 'UpperLeg_R',
|
||||||
'right_knee': 'LowerLeg.R',
|
'right_knee': 'LowerLeg_R',
|
||||||
'right_ankle': 'Foot.R',
|
'right_ankle': 'Foot_R',
|
||||||
'right_toe': 'Toes.R',
|
'right_toe': 'Toe_R',
|
||||||
|
|
||||||
# Fingers Left
|
# Fingers Left
|
||||||
'thumb_1_l': 'Thumb1.L',
|
'thumb_1_l': 'Thumb_L',
|
||||||
'thumb_2_l': 'Thumb2.L',
|
'thumb_2_l': 'Thumb_L.001',
|
||||||
'thumb_3_l': 'Thumb3.L',
|
'thumb_3_l': 'Thumb_L.002',
|
||||||
'index_1_l': 'Index1.L',
|
'index_1_l': 'Index_L',
|
||||||
'index_2_l': 'Index2.L',
|
'index_2_l': 'Index_L.001',
|
||||||
'index_3_l': 'Index3.L',
|
'index_3_l': 'Index_L.002',
|
||||||
'middle_1_l': 'Middle1.L',
|
'middle_1_l': 'Middle_L',
|
||||||
'middle_2_l': 'Middle2.L',
|
'middle_2_l': 'Middle_L.001',
|
||||||
'middle_3_l': 'Middle3.L',
|
'middle_3_l': 'Middle_L.002',
|
||||||
'ring_1_l': 'Ring1.L',
|
'ring_1_l': 'Ring_L',
|
||||||
'ring_2_l': 'Ring2.L',
|
'ring_2_l': 'Ring_L.001',
|
||||||
'ring_3_l': 'Ring3.L',
|
'ring_3_l': 'Ring_L.002',
|
||||||
'pinkie_1_l': 'Pinky1.L',
|
'pinkie_1_l': 'Pinky_L',
|
||||||
'pinkie_2_l': 'Pinky2.L',
|
'pinkie_2_l': 'Pinky_L.001',
|
||||||
'pinkie_3_l': 'Pinky3.L',
|
'pinkie_3_l': 'Pinky_L.002',
|
||||||
|
|
||||||
# Fingers Right
|
# Fingers Right
|
||||||
'thumb_1_r': 'Thumb1.R',
|
'thumb_1_r': 'Thumb_R',
|
||||||
'thumb_2_r': 'Thumb2.R',
|
'thumb_2_r': 'Thumb_R.001',
|
||||||
'thumb_3_r': 'Thumb3.R',
|
'thumb_3_r': 'Thumb_R.002',
|
||||||
'index_1_r': 'Index1.R',
|
'index_1_r': 'Index_R',
|
||||||
'index_2_r': 'Index2.R',
|
'index_2_r': 'Index_R.001',
|
||||||
'index_3_r': 'Index3.R',
|
'index_3_r': 'Index_R.002',
|
||||||
'middle_1_r': 'Middle1.R',
|
'middle_1_r': 'Middle_R',
|
||||||
'middle_2_r': 'Middle2.R',
|
'middle_2_r': 'Middle_R.001',
|
||||||
'middle_3_r': 'Middle3.R',
|
'middle_3_r': 'Middle_R.002',
|
||||||
'ring_1_r': 'Ring1.R',
|
'ring_1_r': 'Ring_R',
|
||||||
'ring_2_r': 'Ring2.R',
|
'ring_2_r': 'Ring_R.001',
|
||||||
'ring_3_r': 'Ring3.R',
|
'ring_3_r': 'Ring_R.002',
|
||||||
'pinkie_1_r': 'Pinky1.R',
|
'pinkie_1_r': 'Pinky_R',
|
||||||
'pinkie_2_r': 'Pinky2.R',
|
'pinkie_2_r': 'Pinky_R.001',
|
||||||
'pinkie_3_r': 'Pinky3.R',
|
'pinkie_3_r': 'Pinky_R.002',
|
||||||
|
|
||||||
# Eyes
|
# Eyes
|
||||||
'left_eye': 'Eye.L',
|
'left_eye': 'Eye_L',
|
||||||
'right_eye': 'Eye.R'
|
'right_eye': 'Eye_R'
|
||||||
}
|
}
|
||||||
|
|
||||||
bone_hierarchy = [
|
bone_hierarchy = [
|
||||||
@@ -434,46 +436,48 @@ bone_hierarchy = [
|
|||||||
('Chest', 'Chest.Up'),
|
('Chest', 'Chest.Up'),
|
||||||
('Chest.Up', 'Neck'),
|
('Chest.Up', 'Neck'),
|
||||||
('Neck', 'Head'),
|
('Neck', 'Head'),
|
||||||
('Head', 'Eye.L'),
|
('Head', 'Eye_L'),
|
||||||
('Head', 'Eye.R'),
|
('Head', 'Eye_R'),
|
||||||
|
|
||||||
# Left Arm Chain
|
# Left Arm Chain
|
||||||
('Chest.Up', 'UpperArm.L'),
|
('Chest.Up', 'Shoulder_L'),
|
||||||
('UpperArm.L', 'LowerArm.L'),
|
('Shoulder_L', 'UpperArm_L'),
|
||||||
('LowerArm.L', 'Hand.L'),
|
('UpperArm_L', 'LowerArm_L'),
|
||||||
|
('LowerArm_L', 'Hand_L'),
|
||||||
|
|
||||||
# Right Arm Chain
|
# Right Arm Chain
|
||||||
('Chest.Up', 'UpperArm.R'),
|
('Chest.Up', 'Shoulder_R'),
|
||||||
('UpperArm.R', 'LowerArm.R'),
|
('Shoulder_R', 'UpperArm_R'),
|
||||||
('LowerArm.R', 'Hand.R'),
|
('UpperArm_R', 'LowerArm_R'),
|
||||||
|
('LowerArm_R', 'Hand_R'),
|
||||||
|
|
||||||
# Left Leg Chain
|
# Left Leg Chain
|
||||||
('Hips', 'UpperLeg.L'),
|
('Hips', 'UpperLeg_L'),
|
||||||
('UpperLeg.L', 'LowerLeg.L'),
|
('UpperLeg_L', 'LowerLeg_L'),
|
||||||
('LowerLeg.L', 'Foot.L'),
|
('LowerLeg_L', 'Foot_L'),
|
||||||
('Foot.L', 'Toes.L'),
|
('Foot_L', 'Toe_L'),
|
||||||
|
|
||||||
# Right Leg Chain
|
# Right Leg Chain
|
||||||
('Hips', 'UpperLeg.R'),
|
('Hips', 'UpperLeg_R'),
|
||||||
('UpperLeg.R', 'LowerLeg.R'),
|
('UpperLeg_R', 'LowerLeg_R'),
|
||||||
('LowerLeg.R', 'Foot.R'),
|
('LowerLeg_R', 'Foot_R'),
|
||||||
('Foot.R', 'Toes.R')
|
('Foot_R', 'Toe_R')
|
||||||
]
|
]
|
||||||
|
|
||||||
finger_hierarchy = {
|
finger_hierarchy = {
|
||||||
'left': [
|
'left': [
|
||||||
('Hand.L', 'Thumb1.L', 'Thumb2.L', 'Thumb3.L'),
|
('Hand_L', 'Thumb_L', 'Thumb_L.001', 'Thumb_L.002'),
|
||||||
('Hand.L', 'Index1.L', 'Index2.L', 'Index3.L'),
|
('Hand_L', 'Index_L', 'Index_L.001', 'Index_L.002'),
|
||||||
('Hand.L', 'Middle1.L', 'Middle2.L', 'Middle3.L'),
|
('Hand_L', 'Middle_L', 'Middle_L.001', 'Middle_L.002'),
|
||||||
('Hand.L', 'Ring1.L', 'Ring2.L', 'Ring3.L'),
|
('Hand_L', 'Ring_L', 'Ring_L.001', 'Ring_L.002'),
|
||||||
('Hand.L', 'Pinky1.L', 'Pinky2.L', 'Pinky3.L')
|
('Hand_L', 'Pinky_L', 'Pinky_L.001', 'Pinky_L.002')
|
||||||
],
|
],
|
||||||
'right': [
|
'right': [
|
||||||
('Hand.R', 'Thumb1.R', 'Thumb2.R', 'Thumb3.R'),
|
('Hand_R', 'Thumb_R', 'Thumb_R.001', 'Thumb_R.002'),
|
||||||
('Hand.R', 'Index1.R', 'Index2.R', 'Index3.R'),
|
('Hand_R', 'Index_R', 'Index_R.001', 'Index_R.002'),
|
||||||
('Hand.R', 'Middle1.R', 'Middle2.R', 'Middle3.R'),
|
('Hand_R', 'Middle_R', 'Middle_R.001', 'Middle_R.002'),
|
||||||
('Hand.R', 'Ring1.R', 'Ring2.R', 'Ring3.R'),
|
('Hand_R', 'Ring_R', 'Ring_R.001', 'Ring_R.002'),
|
||||||
('Hand.R', 'Pinky1.R', 'Pinky2.R', 'Pinky3.R')
|
('Hand_R', 'Pinky_R', 'Pinky_R.001', 'Pinky_R.002')
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,6 +510,8 @@ acceptable_bone_hierarchy = [
|
|||||||
('Head', 'Eye_R'),
|
('Head', 'Eye_R'),
|
||||||
('Head', 'LeftEye'),
|
('Head', 'LeftEye'),
|
||||||
('Head', 'RightEye'),
|
('Head', 'RightEye'),
|
||||||
|
('Head', 'Eye.L'),
|
||||||
|
('Head', 'Eye.R'),
|
||||||
|
|
||||||
# Unity humanoid naming
|
# Unity humanoid naming
|
||||||
('Hips', 'Spine'),
|
('Hips', 'Spine'),
|
||||||
@@ -516,6 +522,40 @@ acceptable_bone_hierarchy = [
|
|||||||
('Head', 'LeftEye'),
|
('Head', 'LeftEye'),
|
||||||
('Head', 'RightEye'),
|
('Head', 'RightEye'),
|
||||||
|
|
||||||
|
# Old standard bone hierarchy patterns
|
||||||
|
('Chest.Up', 'UpperArm.L'),
|
||||||
|
('UpperArm.L', 'LowerArm.L'),
|
||||||
|
('LowerArm.L', 'Hand.L'),
|
||||||
|
('Chest.Up', 'UpperArm.R'),
|
||||||
|
('UpperArm.R', 'LowerArm.R'),
|
||||||
|
('LowerArm.R', 'Hand.R'),
|
||||||
|
('Hips', 'UpperLeg.L'),
|
||||||
|
('UpperLeg.L', 'LowerLeg.L'),
|
||||||
|
('LowerLeg.L', 'Foot.L'),
|
||||||
|
('Foot.L', 'Toes.L'),
|
||||||
|
('Hips', 'UpperLeg.R'),
|
||||||
|
('UpperLeg.R', 'LowerLeg.R'),
|
||||||
|
('LowerLeg.R', 'Foot.R'),
|
||||||
|
('Foot.R', 'Toes.R'),
|
||||||
|
|
||||||
|
# New standard bone hierarchy patterns (with shoulders)
|
||||||
|
('Chest.Up', 'Shoulder_L'),
|
||||||
|
('Shoulder_L', 'UpperArm_L'),
|
||||||
|
('UpperArm_L', 'LowerArm_L'),
|
||||||
|
('LowerArm_L', 'Hand_L'),
|
||||||
|
('Chest.Up', 'Shoulder_R'),
|
||||||
|
('Shoulder_R', 'UpperArm_R'),
|
||||||
|
('UpperArm_R', 'LowerArm_R'),
|
||||||
|
('LowerArm_R', 'Hand_R'),
|
||||||
|
('Hips', 'UpperLeg_L'),
|
||||||
|
('UpperLeg_L', 'LowerLeg_L'),
|
||||||
|
('LowerLeg_L', 'Foot_L'),
|
||||||
|
('Foot_L', 'Toe_L'),
|
||||||
|
('Hips', 'UpperLeg_R'),
|
||||||
|
('UpperLeg_R', 'LowerLeg_R'),
|
||||||
|
('LowerLeg_R', 'Foot_R'),
|
||||||
|
('Foot_R', 'Toe_R'),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
acceptable_bone_names = {
|
acceptable_bone_names = {
|
||||||
@@ -523,59 +563,75 @@ acceptable_bone_names = {
|
|||||||
'chest': ['Chest', 'spine1', 'Spine1', 'spine_01', 'SPINE1', 'Spine01'],
|
'chest': ['Chest', 'spine1', 'Spine1', 'spine_01', 'SPINE1', 'Spine01'],
|
||||||
'neck': ['Neck', 'neck_01', 'Neck01'],
|
'neck': ['Neck', 'neck_01', 'Neck01'],
|
||||||
'head': ['Head', 'head_01', 'Head01'],
|
'head': ['Head', 'head_01', 'Head01'],
|
||||||
'eye_l': ['Eye_L', 'LeftEye', 'lefteye', 'eye_left', 'EyeLeft'],
|
'eye_l': ['Eye_L', 'LeftEye', 'lefteye', 'eye_left', 'EyeLeft', 'Eye.L'],
|
||||||
'eye_r': ['Eye_R', 'RightEye', 'righteye', 'eye_right', 'EyeRight'],
|
'eye_r': ['Eye_R', 'RightEye', 'righteye', 'eye_right', 'EyeRight', 'Eye.R'],
|
||||||
|
|
||||||
'shoulder_r': ['Shoulder.R', 'clavicle_r', 'ClavicleRight', 'RightShoulder'],
|
'shoulder_r': ['Shoulder.R', 'clavicle_r', 'ClavicleRight', 'RightShoulder', 'Shoulder_R'],
|
||||||
'arm_r': ['Arm.R', 'upperarm_r', 'UpperArmRight', 'RightArm'],
|
'arm_r': ['Arm.R', 'upperarm_r', 'UpperArmRight', 'RightArm', 'UpperArm.R', 'UpperArm_R'],
|
||||||
'elbow_r': ['Elbow.R', 'lowerarm_r', 'ForearmRight', 'RightForeArm'],
|
'elbow_r': ['Elbow.R', 'lowerarm_r', 'ForearmRight', 'RightForeArm', 'LowerArm.R', 'LowerArm_R'],
|
||||||
'wrist_r': ['Wrist.R', 'hand_r', 'HandRight', 'RightHand'],
|
'wrist_r': ['Wrist.R', 'hand_r', 'HandRight', 'RightHand', 'Hand.R', 'Hand_R'],
|
||||||
'leg_r': ['Leg.R', 'thigh_r', 'ThighRight', 'RightLeg', 'RightUpLeg'],
|
'leg_r': ['Leg.R', 'thigh_r', 'ThighRight', 'RightLeg', 'RightUpLeg', 'UpperLeg.R', 'UpperLeg_R'],
|
||||||
'knee_r': ['Knee.R', 'calf_r', 'CalfRight', 'RightShin', 'RightLowerLeg'],
|
'knee_r': ['Knee.R', 'calf_r', 'CalfRight', 'RightShin', 'RightLowerLeg', 'LowerLeg.R', 'LowerLeg_R'],
|
||||||
'foot_r': ['Foot.R', 'foot_r', 'FootRight', 'RightFoot'],
|
'foot_r': ['Foot.R', 'foot_r', 'FootRight', 'RightFoot', 'Foot_R'],
|
||||||
'toes_r': ['Toes.R', 'ball_r', 'ToeRight', 'RightToeBase'],
|
'toes_r': ['Toes.R', 'ball_r', 'ToeRight', 'RightToeBase', 'Toe_R'],
|
||||||
|
|
||||||
'shoulder_l': ['Shoulder.L', 'clavicle_l', 'ClavicleLeft', 'LeftShoulder'],
|
'shoulder_l': ['Shoulder.L', 'clavicle_l', 'ClavicleLeft', 'LeftShoulder', 'Shoulder_L'],
|
||||||
'arm_l': ['Arm.L', 'upperarm_l', 'UpperArmLeft', 'LeftArm'],
|
'arm_l': ['Arm.L', 'upperarm_l', 'UpperArmLeft', 'LeftArm', 'UpperArm.L', 'UpperArm_L'],
|
||||||
'elbow_l': ['Elbow.L', 'lowerarm_l', 'ForearmLeft', 'LeftForeArm'],
|
'elbow_l': ['Elbow.L', 'lowerarm_l', 'ForearmLeft', 'LeftForeArm', 'LowerArm.L', 'LowerArm_L'],
|
||||||
'wrist_l': ['Wrist.L', 'hand_l', 'HandLeft', 'LeftHand'],
|
'wrist_l': ['Wrist.L', 'hand_l', 'HandLeft', 'LeftHand', 'Hand.L', 'Hand_L'],
|
||||||
'leg_l': ['Leg.L', 'thigh_l', 'ThighLeft', 'LeftLeg', 'LeftUpLeg'],
|
'leg_l': ['Leg.L', 'thigh_l', 'ThighLeft', 'LeftLeg', 'LeftUpLeg', 'UpperLeg.L', 'UpperLeg_L'],
|
||||||
'knee_l': ['Knee.L', 'calf_l', 'CalfLeft', 'LeftShin', 'LeftLowerLeg'],
|
'knee_l': ['Knee.L', 'calf_l', 'CalfLeft', 'LeftShin', 'LeftLowerLeg', 'LowerLeg.L', 'LowerLeg_L'],
|
||||||
'foot_l': ['Foot.L', 'foot_l', 'FootLeft', 'LeftFoot'],
|
'foot_l': ['Foot.L', 'foot_l', 'FootLeft', 'LeftFoot', 'Foot_L'],
|
||||||
'toes_l': ['Toes.L', 'ball_l', 'ToeLeft', 'LeftToeBase'],
|
'toes_l': ['Toes.L', 'ball_l', 'ToeLeft', 'LeftToeBase', 'Toe_L'],
|
||||||
|
|
||||||
# Add finger bones for left hand
|
# Add finger bones for left hand
|
||||||
'thumb_0_l': ['Thumb0_L'],
|
'thumb_0_l': ['Thumb0_L', 'Thumb0.L'],
|
||||||
'thumb_1_l': ['Thumb1_L'],
|
'thumb_1_l': ['Thumb1_L', 'Thumb1.L', 'Thumb_L'],
|
||||||
'thumb_2_l': ['Thumb2_L'],
|
'thumb_2_l': ['Thumb2_L', 'Thumb2.L', 'Thumb_L.001'],
|
||||||
'index_1_l': ['IndexFinger1_L'],
|
'thumb_3_l': ['Thumb3_L', 'Thumb3.L', 'Thumb_L.002'],
|
||||||
'index_2_l': ['IndexFinger2_L'],
|
'index_1_l': ['IndexFinger1_L', 'IndexFinger1.L', 'Index1.L', 'Index_L'],
|
||||||
'index_3_l': ['IndexFinger3_L'],
|
'index_2_l': ['IndexFinger2_L', 'IndexFinger2.L', 'Index2.L', 'Index_L.001'],
|
||||||
'middle_1_l': ['MiddleFinger1_L'],
|
'index_3_l': ['IndexFinger3_L', 'IndexFinger3.L', 'Index3.L', 'Index_L.002'],
|
||||||
'middle_2_l': ['MiddleFinger2_L'],
|
'middle_1_l': ['MiddleFinger1_L', 'MiddleFinger1.L', 'Middle1.L', 'Middle_L'],
|
||||||
'middle_3_l': ['MiddleFinger3_L'],
|
'middle_2_l': ['MiddleFinger2_L', 'MiddleFinger2.L', 'Middle2.L', 'Middle_L.001'],
|
||||||
'ring_1_l': ['RingFinger1_L'],
|
'middle_3_l': ['MiddleFinger3_L', 'MiddleFinger3.L', 'Middle3.L', 'Middle_L.002'],
|
||||||
'ring_2_l': ['RingFinger2_L'],
|
'ring_1_l': ['RingFinger1_L', 'RingFinger1.L', 'Ring1.L', 'Ring_L'],
|
||||||
'ring_3_l': ['RingFinger3_L'],
|
'ring_2_l': ['RingFinger2_L', 'RingFinger2.L', 'Ring2.L', 'Ring_L.001'],
|
||||||
|
'ring_3_l': ['RingFinger3_L', 'RingFinger3.L', 'Ring3.L', 'Ring_L.002'],
|
||||||
|
'pinky_1_l': ['Pinky1_L', 'Pinky1.L', 'Pinky_L'],
|
||||||
|
'pinky_2_l': ['Pinky2_L', 'Pinky2.L', 'Pinky_L.001'],
|
||||||
|
'pinky_3_l': ['Pinky3_L', 'Pinky3.L', 'Pinky_L.002'],
|
||||||
|
|
||||||
# Add finger bones for right hand
|
# Add finger bones for right hand
|
||||||
'thumb_0_r': ['Thumb0_R', 'ThumbO_R'],
|
'thumb_0_r': ['Thumb0_R', 'Thumb0.R', 'ThumbO_R'],
|
||||||
'thumb_1_r': ['Thumb1_R'],
|
'thumb_1_r': ['Thumb1_R', 'Thumb1.R', 'Thumb_R'],
|
||||||
'thumb_2_r': ['Thumb2_R'],
|
'thumb_2_r': ['Thumb2_R', 'Thumb2.R', 'Thumb_R.001'],
|
||||||
'index_1_r': ['IndexFinger1_R'],
|
'thumb_3_r': ['Thumb3_R', 'Thumb3.R', 'Thumb_R.002'],
|
||||||
'index_2_r': ['IndexFinger2_R'],
|
'index_1_r': ['IndexFinger1_R', 'IndexFinger1.R', 'Index1.R', 'Index_R'],
|
||||||
'index_3_r': ['IndexFinger3_R'],
|
'index_2_r': ['IndexFinger2_R', 'IndexFinger2.R', 'Index2.R', 'Index_R.001'],
|
||||||
'middle_1_r': ['MiddleFinger1_R'],
|
'index_3_r': ['IndexFinger3_R', 'IndexFinger3.R', 'Index3.R', 'Index_R.002'],
|
||||||
'middle_2_r': ['MiddleFinger2_R'],
|
'middle_1_r': ['MiddleFinger1_R', 'MiddleFinger1.R', 'Middle1.R', 'Middle_R'],
|
||||||
'middle_3_r': ['MiddleFinger3_R'],
|
'middle_2_r': ['MiddleFinger2_R', 'MiddleFinger2.R', 'Middle2.R', 'Middle_R.001'],
|
||||||
'ring_1_r': ['RingFinger1_R'],
|
'middle_3_r': ['MiddleFinger3_R', 'MiddleFinger3.R', 'Middle3.R', 'Middle_R.002'],
|
||||||
'ring_2_r': ['RingFinger2_R'],
|
'ring_1_r': ['RingFinger1_R', 'RingFinger1.R', 'Ring1.R', 'Ring_R'],
|
||||||
'ring_3_r': ['RingFinger3_R'],
|
'ring_2_r': ['RingFinger2_R', 'RingFinger2.R', 'Ring2.R', 'Ring_R.001'],
|
||||||
|
'ring_3_r': ['RingFinger3_R', 'RingFinger3.R', 'Ring3.R', 'Ring_R.002'],
|
||||||
|
'pinky_1_r': ['Pinky1_R', 'Pinky1.R', 'Pinky_R'],
|
||||||
|
'pinky_2_r': ['Pinky2_R', 'Pinky2.R', 'Pinky_R.001'],
|
||||||
|
'pinky_3_r': ['Pinky3_R', 'Pinky3.R', 'Pinky_R.002'],
|
||||||
|
|
||||||
'breast_upper_1_l': ['BreastUpper1_L'],
|
'breast_upper_1_l': ['BreastUpper1_L', 'BreastUpper1.L'],
|
||||||
'breast_upper_2_l': ['BreastUpper2_L'],
|
'breast_upper_2_l': ['BreastUpper2_L', 'BreastUpper2.L'],
|
||||||
'breast_upper_1_r': ['BreastUpper1_R'],
|
'breast_upper_1_r': ['BreastUpper1_R', 'BreastUpper1.R'],
|
||||||
'breast_upper_2_r': ['BreastUpper2_R'],
|
'breast_upper_2_r': ['BreastUpper2_R', 'BreastUpper2.R'],
|
||||||
|
|
||||||
|
# Little finger bones
|
||||||
|
'little_finger_1_l': ['LittleFinger1_L', 'LittleFinger1.L'],
|
||||||
|
'little_finger_2_l': ['LittleFinger2_L', 'LittleFinger2.L'],
|
||||||
|
'little_finger_3_l': ['LittleFinger3_L', 'LittleFinger3.L'],
|
||||||
|
'little_finger_1_r': ['LittleFinger1_R', 'LittleFinger1.R'],
|
||||||
|
'little_finger_2_r': ['LittleFinger2_R', 'LittleFinger2.R'],
|
||||||
|
'little_finger_3_r': ['LittleFinger3_R', 'LittleFinger3.R'],
|
||||||
|
|
||||||
'ear_upper_l': ['UpperEar.L', 'Upper Ear.L', 'Upper Ear_L'],
|
'ear_upper_l': ['UpperEar.L', 'Upper Ear.L', 'Upper Ear_L'],
|
||||||
'ear_upper_r': ['UpperEar.R', 'Upper Ear.R', 'Upper Ear_R'],
|
'ear_upper_r': ['UpperEar.R', 'Upper Ear.R', 'Upper Ear_R'],
|
||||||
@@ -695,17 +751,17 @@ non_standard_mappings = {
|
|||||||
'left_arm': [
|
'left_arm': [
|
||||||
'mixamorig:LeftArm', 'mixamorig_LeftArm',
|
'mixamorig:LeftArm', 'mixamorig_LeftArm',
|
||||||
'ORG-upper_arm.L', 'upper_arm.L',
|
'ORG-upper_arm.L', 'upper_arm.L',
|
||||||
'lShldrBend', 'lShldrTwist', 'lArm'
|
'lShldrBend', 'lShldrTwist', 'lArm', 'UpperArm.L'
|
||||||
],
|
],
|
||||||
'left_elbow': [
|
'left_elbow': [
|
||||||
'mixamorig:LeftForeArm', 'mixamorig_LeftForeArm',
|
'mixamorig:LeftForeArm', 'mixamorig_LeftForeArm',
|
||||||
'ORG-forearm.L', 'forearm.L',
|
'ORG-forearm.L', 'forearm.L',
|
||||||
'lForearmBend', 'lElbow', 'lForeArm'
|
'lForearmBend', 'lElbow', 'lForeArm', 'LowerArm.L'
|
||||||
],
|
],
|
||||||
'left_wrist': [
|
'left_wrist': [
|
||||||
'mixamorig:LeftHand', 'mixamorig_LeftHand',
|
'mixamorig:LeftHand', 'mixamorig_LeftHand',
|
||||||
'ORG-hand.L', 'hand.L',
|
'ORG-hand.L', 'hand.L',
|
||||||
'lHand', 'lWrist'
|
'lHand', 'lWrist', 'Hand.L'
|
||||||
],
|
],
|
||||||
|
|
||||||
'right_shoulder': [
|
'right_shoulder': [
|
||||||
@@ -716,59 +772,59 @@ non_standard_mappings = {
|
|||||||
'right_arm': [
|
'right_arm': [
|
||||||
'mixamorig:RightArm', 'mixamorig_RightArm',
|
'mixamorig:RightArm', 'mixamorig_RightArm',
|
||||||
'ORG-upper_arm.R', 'upper_arm.R',
|
'ORG-upper_arm.R', 'upper_arm.R',
|
||||||
'rShldrBend', 'rShldrTwist', 'rArm'
|
'rShldrBend', 'rShldrTwist', 'rArm', 'UpperArm.R'
|
||||||
],
|
],
|
||||||
'right_elbow': [
|
'right_elbow': [
|
||||||
'mixamorig:RightForeArm', 'mixamorig_RightForeArm',
|
'mixamorig:RightForeArm', 'mixamorig_RightForeArm',
|
||||||
'ORG-forearm.R', 'forearm.R',
|
'ORG-forearm.R', 'forearm.R',
|
||||||
'rForearmBend', 'rElbow', 'rForeArm'
|
'rForearmBend', 'rElbow', 'rForeArm', 'LowerArm.R'
|
||||||
],
|
],
|
||||||
'right_wrist': [
|
'right_wrist': [
|
||||||
'mixamorig:RightHand', 'mixamorig_RightHand',
|
'mixamorig:RightHand', 'mixamorig_RightHand',
|
||||||
'ORG-hand.R', 'hand.R',
|
'ORG-hand.R', 'hand.R',
|
||||||
'rHand', 'rWrist'
|
'rHand', 'rWrist', 'Hand.R'
|
||||||
],
|
],
|
||||||
|
|
||||||
'left_leg': [
|
'left_leg': [
|
||||||
'mixamorig:LeftUpLeg', 'mixamorig_LeftUpLeg',
|
'mixamorig:LeftUpLeg', 'mixamorig_LeftUpLeg',
|
||||||
'ORG-thigh.L', 'thigh.L',
|
'ORG-thigh.L', 'thigh.L',
|
||||||
'lThighBend', 'lThigh'
|
'lThighBend', 'lThigh', 'UpperLeg.L'
|
||||||
],
|
],
|
||||||
'left_knee': [
|
'left_knee': [
|
||||||
'mixamorig:LeftLeg', 'mixamorig_LeftLeg',
|
'mixamorig:LeftLeg', 'mixamorig_LeftLeg',
|
||||||
'ORG-shin.L', 'shin.L',
|
'ORG-shin.L', 'shin.L',
|
||||||
'lShin', 'lKnee', 'lLeg'
|
'lShin', 'lKnee', 'lLeg', 'LowerLeg.L'
|
||||||
],
|
],
|
||||||
'left_ankle': [
|
'left_ankle': [
|
||||||
'mixamorig:LeftFoot', 'mixamorig_LeftFoot',
|
'mixamorig:LeftFoot', 'mixamorig_LeftFoot',
|
||||||
'ORG-foot.L', 'foot.L',
|
'ORG-foot.L', 'foot.L',
|
||||||
'lFoot', 'lAnkle'
|
'lFoot', 'lAnkle', 'Foot.L'
|
||||||
],
|
],
|
||||||
'left_toe': [
|
'left_toe': [
|
||||||
'mixamorig:LeftToeBase', 'mixamorig_LeftToeBase',
|
'mixamorig:LeftToeBase', 'mixamorig_LeftToeBase',
|
||||||
'ORG-toe.L', 'toe.L',
|
'ORG-toe.L', 'toe.L',
|
||||||
'lToe'
|
'lToe', 'Toes.L'
|
||||||
],
|
],
|
||||||
|
|
||||||
'right_leg': [
|
'right_leg': [
|
||||||
'mixamorig:RightUpLeg', 'mixamorig_RightUpLeg',
|
'mixamorig:RightUpLeg', 'mixamorig_RightUpLeg',
|
||||||
'ORG-thigh.R', 'thigh.R',
|
'ORG-thigh.R', 'thigh.R',
|
||||||
'rThighBend', 'rThigh'
|
'rThighBend', 'rThigh', 'UpperLeg.R'
|
||||||
],
|
],
|
||||||
'right_knee': [
|
'right_knee': [
|
||||||
'mixamorig:RightLeg', 'mixamorig_RightLeg',
|
'mixamorig:RightLeg', 'mixamorig_RightLeg',
|
||||||
'ORG-shin.R', 'shin.R',
|
'ORG-shin.R', 'shin.R',
|
||||||
'rShin', 'rKnee', 'rLeg'
|
'rShin', 'rKnee', 'rLeg', 'LowerLeg.R'
|
||||||
],
|
],
|
||||||
'right_ankle': [
|
'right_ankle': [
|
||||||
'mixamorig:RightFoot', 'mixamorig_RightFoot',
|
'mixamorig:RightFoot', 'mixamorig_RightFoot',
|
||||||
'ORG-foot.R', 'foot.R',
|
'ORG-foot.R', 'foot.R',
|
||||||
'rFoot', 'rAnkle'
|
'rFoot', 'rAnkle', 'Foot.R'
|
||||||
],
|
],
|
||||||
'right_toe': [
|
'right_toe': [
|
||||||
'mixamorig:RightToeBase', 'mixamorig_RightToeBase',
|
'mixamorig:RightToeBase', 'mixamorig_RightToeBase',
|
||||||
'ORG-toe.R', 'toe.R',
|
'ORG-toe.R', 'toe.R',
|
||||||
'rToe'
|
'rToe', 'Toes.R'
|
||||||
],
|
],
|
||||||
|
|
||||||
'thumb_1_l': [
|
'thumb_1_l': [
|
||||||
@@ -934,12 +990,12 @@ non_standard_mappings = {
|
|||||||
'left_eye': [
|
'left_eye': [
|
||||||
'mixamorig:LeftEye', 'mixamorig_LeftEye',
|
'mixamorig:LeftEye', 'mixamorig_LeftEye',
|
||||||
'ORG-eye.L', 'eye.L',
|
'ORG-eye.L', 'eye.L',
|
||||||
'lEye'
|
'lEye', 'Eye.L'
|
||||||
],
|
],
|
||||||
'right_eye': [
|
'right_eye': [
|
||||||
'mixamorig:RightEye', 'mixamorig_RightEye',
|
'mixamorig:RightEye', 'mixamorig_RightEye',
|
||||||
'ORG-eye.R', 'eye.R',
|
'ORG-eye.R', 'eye.R',
|
||||||
'rEye'
|
'rEye', 'Eye.R'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ class AvatarToolkit_OT_MergeArmature(bpy.types.Operator):
|
|||||||
#Store current armature settings that can mess us up.
|
#Store current armature settings that can mess us up.
|
||||||
data_breaking_base = store_breaking_settings_armature(base_armature)
|
data_breaking_base = store_breaking_settings_armature(base_armature)
|
||||||
data_breaking_merge = store_breaking_settings_armature(merge_armature)
|
data_breaking_merge = store_breaking_settings_armature(merge_armature)
|
||||||
|
|
||||||
|
# Store the merge armature name before it gets removed during join
|
||||||
|
merge_armature_name_stored = merge_armature.name
|
||||||
|
|
||||||
# Remove Rigid Bodies and Joints
|
# Remove Rigid Bodies and Joints
|
||||||
delete_rigidbodies_and_joints(base_armature)
|
delete_rigidbodies_and_joints(base_armature)
|
||||||
@@ -77,14 +80,17 @@ class AvatarToolkit_OT_MergeArmature(bpy.types.Operator):
|
|||||||
wm.progress_end()
|
wm.progress_end()
|
||||||
|
|
||||||
restore_breaking_settings_armature(base_armature, data_breaking_base)
|
restore_breaking_settings_armature(base_armature, data_breaking_base)
|
||||||
restore_breaking_settings_armature(merge_armature, data_breaking_merge)
|
|
||||||
|
if merge_armature_name_stored in bpy.data.objects:
|
||||||
|
merge_armature_obj = bpy.data.objects[merge_armature_name_stored]
|
||||||
|
restore_breaking_settings_armature(merge_armature_obj, data_breaking_merge)
|
||||||
|
|
||||||
self.report({'INFO'}, t('MergeArmature.success'))
|
self.report({'INFO'}, t('MergeArmature.success'))
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error merging armatures:", exception=e)
|
logger.error(f"Error merging armatures: {str(e)}\n{traceback.format_exc()}")
|
||||||
self.report({'ERROR'}, traceback.format_exc())
|
self.report({'ERROR'}, traceback.format_exc())
|
||||||
return {'CANCELLED'}
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
|||||||
@@ -186,7 +186,6 @@ class AvatarToolKit_OT_RemoveZeroWeightBones(Operator):
|
|||||||
if not armature:
|
if not armature:
|
||||||
return {'CANCELLED'}
|
return {'CANCELLED'}
|
||||||
|
|
||||||
# Store initial transforms
|
|
||||||
bpy.ops.object.mode_set(mode='EDIT')
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
initial_transforms: Dict[str, Dict[str, Any]] = {}
|
initial_transforms: Dict[str, Dict[str, Any]] = {}
|
||||||
data_breaking = store_breaking_settings_armature(armature)
|
data_breaking = store_breaking_settings_armature(armature)
|
||||||
@@ -200,56 +199,61 @@ class AvatarToolKit_OT_RemoveZeroWeightBones(Operator):
|
|||||||
'parent': bone.parent.name if bone.parent else None
|
'parent': bone.parent.name if bone.parent else None
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get weighted bones
|
# Get bones with any weight
|
||||||
weighted_bones: List[str] = []
|
weighted_bones: List[str] = []
|
||||||
meshes = get_all_meshes(context)
|
meshes = get_all_meshes(context)
|
||||||
zero_weight_bones: List[str] = []
|
|
||||||
|
|
||||||
for mesh in meshes:
|
for mesh in meshes:
|
||||||
mesh_data: Mesh = mesh.data
|
for vertex in mesh.data.vertices:
|
||||||
for vertex in mesh_data.vertices:
|
|
||||||
for group in vertex.groups:
|
for group in vertex.groups:
|
||||||
if group.weight > context.scene.avatar_toolkit.merge_weights_threshold:
|
if group.weight > context.scene.avatar_toolkit.merge_weights_threshold:
|
||||||
weighted_bones.append(mesh.vertex_groups[group.group].name)
|
vg = mesh.vertex_groups[group.group]
|
||||||
|
if vg.name not in weighted_bones:
|
||||||
|
weighted_bones.append(vg.name)
|
||||||
|
|
||||||
# Process bone removal
|
armature_data = armature.data
|
||||||
bpy.ops.object.mode_set(mode='EDIT')
|
|
||||||
armature_data: Armature = armature.data
|
|
||||||
removed_count = 0
|
removed_count = 0
|
||||||
|
zero_weight_bones: List[str] = []
|
||||||
|
|
||||||
for bone in armature_data.edit_bones[:]: # Create a copy of the list
|
def is_zero_weight_chain(bone, weighted_bones, preserve_check_fn):
|
||||||
if (bone.name not in weighted_bones and
|
if bone.name in weighted_bones or preserve_check_fn(bone.name, context):
|
||||||
not self.should_preserve_bone(bone.name, context)):
|
return False
|
||||||
|
return all(is_zero_weight_chain(child, weighted_bones, preserve_check_fn) for child in bone.children)
|
||||||
if context.scene.avatar_toolkit.list_only_mode:
|
|
||||||
zero_weight_bones.append(bone.name)
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Store children data
|
for bone in armature_data.edit_bones[:]:
|
||||||
children = bone.children
|
if bone.name in weighted_bones or self.should_preserve_bone(bone.name, context):
|
||||||
children_data = {child.name: initial_transforms[child.name] for child in children}
|
continue
|
||||||
|
|
||||||
# Reparent children
|
if not is_zero_weight_chain(bone, weighted_bones, self.should_preserve_bone):
|
||||||
for child in children:
|
continue
|
||||||
|
|
||||||
|
if context.scene.avatar_toolkit.list_only_mode:
|
||||||
|
zero_weight_bones.append(bone.name)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Traverse and collect the full empty chain
|
||||||
|
stack = [bone]
|
||||||
|
chain = []
|
||||||
|
|
||||||
|
while stack:
|
||||||
|
b = stack.pop()
|
||||||
|
chain.append(b)
|
||||||
|
stack.extend(b.children)
|
||||||
|
|
||||||
|
for b in reversed(chain): # Remove children before parents
|
||||||
|
for child in b.children:
|
||||||
child.use_connect = False
|
child.use_connect = False
|
||||||
if bone.parent:
|
if b.parent:
|
||||||
child.parent = bone.parent
|
child.parent = b.parent
|
||||||
|
if b.name in armature_data.edit_bones:
|
||||||
# Remove bone
|
armature_data.edit_bones.remove(b)
|
||||||
armature_data.edit_bones.remove(bone)
|
removed_count += 1
|
||||||
removed_count += 1
|
|
||||||
|
|
||||||
# Restore children positions
|
|
||||||
for child_name, data in children_data.items():
|
|
||||||
if child_name in armature_data.edit_bones:
|
|
||||||
child = armature_data.edit_bones[child_name]
|
|
||||||
restore_bone_transforms(child, data)
|
|
||||||
|
|
||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
|
|
||||||
if context.scene.avatar_toolkit.list_only_mode:
|
if context.scene.avatar_toolkit.list_only_mode:
|
||||||
self.populate_bone_list(context, zero_weight_bones)
|
self.populate_bone_list(context, zero_weight_bones)
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
restore_breaking_settings_armature(armature, data_breaking)
|
restore_breaking_settings_armature(armature, data_breaking)
|
||||||
self.report({'INFO'}, t("Tools.clean_weights_success", count=removed_count))
|
self.report({'INFO'}, t("Tools.clean_weights_success", count=removed_count))
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import traceback
|
|||||||
import bpy
|
import bpy
|
||||||
from typing import Dict, List, Set, Optional, Tuple, Any
|
from typing import Dict, List, Set, Optional, Tuple, Any
|
||||||
from bpy.types import Operator, Context, Object, PoseBone, EditBone, Bone, Constraint
|
from bpy.types import Operator, Context, Object, PoseBone, EditBone, Bone, Constraint
|
||||||
from ...core.common import get_active_armature
|
from ...core.common import get_active_armature, transfer_vertex_weights, get_all_meshes
|
||||||
from ...core.logging_setup import logger
|
from ...core.logging_setup import logger
|
||||||
from ...core.translations import t
|
from ...core.translations import t
|
||||||
from ...core.dictionaries import rigify_unity_names, rigify_basic_unity_names, rigify_unnecessary_bones
|
from ...core.dictionaries import rigify_unity_names, rigify_basic_unity_names, rigify_unnecessary_bones
|
||||||
@@ -69,19 +69,50 @@ class AvatarToolkit_OT_ConvertRigifyToUnity(Operator):
|
|||||||
|
|
||||||
# Set armature as active object before mode switch
|
# Set armature as active object before mode switch
|
||||||
bpy.context.view_layer.objects.active = armature
|
bpy.context.view_layer.objects.active = armature
|
||||||
|
|
||||||
|
# Get all meshes for weight transfer
|
||||||
|
meshes = get_all_meshes(bpy.context)
|
||||||
|
|
||||||
bpy.ops.object.mode_set(mode='EDIT')
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
|
|
||||||
bones_to_remove: List[str] = []
|
bones_to_remove: List[str] = []
|
||||||
for bone in armature.data.edit_bones:
|
for bone in armature.data.edit_bones:
|
||||||
if any(pattern in bone.name.lower() for pattern in rigify_unnecessary_bones):
|
bone_name_lower = bone.name.lower()
|
||||||
|
if any(bone_name_lower.startswith(pattern) or bone_name_lower == pattern
|
||||||
|
for pattern in rigify_unnecessary_bones):
|
||||||
bones_to_remove.append(bone.name)
|
bones_to_remove.append(bone.name)
|
||||||
|
|
||||||
|
# Check for neck bones that need merging
|
||||||
|
merge_neck_bones = 'spine.004' in armature.data.edit_bones and 'spine.005' in armature.data.edit_bones
|
||||||
|
|
||||||
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
|
|
||||||
|
# Transfer weights from bones being removed
|
||||||
|
for bone_name in bones_to_remove:
|
||||||
|
if bone_name in armature.data.bones:
|
||||||
|
logger.debug(f"Transferring weights from bone: {bone_name}")
|
||||||
|
for mesh in meshes:
|
||||||
|
if bone_name in mesh.vertex_groups:
|
||||||
|
# Remove the vertex group since we don't need the weights
|
||||||
|
mesh.vertex_groups.remove(mesh.vertex_groups[bone_name])
|
||||||
|
|
||||||
|
# Transfer weights for neck bone merging
|
||||||
|
if merge_neck_bones:
|
||||||
|
logger.debug("Transferring weights from spine.005 to spine.004")
|
||||||
|
for mesh in meshes:
|
||||||
|
if 'spine.005' in mesh.vertex_groups:
|
||||||
|
transfer_vertex_weights(mesh, 'spine.005', 'spine.004')
|
||||||
|
|
||||||
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
|
|
||||||
|
# Remove unnecessary bones
|
||||||
for bone_name in bones_to_remove:
|
for bone_name in bones_to_remove:
|
||||||
if bone_name in armature.data.edit_bones:
|
if bone_name in armature.data.edit_bones:
|
||||||
logger.debug(f"Removing bone: {bone_name}")
|
logger.debug(f"Removing bone: {bone_name}")
|
||||||
armature.data.edit_bones.remove(armature.data.edit_bones[bone_name])
|
armature.data.edit_bones.remove(armature.data.edit_bones[bone_name])
|
||||||
|
|
||||||
if 'spine.004' in armature.data.edit_bones and 'spine.005' in armature.data.edit_bones:
|
# Merge neck bones
|
||||||
|
if merge_neck_bones:
|
||||||
logger.debug("Merging neck bones")
|
logger.debug("Merging neck bones")
|
||||||
neck_start = armature.data.edit_bones['spine.004']
|
neck_start = armature.data.edit_bones['spine.004']
|
||||||
neck_end = armature.data.edit_bones['spine.005']
|
neck_end = armature.data.edit_bones['spine.005']
|
||||||
@@ -89,6 +120,7 @@ class AvatarToolkit_OT_ConvertRigifyToUnity(Operator):
|
|||||||
armature.data.edit_bones.remove(neck_end)
|
armature.data.edit_bones.remove(neck_end)
|
||||||
neck_start.name = "Neck"
|
neck_start.name = "Neck"
|
||||||
|
|
||||||
|
# Rename head bone
|
||||||
if 'spine.006' in armature.data.edit_bones:
|
if 'spine.006' in armature.data.edit_bones:
|
||||||
logger.debug("Renaming head bone")
|
logger.debug("Renaming head bone")
|
||||||
head_bone = armature.data.edit_bones['spine.006']
|
head_bone = armature.data.edit_bones['spine.006']
|
||||||
@@ -137,6 +169,22 @@ class AvatarToolkit_OT_ConvertRigifyToUnity(Operator):
|
|||||||
if bone_name in armature.data.bones:
|
if bone_name in armature.data.bones:
|
||||||
armature.data.bones[bone_name].use_deform = False
|
armature.data.bones[bone_name].use_deform = False
|
||||||
|
|
||||||
|
# Get all meshes for weight transfer
|
||||||
|
meshes = get_all_meshes(bpy.context)
|
||||||
|
|
||||||
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
|
for bone_name in remove_bones_in_chain:
|
||||||
|
if bone_name in armature.data.bones:
|
||||||
|
parent_name = armature.data.bones[bone_name].parent.name if armature.data.bones[bone_name].parent else None
|
||||||
|
if parent_name:
|
||||||
|
logger.debug(f"Transferring weights from {bone_name} to {parent_name}")
|
||||||
|
for mesh in meshes:
|
||||||
|
if bone_name in mesh.vertex_groups and parent_name in mesh.vertex_groups:
|
||||||
|
transfer_vertex_weights(mesh, bone_name, parent_name)
|
||||||
|
elif bone_name in mesh.vertex_groups:
|
||||||
|
# Remove weights if no parent to merge to
|
||||||
|
mesh.vertex_groups.remove(mesh.vertex_groups[bone_name])
|
||||||
|
|
||||||
bpy.ops.object.mode_set(mode='EDIT')
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
for bone_name in remove_bones_in_chain:
|
for bone_name in remove_bones_in_chain:
|
||||||
if bone_name in armature.data.bones:
|
if bone_name in armature.data.bones:
|
||||||
@@ -190,6 +238,17 @@ class AvatarToolkit_OT_ConvertRigifyToUnity(Operator):
|
|||||||
("DEF-thigh_twist.R", "DEF-thigh.R")
|
("DEF-thigh_twist.R", "DEF-thigh.R")
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Get all meshes for weight transfer
|
||||||
|
meshes = get_all_meshes(bpy.context)
|
||||||
|
|
||||||
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
|
for twist_bone, parent_bone in twist_bones:
|
||||||
|
if twist_bone in armature.data.bones and parent_bone in armature.data.bones:
|
||||||
|
logger.debug(f"Transferring weights from {twist_bone} to {parent_bone}")
|
||||||
|
for mesh in meshes:
|
||||||
|
if twist_bone in mesh.vertex_groups:
|
||||||
|
transfer_vertex_weights(mesh, twist_bone, parent_bone)
|
||||||
|
|
||||||
bpy.ops.object.mode_set(mode='EDIT')
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
for twist_bone, parent_bone in twist_bones:
|
for twist_bone, parent_bone in twist_bones:
|
||||||
if twist_bone in armature.data.edit_bones and parent_bone in armature.data.edit_bones:
|
if twist_bone in armature.data.edit_bones and parent_bone in armature.data.edit_bones:
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ from ...core.dictionaries import (
|
|||||||
bone_hierarchy,
|
bone_hierarchy,
|
||||||
acceptable_bone_names,
|
acceptable_bone_names,
|
||||||
acceptable_bone_hierarchy,
|
acceptable_bone_hierarchy,
|
||||||
non_standard_mappings
|
non_standard_mappings,
|
||||||
|
reverse_bone_lookup,
|
||||||
|
simplify_bonename
|
||||||
)
|
)
|
||||||
|
|
||||||
class AvatarToolkit_OT_StandardizeArmature(Operator):
|
class AvatarToolkit_OT_StandardizeArmature(Operator):
|
||||||
@@ -134,17 +136,14 @@ class AvatarToolkit_OT_StandardizeArmature(Operator):
|
|||||||
existing_standard_bones.add(bone.name)
|
existing_standard_bones.add(bone.name)
|
||||||
logger.debug(f"Found existing standard bone: {bone.name}")
|
logger.debug(f"Found existing standard bone: {bone.name}")
|
||||||
|
|
||||||
# Build a mapping of non-standard bone names to standard names
|
# Use the reverse bone lookup that's already built and simplified
|
||||||
name_mapping: Dict[str, str] = {}
|
name_mapping: Dict[str, str] = {}
|
||||||
for category, standard_name in standard_bones.items():
|
for simplified_name, category in reverse_bone_lookup.items():
|
||||||
# Skip if this standard bone already exists
|
if category in standard_bones:
|
||||||
if standard_name in existing_standard_bones:
|
standard_name = standard_bones[category]
|
||||||
continue
|
# Skip if this standard bone already exists
|
||||||
|
if standard_name not in existing_standard_bones:
|
||||||
# Get all variants for this category
|
name_mapping[simplified_name] = standard_name
|
||||||
if category in non_standard_mappings:
|
|
||||||
for variant in non_standard_mappings[category]:
|
|
||||||
name_mapping[variant.lower()] = standard_name
|
|
||||||
|
|
||||||
# First pass: identify bones to rename
|
# First pass: identify bones to rename
|
||||||
bones_to_rename: Dict[str, str] = {}
|
bones_to_rename: Dict[str, str] = {}
|
||||||
@@ -155,20 +154,14 @@ class AvatarToolkit_OT_StandardizeArmature(Operator):
|
|||||||
if original_name in standard_bones.values():
|
if original_name in standard_bones.values():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
simplified_name: str = original_name.lower().replace(' ', '').replace('_', '').replace('.', '')
|
simplified_name: str = simplify_bonename(original_name)
|
||||||
|
|
||||||
# Check if this bone matches any known pattern
|
# Check if this simplified bone name has a standard mapping
|
||||||
for variant, standard_name in name_mapping.items():
|
if simplified_name in name_mapping:
|
||||||
# More precise matching - exact match or with common separators
|
standard_name = name_mapping[simplified_name]
|
||||||
if (variant == simplified_name or
|
if original_name != standard_name:
|
||||||
variant == original_name.lower() or
|
bones_to_rename[original_name] = standard_name
|
||||||
f"{variant}_" in simplified_name or
|
logger.debug(f"Identified bone to rename: {original_name} -> {standard_name}")
|
||||||
f"{variant}." in simplified_name):
|
|
||||||
|
|
||||||
if original_name != standard_name:
|
|
||||||
bones_to_rename[original_name] = standard_name
|
|
||||||
logger.debug(f"Identified bone to rename: {original_name} -> {standard_name}")
|
|
||||||
break
|
|
||||||
|
|
||||||
# Special case for spine/chest hierarchy
|
# Special case for spine/chest hierarchy
|
||||||
# If we don't have an upper chest, don't rename chest to upper chest because it will break hierarchy
|
# If we don't have an upper chest, don't rename chest to upper chest because it will break hierarchy
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"authors": ["Avatar Toolkit Team"],
|
"authors": ["Avatar Toolkit Team"],
|
||||||
"messages": {
|
"messages": {
|
||||||
"AvatarToolkit.label": "Avatar Toolkit (Alpha 0.3.0)",
|
"AvatarToolkit.label": "Avatar Toolkit (Alpha 0.3.1)",
|
||||||
"AvatarToolkit.desc1": "Avatar Toolkit is in Early Access there",
|
"AvatarToolkit.desc1": "Avatar Toolkit is in Early Access there",
|
||||||
"AvatarToolkit.desc2": "will be issues, if you find any issues,",
|
"AvatarToolkit.desc2": "will be issues, if you find any issues,",
|
||||||
"AvatarToolkit.desc3": "please report it on our Github.",
|
"AvatarToolkit.desc3": "please report it on our Github.",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"authors": ["Avatar Toolkit Team"],
|
"authors": ["Avatar Toolkit Team"],
|
||||||
"messages": {
|
"messages": {
|
||||||
"AvatarToolkit.label": "アバターツールキット (アルファ 0.3.0)",
|
"AvatarToolkit.label": "アバターツールキット (アルファ 0.3.1)",
|
||||||
"AvatarToolkit.desc1": "アバターツールキットは早期アクセス中であり、",
|
"AvatarToolkit.desc1": "アバターツールキットは早期アクセス中であり、",
|
||||||
"AvatarToolkit.desc2": "問題が発生する可能性があります。問題を見つけた場合は、",
|
"AvatarToolkit.desc2": "問題が発生する可能性があります。問題を見つけた場合は、",
|
||||||
"AvatarToolkit.desc3": "GitHubで報告してください。",
|
"AvatarToolkit.desc3": "GitHubで報告してください。",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"authors": ["Avatar Toolkit Team"],
|
"authors": ["Avatar Toolkit Team"],
|
||||||
"messages": {
|
"messages": {
|
||||||
"AvatarToolkit.label": "아바타 툴킷 (알파 0.3.0)",
|
"AvatarToolkit.label": "아바타 툴킷 (알파 0.3.1)",
|
||||||
"AvatarToolkit.desc1": "아바타 툴킷은 초기 액세스 단계에 있으므로",
|
"AvatarToolkit.desc1": "아바타 툴킷은 초기 액세스 단계에 있으므로",
|
||||||
"AvatarToolkit.desc2": "문제가 있을 수 있습니다. 문제를 발견하시면",
|
"AvatarToolkit.desc2": "문제가 있을 수 있습니다. 문제를 발견하시면",
|
||||||
"AvatarToolkit.desc3": "Github에 보고해 주세요.",
|
"AvatarToolkit.desc3": "Github에 보고해 주세요.",
|
||||||
|
|||||||
Reference in New Issue
Block a user