Acceptable Standards Added
This commit is contained in:
@@ -5,21 +5,29 @@ from ..core.translations import t
|
||||
from ..core.dictionaries import (
|
||||
standard_bones,
|
||||
bone_hierarchy,
|
||||
finger_hierarchy
|
||||
finger_hierarchy,
|
||||
acceptable_bone_hierarchy,
|
||||
acceptable_bone_names
|
||||
)
|
||||
|
||||
def validate_armature(armature: Object) -> Tuple[bool, List[str]]:
|
||||
def validate_armature(armature: Object) -> Tuple[bool, List[str], bool]:
|
||||
"""
|
||||
Validates armature and returns (is_valid, messages, is_acceptable_standard)
|
||||
"""
|
||||
validation_mode = bpy.context.scene.avatar_toolkit.validation_mode
|
||||
messages: List[str] = []
|
||||
|
||||
if validation_mode == 'NONE':
|
||||
return True, []
|
||||
return True, [], False
|
||||
|
||||
if not armature or armature.type != 'ARMATURE' or not armature.data.bones:
|
||||
return False, [t("Armature.validation.basic_check_failed")]
|
||||
return False, [t("Armature.validation.basic_check_failed")], False
|
||||
|
||||
found_bones: Dict[str, Bone] = {bone.name: bone for bone in armature.data.bones}
|
||||
|
||||
# Check if armature matches acceptable standards
|
||||
is_acceptable = check_acceptable_standards(found_bones)
|
||||
|
||||
# List all bones in armature
|
||||
bone_list = "\n".join([f"- {bone}" for bone in found_bones.keys()])
|
||||
messages.append(t("Armature.validation.found_bones", bones=bone_list))
|
||||
@@ -75,8 +83,17 @@ def validate_armature(armature: Object) -> Tuple[bool, List[str]]:
|
||||
if not validate_finger_chain(found_bones, finger_chain):
|
||||
messages.append(t("Armature.validation.invalid_finger", finger=finger_chain[0]))
|
||||
|
||||
is_valid: bool = len(messages) == 0
|
||||
return is_valid, messages
|
||||
is_valid = len(messages) == 0
|
||||
|
||||
if not is_valid and is_acceptable:
|
||||
messages = [
|
||||
t("Armature.validation.acceptable_standard.success"),
|
||||
t("Armature.validation.acceptable_standard.note"),
|
||||
t("Armature.validation.acceptable_standard.option")
|
||||
]
|
||||
return True, messages, True
|
||||
|
||||
return is_valid, messages, False
|
||||
|
||||
def validate_bone_hierarchy(bones: Dict[str, Bone], parent_name: str, child_name: str) -> bool:
|
||||
"""Validate if there is a valid parent-child relationship between bones"""
|
||||
@@ -109,3 +126,23 @@ def validate_finger_chain(bones: Dict[str, Bone], chain: Tuple[str, ...]) -> boo
|
||||
if not validate_bone_hierarchy(bones, chain[i], chain[i + 1]):
|
||||
return False
|
||||
return True
|
||||
|
||||
def check_acceptable_standards(bones: Dict[str, Bone]) -> bool:
|
||||
"""Check if armature matches acceptable non-standard hierarchy"""
|
||||
# Check if bones exist in acceptable list
|
||||
for bone_category, acceptable_names in acceptable_bone_names.items():
|
||||
found = False
|
||||
for name in acceptable_names:
|
||||
if name in bones:
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
return False
|
||||
|
||||
# Validate acceptable hierarchy
|
||||
for parent, child in acceptable_bone_hierarchy:
|
||||
if parent in bones and child in bones:
|
||||
if not validate_bone_hierarchy(bones, parent, child):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@@ -470,6 +470,62 @@ finger_hierarchy = {
|
||||
]
|
||||
}
|
||||
|
||||
acceptable_bone_hierarchy = [
|
||||
# Right side chain
|
||||
('Hips', 'Chest'),
|
||||
('Chest', 'Shoulder.R'),
|
||||
('Shoulder.R', 'Arm.R'),
|
||||
('Arm.R', 'Elbow.R'),
|
||||
('Elbow.R', 'Wrist.R'),
|
||||
('Hips', 'Leg.R'),
|
||||
('Leg.R', 'Knee.R'),
|
||||
('Knee.R', 'Foot.R'),
|
||||
('Foot.R', 'Toes.R'),
|
||||
|
||||
# Left side chain
|
||||
('Chest', 'Shoulder.L'),
|
||||
('Shoulder.L', 'Arm.L'),
|
||||
('Arm.L', 'Elbow.L'),
|
||||
('Elbow.L', 'Wrist.L'),
|
||||
('Hips', 'Leg.L'),
|
||||
('Leg.L', 'Knee.L'),
|
||||
('Knee.L', 'Foot.L'),
|
||||
('Foot.L', 'Toes.L'),
|
||||
|
||||
# Head and Eyes
|
||||
('Chest', 'Neck'),
|
||||
('Neck', 'Head'),
|
||||
('Head', 'Eye_L'),
|
||||
('Head', 'Eye_R'),
|
||||
('Head', 'LeftEye'),
|
||||
('Head', 'RightEye')
|
||||
]
|
||||
|
||||
acceptable_bone_names = {
|
||||
'hips': ['Hips'],
|
||||
'chest': ['Chest'],
|
||||
'neck': ['Neck'],
|
||||
'head': ['Head'],
|
||||
'eye_l': ['Eye_L', 'LeftEye'],
|
||||
'eye_r': ['Eye_R', 'RightEye'],
|
||||
'shoulder_r': ['Shoulder.R'],
|
||||
'arm_r': ['Arm.R'],
|
||||
'elbow_r': ['Elbow.R'],
|
||||
'wrist_r': ['Wrist.R'],
|
||||
'leg_r': ['Leg.R'],
|
||||
'knee_r': ['Knee.R'],
|
||||
'foot_r': ['Foot.R'],
|
||||
'toes_r': ['Toes.R'],
|
||||
'shoulder_l': ['Shoulder.L'],
|
||||
'arm_l': ['Arm.L'],
|
||||
'elbow_l': ['Elbow.L'],
|
||||
'wrist_l': ['Wrist.L'],
|
||||
'leg_l': ['Leg.L'],
|
||||
'knee_l': ['Knee.L'],
|
||||
'foot_l': ['Foot.L'],
|
||||
'toes_l': ['Toes.L']
|
||||
}
|
||||
|
||||
rigify_unity_names = {
|
||||
"DEF-spine": "Hips",
|
||||
"DEF-spine.001": "Spine",
|
||||
|
||||
+1
-13
@@ -396,12 +396,6 @@ class AvatarToolkitSceneProperties(PropertyGroup):
|
||||
default=0
|
||||
)
|
||||
|
||||
merge_twist_bones: BoolProperty(
|
||||
name=t("Tools.merge_twist_bones"),
|
||||
description=t("Tools.merge_twist_bones_desc"),
|
||||
default=True
|
||||
)
|
||||
|
||||
list_only_mode: BoolProperty(
|
||||
name=t("Tools.list_only_mode"),
|
||||
description=t("Tools.list_only_mode_desc"),
|
||||
@@ -521,19 +515,13 @@ class AvatarToolkitSceneProperties(PropertyGroup):
|
||||
default=False
|
||||
)
|
||||
show_non_standard: BoolProperty(
|
||||
name="Show Non-Standard Bones",
|
||||
name="Show Non-Standard Bones",
|
||||
default=False
|
||||
)
|
||||
show_hierarchy: BoolProperty(
|
||||
name="Show Hierarchy Issues",
|
||||
default=False
|
||||
)
|
||||
|
||||
merge_twist_bones: BoolProperty(
|
||||
name=t("Tools.merge_twist_bones"),
|
||||
description=t("Tools.merge_twist_bones_desc"),
|
||||
default=True
|
||||
)
|
||||
|
||||
def register() -> None:
|
||||
"""Register the Avatar Toolkit property group"""
|
||||
|
||||
Reference in New Issue
Block a user