Fixes
- All bones should convert now - Root bone now get's removed. - Fixed Collections not getting removed
This commit is contained in:
+49
-47
@@ -266,73 +266,73 @@ bone_names.update({
|
|||||||
'neck': bone_names['neck'] + ['jbipcneck', 'jneck', 'vrmneck'],
|
'neck': bone_names['neck'] + ['jbipcneck', 'jneck', 'vrmneck'],
|
||||||
'head': bone_names['head'] + ['jbipchead', 'jhead', 'vrmhead'],
|
'head': bone_names['head'] + ['jbipchead', 'jhead', 'vrmhead'],
|
||||||
|
|
||||||
# VRM arms
|
# VRM arms - both simplified patterns
|
||||||
'left_shoulder': bone_names['left_shoulder'] + ['jbipllshoulder', 'jlshoulder'],
|
'left_shoulder': bone_names['left_shoulder'] + ['jbipllshoulder', 'jlshoulder', 'jbiplshoulder'],
|
||||||
'left_arm': bone_names['left_arm'] + ['jbiplupperarm', 'jlupperarm'],
|
'left_arm': bone_names['left_arm'] + ['jbiplupperarm', 'jlupperarm'],
|
||||||
'left_elbow': bone_names['left_elbow'] + ['jbipllforearm', 'jlforearm'],
|
'left_elbow': bone_names['left_elbow'] + ['jbipllforearm', 'jlforearm', 'jbipllowerarm'],
|
||||||
'left_wrist': bone_names['left_wrist'] + ['jbipllhand', 'jlhand'],
|
'left_wrist': bone_names['left_wrist'] + ['jbipllhand', 'jlhand', 'jbiplhand'],
|
||||||
|
|
||||||
'right_shoulder': bone_names['right_shoulder'] + ['jbiprlshoulder', 'jrshoulder'],
|
'right_shoulder': bone_names['right_shoulder'] + ['jbiprlshoulder', 'jrshoulder', 'jbiprshoulder'],
|
||||||
'right_arm': bone_names['right_arm'] + ['jbiprrupperarm', 'jrupperarm'],
|
'right_arm': bone_names['right_arm'] + ['jbiprrupperarm', 'jrupperarm', 'jbiprupperarm'],
|
||||||
'right_elbow': bone_names['right_elbow'] + ['jbiprrforearm', 'jrforearm'],
|
'right_elbow': bone_names['right_elbow'] + ['jbiprrforearm', 'jrforearm', 'jbiprforearm', 'jbiprlowerarm'],
|
||||||
'right_wrist': bone_names['right_wrist'] + ['jbiprrhand', 'jrhand'],
|
'right_wrist': bone_names['right_wrist'] + ['jbiprrhand', 'jrhand', 'jbiprhand'],
|
||||||
|
|
||||||
# VRM legs
|
# VRM legs - both simplified patterns
|
||||||
'left_leg': bone_names['left_leg'] + ['jbiplupperleg', 'jlupperleg'],
|
'left_leg': bone_names['left_leg'] + ['jbiplupperleg', 'jlupperleg'],
|
||||||
'left_knee': bone_names['left_knee'] + ['jbipllowerleg', 'jllowerleg'],
|
'left_knee': bone_names['left_knee'] + ['jbipllowerleg', 'jllowerleg'],
|
||||||
'left_ankle': bone_names['left_ankle'] + ['jbipllfoot', 'jlfoot'],
|
'left_ankle': bone_names['left_ankle'] + ['jbipllfoot', 'jlfoot', 'jbiplfoot'],
|
||||||
'left_toe': bone_names['left_toe'] + ['jbiplltoe', 'jltoe'],
|
'left_toe': bone_names['left_toe'] + ['jbiplltoe', 'jltoe', 'jbipltoebase'],
|
||||||
|
|
||||||
'right_leg': bone_names['right_leg'] + ['jbiprrupperleg', 'jrupperleg'],
|
'right_leg': bone_names['right_leg'] + ['jbiprrupperleg', 'jrupperleg', 'jbiprupperleg'],
|
||||||
'right_knee': bone_names['right_knee'] + ['jbiprrlowerleg', 'jrlowerleg'],
|
'right_knee': bone_names['right_knee'] + ['jbiprrlowerleg', 'jrlowerleg', 'jbiprlowerleg'],
|
||||||
'right_ankle': bone_names['right_ankle'] + ['jbiprrfoot', 'jrfoot'],
|
'right_ankle': bone_names['right_ankle'] + ['jbiprrfoot', 'jrfoot', 'jbiprfoot'],
|
||||||
'right_toe': bone_names['right_toe'] + ['jbiprrtoe', 'jrtoe'],
|
'right_toe': bone_names['right_toe'] + ['jbiprrtoe', 'jrtoe', 'jbiprtoebase'],
|
||||||
|
|
||||||
# VRM eyes
|
# VRM eyes
|
||||||
'left_eye': bone_names['left_eye'] + ['jbipcleye', 'jleye'],
|
'left_eye': bone_names['left_eye'] + ['jbipcleye', 'jleye'],
|
||||||
'right_eye': bone_names['right_eye'] + ['jbipcreye', 'jreye'],
|
'right_eye': bone_names['right_eye'] + ['jbipcreye', 'jreye'],
|
||||||
|
|
||||||
# VRM fingers - Left
|
# VRM fingers - Left (including Little finger variations)
|
||||||
'thumb_1_l': bone_names['thumb_1_l'] + ['jbipllthumb1', 'jlthumb1'],
|
'thumb_1_l': bone_names['thumb_1_l'] + ['jbipllthumb1', 'jlthumb1', 'jbiplthumb1'],
|
||||||
'thumb_2_l': bone_names['thumb_2_l'] + ['jbipllthumb2', 'jlthumb2'],
|
'thumb_2_l': bone_names['thumb_2_l'] + ['jbipllthumb2', 'jlthumb2', 'jbiplthumb2'],
|
||||||
'thumb_3_l': bone_names['thumb_3_l'] + ['jbipllthumb3', 'jlthumb3'],
|
'thumb_3_l': bone_names['thumb_3_l'] + ['jbipllthumb3', 'jlthumb3', 'jbiplthumb3'],
|
||||||
|
|
||||||
'index_1_l': bone_names['index_1_l'] + ['jbipllindex1', 'jlindex1'],
|
'index_1_l': bone_names['index_1_l'] + ['jbipllindex1', 'jlindex1', 'jbiplindex1'],
|
||||||
'index_2_l': bone_names['index_2_l'] + ['jbipllindex2', 'jlindex2'],
|
'index_2_l': bone_names['index_2_l'] + ['jbipllindex2', 'jlindex2', 'jbiplindex2'],
|
||||||
'index_3_l': bone_names['index_3_l'] + ['jbipllindex3', 'jlindex3'],
|
'index_3_l': bone_names['index_3_l'] + ['jbipllindex3', 'jlindex3', 'jbiplindex3'],
|
||||||
|
|
||||||
'middle_1_l': bone_names['middle_1_l'] + ['jbipllmiddle1', 'jlmiddle1'],
|
'middle_1_l': bone_names['middle_1_l'] + ['jbipllmiddle1', 'jlmiddle1', 'jbiplmiddle1'],
|
||||||
'middle_2_l': bone_names['middle_2_l'] + ['jbipllmiddle2', 'jlmiddle2'],
|
'middle_2_l': bone_names['middle_2_l'] + ['jbipllmiddle2', 'jlmiddle2', 'jbiplmiddle2'],
|
||||||
'middle_3_l': bone_names['middle_3_l'] + ['jbipllmiddle3', 'jlmiddle3'],
|
'middle_3_l': bone_names['middle_3_l'] + ['jbipllmiddle3', 'jlmiddle3', 'jbiplmiddle3'],
|
||||||
|
|
||||||
'ring_1_l': bone_names['ring_1_l'] + ['jbipllring1', 'jlring1'],
|
'ring_1_l': bone_names['ring_1_l'] + ['jbipllring1', 'jlring1', 'jbiplring1'],
|
||||||
'ring_2_l': bone_names['ring_2_l'] + ['jbipllring2', 'jlring2'],
|
'ring_2_l': bone_names['ring_2_l'] + ['jbipllring2', 'jlring2', 'jbiplring2'],
|
||||||
'ring_3_l': bone_names['ring_3_l'] + ['jbipllring3', 'jlring3'],
|
'ring_3_l': bone_names['ring_3_l'] + ['jbipllring3', 'jlring3', 'jbiplring3'],
|
||||||
|
|
||||||
'pinkie_1_l': bone_names['pinkie_1_l'] + ['jbipllpinky1', 'jlpinky1'],
|
'pinkie_1_l': bone_names['pinkie_1_l'] + ['jbipllpinky1', 'jlpinky1', 'jbipllittle1', 'jbipllpinkie1'],
|
||||||
'pinkie_2_l': bone_names['pinkie_2_l'] + ['jbipllpinky2', 'jlpinky2'],
|
'pinkie_2_l': bone_names['pinkie_2_l'] + ['jbipllpinky2', 'jlpinky2', 'jbipllittle2', 'jbipllpinkie2'],
|
||||||
'pinkie_3_l': bone_names['pinkie_3_l'] + ['jbipllpinky3', 'jlpinky3'],
|
'pinkie_3_l': bone_names['pinkie_3_l'] + ['jbipllpinky3', 'jlpinky3', 'jbipllittle3', 'jbipllpinkie3'],
|
||||||
|
|
||||||
# VRM fingers - Right
|
# VRM fingers - Right (including Little finger variations)
|
||||||
'thumb_1_r': bone_names['thumb_1_r'] + ['jbiprthumb1', 'jrthumb1'],
|
'thumb_1_r': bone_names['thumb_1_r'] + ['jbiprthumb1', 'jrthumb1', 'jbiprrrthumb1'],
|
||||||
'thumb_2_r': bone_names['thumb_2_r'] + ['jbiprthumb2', 'jrthumb2'],
|
'thumb_2_r': bone_names['thumb_2_r'] + ['jbiprthumb2', 'jrthumb2', 'jbiprrrthumb2'],
|
||||||
'thumb_3_r': bone_names['thumb_3_r'] + ['jbiprthumb3', 'jrthumb3'],
|
'thumb_3_r': bone_names['thumb_3_r'] + ['jbiprthumb3', 'jrthumb3', 'jbiprrrthumb3'],
|
||||||
|
|
||||||
'index_1_r': bone_names['index_1_r'] + ['jbiprindex1', 'jrindex1'],
|
'index_1_r': bone_names['index_1_r'] + ['jbiprindex1', 'jrindex1', 'jbiprrrindex1'],
|
||||||
'index_2_r': bone_names['index_2_r'] + ['jbiprindex2', 'jrindex2'],
|
'index_2_r': bone_names['index_2_r'] + ['jbiprindex2', 'jrindex2', 'jbiprrrindex2'],
|
||||||
'index_3_r': bone_names['index_3_r'] + ['jbiprindex3', 'jrindex3'],
|
'index_3_r': bone_names['index_3_r'] + ['jbiprindex3', 'jrindex3', 'jbiprrrindex3'],
|
||||||
|
|
||||||
'middle_1_r': bone_names['middle_1_r'] + ['jbiprmiddle1', 'jrmiddle1'],
|
'middle_1_r': bone_names['middle_1_r'] + ['jbiprmiddle1', 'jrmiddle1', 'jbiprrmiddle1'],
|
||||||
'middle_2_r': bone_names['middle_2_r'] + ['jbiprmiddle2', 'jrmiddle2'],
|
'middle_2_r': bone_names['middle_2_r'] + ['jbiprmiddle2', 'jrmiddle2', 'jbiprrmiddle2'],
|
||||||
'middle_3_r': bone_names['middle_3_r'] + ['jbiprmiddle3', 'jrmiddle3'],
|
'middle_3_r': bone_names['middle_3_r'] + ['jbiprmiddle3', 'jrmiddle3', 'jbiprrmiddle3'],
|
||||||
|
|
||||||
'ring_1_r': bone_names['ring_1_r'] + ['jbiprring1', 'jrring1'],
|
'ring_1_r': bone_names['ring_1_r'] + ['jbiprring1', 'jrring1', 'jbiprrrring1'],
|
||||||
'ring_2_r': bone_names['ring_2_r'] + ['jbiprring2', 'jrring2'],
|
'ring_2_r': bone_names['ring_2_r'] + ['jbiprring2', 'jrring2', 'jbiprrrring2'],
|
||||||
'ring_3_r': bone_names['ring_3_r'] + ['jbiprring3', 'jrring3'],
|
'ring_3_r': bone_names['ring_3_r'] + ['jbiprring3', 'jrring3', 'jbiprrrring3'],
|
||||||
|
|
||||||
'pinkie_1_r': bone_names['pinkie_1_r'] + ['jbiprpinky1', 'jrpinky1'],
|
'pinkie_1_r': bone_names['pinkie_1_r'] + ['jbiprpinky1', 'jrpinky1', 'jbiprlittle1', 'jbiprrrpinky1'],
|
||||||
'pinkie_2_r': bone_names['pinkie_2_r'] + ['jbiprpinky2', 'jrpinky2'],
|
'pinkie_2_r': bone_names['pinkie_2_r'] + ['jbiprpinky2', 'jrpinky2', 'jbiprlittle2', 'jbiprrrpinky2'],
|
||||||
'pinkie_3_r': bone_names['pinkie_3_r'] + ['jbiprpinky3', 'jrpinky3']
|
'pinkie_3_r': bone_names['pinkie_3_r'] + ['jbiprpinky3', 'jrpinky3', 'jbiprlittle3', 'jbiprrrpinky3']
|
||||||
})
|
})
|
||||||
|
|
||||||
# array taken from cats
|
# array taken from cats
|
||||||
@@ -426,9 +426,11 @@ standard_bones = {
|
|||||||
'head': 'Head',
|
'head': 'Head',
|
||||||
|
|
||||||
# Arms
|
# Arms
|
||||||
|
'left_shoulder': 'Shoulder.L',
|
||||||
'left_arm': 'UpperArm.L',
|
'left_arm': 'UpperArm.L',
|
||||||
'left_elbow': 'LowerArm.L',
|
'left_elbow': 'LowerArm.L',
|
||||||
'left_wrist': 'Hand.L',
|
'left_wrist': 'Hand.L',
|
||||||
|
'right_shoulder': 'Shoulder.R',
|
||||||
'right_arm': 'UpperArm.R',
|
'right_arm': 'UpperArm.R',
|
||||||
'right_elbow': 'LowerArm.R',
|
'right_elbow': 'LowerArm.R',
|
||||||
'right_wrist': 'Hand.R',
|
'right_wrist': 'Hand.R',
|
||||||
|
|||||||
@@ -615,6 +615,12 @@ class AvatarToolkitSceneProperties(PropertyGroup):
|
|||||||
default=True
|
default=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
vrm_remove_root: BoolProperty(
|
||||||
|
name="Remove Root Bone",
|
||||||
|
description="Remove unnecessary VRM root bone and make Hips the root bone",
|
||||||
|
default=True
|
||||||
|
)
|
||||||
|
|
||||||
def register() -> None:
|
def register() -> None:
|
||||||
"""Register the Avatar Toolkit property group"""
|
"""Register the Avatar Toolkit property group"""
|
||||||
logger.info("Registering Avatar Toolkit properties")
|
logger.info("Registering Avatar Toolkit properties")
|
||||||
|
|||||||
+271
-35
@@ -15,10 +15,24 @@ def detect_vrm_armature(armature: Object) -> bool:
|
|||||||
|
|
||||||
vrm_patterns = [
|
vrm_patterns = [
|
||||||
'jbipchips', 'jbipcspine', 'jbipcchest', 'jbipcneck', 'jbipchead',
|
'jbipchips', 'jbipcspine', 'jbipcchest', 'jbipcneck', 'jbipchead',
|
||||||
'jbiprlshoulder', 'jbiprrupperarm', 'jbiprrforearm', 'jbiprrhand',
|
# Right arm patterns (both single and double R)
|
||||||
'jbipllshoulder', 'jbiplupperarm', 'jbipllforearm', 'jbipllhand',
|
'jbiprlshoulder', 'jbiprshoulder', 'jbiprupperarm', 'jbiprforearm', 'jbiprhand', 'jbiprlowerarm',
|
||||||
|
'jbiprrupperarm', 'jbiprrforearm', 'jbiprrhand',
|
||||||
|
# Left arm patterns
|
||||||
|
'jbipllshoulder', 'jbiplshoulder', 'jbiplupperarm', 'jbipllforearm', 'jbipllhand', 'jbipllowerarm', 'jbiplhand',
|
||||||
|
# Right leg patterns (both single and double R)
|
||||||
|
'jbiprupperleg', 'jbiprlowerleg', 'jbiprfoot', 'jbiprtoe', 'jbiprtoebase',
|
||||||
'jbiprrupperleg', 'jbiprrlowerleg', 'jbiprrfoot', 'jbiprrtoe',
|
'jbiprrupperleg', 'jbiprrlowerleg', 'jbiprrfoot', 'jbiprrtoe',
|
||||||
'jbiplupperleg', 'jbipllowerleg', 'jbipllfoot', 'jbiplltoe',
|
# Left leg patterns
|
||||||
|
'jbiplupperleg', 'jbipllowerleg', 'jbipllfoot', 'jbiplfoot', 'jbiplltoe', 'jbipltoebase',
|
||||||
|
# Finger patterns
|
||||||
|
'jbipllittle1', 'jbiprlittle1',
|
||||||
|
'jbiplthumb1', 'jbiplthumb2', 'jbiplthumb3',
|
||||||
|
'jbiplindex1', 'jbiplindex2', 'jbiplindex3',
|
||||||
|
'jbiplmiddle1', 'jbiplmiddle2', 'jbiplmiddle3',
|
||||||
|
'jbiplring1', 'jbiplring2', 'jbiplring3',
|
||||||
|
# Face eye patterns
|
||||||
|
'jadjlfaceeye', 'jadjrfaceeye',
|
||||||
'jbipc', 'jbipr', 'jbipl'
|
'jbipc', 'jbipr', 'jbipl'
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -48,81 +62,132 @@ def get_vrm_to_unity_mapping() -> Dict[str, str]:
|
|||||||
|
|
||||||
# Left arm
|
# Left arm
|
||||||
'jbipllshoulder': standard_bones.get('left_shoulder', 'LeftShoulder'),
|
'jbipllshoulder': standard_bones.get('left_shoulder', 'LeftShoulder'),
|
||||||
|
'jbiplshoulder': standard_bones.get('left_shoulder', 'LeftShoulder'),
|
||||||
'jbiplupperarm': standard_bones['left_arm'],
|
'jbiplupperarm': standard_bones['left_arm'],
|
||||||
'jbipllforearm': standard_bones['left_elbow'],
|
'jbipllforearm': standard_bones['left_elbow'],
|
||||||
|
'jbipllowerarm': standard_bones['left_elbow'],
|
||||||
'jbipllhand': standard_bones['left_wrist'],
|
'jbipllhand': standard_bones['left_wrist'],
|
||||||
|
'jbiplhand': standard_bones['left_wrist'],
|
||||||
|
|
||||||
# Right arm
|
# Right arm (both jbipr and jbiprr patterns)
|
||||||
'jbiprlshoulder': standard_bones.get('right_shoulder', 'RightShoulder'),
|
'jbiprlshoulder': standard_bones.get('right_shoulder', 'RightShoulder'),
|
||||||
|
'jbiprshoulder': standard_bones.get('right_shoulder', 'RightShoulder'),
|
||||||
|
'jbiprrshoulder': standard_bones.get('right_shoulder', 'RightShoulder'),
|
||||||
|
'jbiprupperarm': standard_bones['right_arm'],
|
||||||
'jbiprrupperarm': standard_bones['right_arm'],
|
'jbiprrupperarm': standard_bones['right_arm'],
|
||||||
|
'jbiprforearm': standard_bones['right_elbow'],
|
||||||
'jbiprrforearm': standard_bones['right_elbow'],
|
'jbiprrforearm': standard_bones['right_elbow'],
|
||||||
|
'jbiprlowerarm': standard_bones['right_elbow'],
|
||||||
|
'jbiprhand': standard_bones['right_wrist'],
|
||||||
'jbiprrhand': standard_bones['right_wrist'],
|
'jbiprrhand': standard_bones['right_wrist'],
|
||||||
|
|
||||||
# Left leg
|
# Left leg
|
||||||
'jbiplupperleg': standard_bones['left_leg'],
|
'jbiplupperleg': standard_bones['left_leg'],
|
||||||
'jbipllowerleg': standard_bones['left_knee'],
|
'jbipllowerleg': standard_bones['left_knee'],
|
||||||
'jbipllfoot': standard_bones['left_ankle'],
|
'jbipllfoot': standard_bones['left_ankle'],
|
||||||
|
'jbiplfoot': standard_bones['left_ankle'],
|
||||||
'jbiplltoe': standard_bones['left_toe'],
|
'jbiplltoe': standard_bones['left_toe'],
|
||||||
|
'jbipltoebase': standard_bones['left_toe'],
|
||||||
|
|
||||||
# Right leg
|
# Right leg (both jbipr and jbiprr patterns)
|
||||||
|
'jbiprupperleg': standard_bones['right_leg'],
|
||||||
'jbiprrupperleg': standard_bones['right_leg'],
|
'jbiprrupperleg': standard_bones['right_leg'],
|
||||||
|
'jbiprlowerleg': standard_bones['right_knee'],
|
||||||
'jbiprrlowerleg': standard_bones['right_knee'],
|
'jbiprrlowerleg': standard_bones['right_knee'],
|
||||||
|
'jbiprfoot': standard_bones['right_ankle'],
|
||||||
'jbiprrfoot': standard_bones['right_ankle'],
|
'jbiprrfoot': standard_bones['right_ankle'],
|
||||||
|
'jbiprtoe': standard_bones['right_toe'],
|
||||||
'jbiprrtoe': standard_bones['right_toe'],
|
'jbiprrtoe': standard_bones['right_toe'],
|
||||||
|
'jbiprtoebase': standard_bones['right_toe'],
|
||||||
|
|
||||||
# Eyes
|
# Eyes
|
||||||
'jbipcleye': standard_bones.get('left_eye', 'Eye.L'),
|
'jbipcleye': standard_bones.get('left_eye', 'Eye.L'),
|
||||||
'jbipcreye': standard_bones.get('right_eye', 'Eye.R'),
|
'jbipcreye': standard_bones.get('right_eye', 'Eye.R'),
|
||||||
|
'jadjlfaceeye': standard_bones.get('left_eye', 'Eye.L'),
|
||||||
|
'jadjrfaceeye': standard_bones.get('right_eye', 'Eye.R'),
|
||||||
|
|
||||||
# Fingers - Left thumb
|
# Fingers - Left thumb
|
||||||
'jbipllthumb1': standard_bones.get('thumb_1_l', 'Thumb1.L'),
|
'jbipllthumb1': standard_bones.get('thumb_1_l', 'Thumb1.L'),
|
||||||
'jbipllthumb2': standard_bones.get('thumb_2_l', 'Thumb2.L'),
|
'jbipllthumb2': standard_bones.get('thumb_2_l', 'Thumb2.L'),
|
||||||
'jbipllthumb3': standard_bones.get('thumb_3_l', 'Thumb3.L'),
|
'jbipllthumb3': standard_bones.get('thumb_3_l', 'Thumb3.L'),
|
||||||
|
'jbiplthumb1': standard_bones.get('thumb_1_l', 'Thumb1.L'),
|
||||||
|
'jbiplthumb2': standard_bones.get('thumb_2_l', 'Thumb2.L'),
|
||||||
|
'jbiplthumb3': standard_bones.get('thumb_3_l', 'Thumb3.L'),
|
||||||
|
|
||||||
# Fingers - Left index
|
# Fingers - Left index
|
||||||
'jbipllindex1': standard_bones.get('index_1_l', 'Index1.L'),
|
'jbipllindex1': standard_bones.get('index_1_l', 'Index1.L'),
|
||||||
'jbipllindex2': standard_bones.get('index_2_l', 'Index2.L'),
|
'jbipllindex2': standard_bones.get('index_2_l', 'Index2.L'),
|
||||||
'jbipllindex3': standard_bones.get('index_3_l', 'Index3.L'),
|
'jbipllindex3': standard_bones.get('index_3_l', 'Index3.L'),
|
||||||
|
'jbiplindex1': standard_bones.get('index_1_l', 'Index1.L'),
|
||||||
|
'jbiplindex2': standard_bones.get('index_2_l', 'Index2.L'),
|
||||||
|
'jbiplindex3': standard_bones.get('index_3_l', 'Index3.L'),
|
||||||
|
|
||||||
# Fingers - Left middle
|
# Fingers - Left middle
|
||||||
'jbipllmiddle1': standard_bones.get('middle_1_l', 'Middle1.L'),
|
'jbipllmiddle1': standard_bones.get('middle_1_l', 'Middle1.L'),
|
||||||
'jbipllmiddle2': standard_bones.get('middle_2_l', 'Middle2.L'),
|
'jbipllmiddle2': standard_bones.get('middle_2_l', 'Middle2.L'),
|
||||||
'jbipllmiddle3': standard_bones.get('middle_3_l', 'Middle3.L'),
|
'jbipllmiddle3': standard_bones.get('middle_3_l', 'Middle3.L'),
|
||||||
|
'jbiplmiddle1': standard_bones.get('middle_1_l', 'Middle1.L'),
|
||||||
|
'jbiplmiddle2': standard_bones.get('middle_2_l', 'Middle2.L'),
|
||||||
|
'jbiplmiddle3': standard_bones.get('middle_3_l', 'Middle3.L'),
|
||||||
|
|
||||||
# Fingers - Left ring
|
# Fingers - Left ring
|
||||||
'jbipllring1': standard_bones.get('ring_1_l', 'Ring1.L'),
|
'jbipllring1': standard_bones.get('ring_1_l', 'Ring1.L'),
|
||||||
'jbipllring2': standard_bones.get('ring_2_l', 'Ring2.L'),
|
'jbipllring2': standard_bones.get('ring_2_l', 'Ring2.L'),
|
||||||
'jbipllring3': standard_bones.get('ring_3_l', 'Ring3.L'),
|
'jbipllring3': standard_bones.get('ring_3_l', 'Ring3.L'),
|
||||||
|
'jbiplring1': standard_bones.get('ring_1_l', 'Ring1.L'),
|
||||||
|
'jbiplring2': standard_bones.get('ring_2_l', 'Ring2.L'),
|
||||||
|
'jbiplring3': standard_bones.get('ring_3_l', 'Ring3.L'),
|
||||||
|
|
||||||
# Fingers - Left pinky
|
# Fingers - Left pinky
|
||||||
'jbipllpinky1': standard_bones.get('pinkie_1_l', 'Pinky1.L'),
|
'jbipllpinky1': standard_bones.get('pinkie_1_l', 'Pinky1.L'),
|
||||||
'jbipllpinky2': standard_bones.get('pinkie_2_l', 'Pinky2.L'),
|
'jbipllpinky2': standard_bones.get('pinkie_2_l', 'Pinky2.L'),
|
||||||
'jbipllpinky3': standard_bones.get('pinkie_3_l', 'Pinky3.L'),
|
'jbipllpinky3': standard_bones.get('pinkie_3_l', 'Pinky3.L'),
|
||||||
|
'jbipllittle1': standard_bones.get('pinkie_1_l', 'Pinky1.L'),
|
||||||
|
'jbipllittle2': standard_bones.get('pinkie_2_l', 'Pinky2.L'),
|
||||||
|
'jbipllittle3': standard_bones.get('pinkie_3_l', 'Pinky3.L'),
|
||||||
|
|
||||||
# Fingers - Right thumb
|
# Fingers - Right thumb (both jbipr and jbiprr patterns)
|
||||||
'jbiprthumb1': standard_bones.get('thumb_1_r', 'Thumb1.R'),
|
'jbiprthumb1': standard_bones.get('thumb_1_r', 'Thumb1.R'),
|
||||||
'jbiprthumb2': standard_bones.get('thumb_2_r', 'Thumb2.R'),
|
'jbiprthumb2': standard_bones.get('thumb_2_r', 'Thumb2.R'),
|
||||||
'jbiprthumb3': standard_bones.get('thumb_3_r', 'Thumb3.R'),
|
'jbiprthumb3': standard_bones.get('thumb_3_r', 'Thumb3.R'),
|
||||||
|
'jbiprrrthumb1': standard_bones.get('thumb_1_r', 'Thumb1.R'),
|
||||||
|
'jbiprrrthumb2': standard_bones.get('thumb_2_r', 'Thumb2.R'),
|
||||||
|
'jbiprrrthumb3': standard_bones.get('thumb_3_r', 'Thumb3.R'),
|
||||||
|
|
||||||
# Fingers - Right index
|
# Fingers - Right index
|
||||||
'jbiprindex1': standard_bones.get('index_1_r', 'Index1.R'),
|
'jbiprindex1': standard_bones.get('index_1_r', 'Index1.R'),
|
||||||
'jbiprindex2': standard_bones.get('index_2_r', 'Index2.R'),
|
'jbiprindex2': standard_bones.get('index_2_r', 'Index2.R'),
|
||||||
'jbiprindex3': standard_bones.get('index_3_r', 'Index3.R'),
|
'jbiprindex3': standard_bones.get('index_3_r', 'Index3.R'),
|
||||||
|
'jbiprrrindex1': standard_bones.get('index_1_r', 'Index1.R'),
|
||||||
|
'jbiprrrindex2': standard_bones.get('index_2_r', 'Index2.R'),
|
||||||
|
'jbiprrrindex3': standard_bones.get('index_3_r', 'Index3.R'),
|
||||||
|
|
||||||
# Fingers - Right middle
|
# Fingers - Right middle
|
||||||
'jbiprmiddle1': standard_bones.get('middle_1_r', 'Middle1.R'),
|
'jbiprmiddle1': standard_bones.get('middle_1_r', 'Middle1.R'),
|
||||||
'jbiprmiddle2': standard_bones.get('middle_2_r', 'Middle2.R'),
|
'jbiprmiddle2': standard_bones.get('middle_2_r', 'Middle2.R'),
|
||||||
'jbiprmiddle3': standard_bones.get('middle_3_r', 'Middle3.R'),
|
'jbiprmiddle3': standard_bones.get('middle_3_r', 'Middle3.R'),
|
||||||
|
'jbiprrmiddle1': standard_bones.get('middle_1_r', 'Middle1.R'),
|
||||||
|
'jbiprrmiddle2': standard_bones.get('middle_2_r', 'Middle2.R'),
|
||||||
|
'jbiprrmiddle3': standard_bones.get('middle_3_r', 'Middle3.R'),
|
||||||
|
|
||||||
# Fingers - Right ring
|
# Fingers - Right ring
|
||||||
'jbiprring1': standard_bones.get('ring_1_r', 'Ring1.R'),
|
'jbiprring1': standard_bones.get('ring_1_r', 'Ring1.R'),
|
||||||
'jbiprring2': standard_bones.get('ring_2_r', 'Ring2.R'),
|
'jbiprring2': standard_bones.get('ring_2_r', 'Ring2.R'),
|
||||||
'jbiprring3': standard_bones.get('ring_3_r', 'Ring3.R'),
|
'jbiprring3': standard_bones.get('ring_3_r', 'Ring3.R'),
|
||||||
|
'jbiprrrring1': standard_bones.get('ring_1_r', 'Ring1.R'),
|
||||||
|
'jbiprrrring2': standard_bones.get('ring_2_r', 'Ring2.R'),
|
||||||
|
'jbiprrrring3': standard_bones.get('ring_3_r', 'Ring3.R'),
|
||||||
|
|
||||||
# Fingers - Right pinky
|
# Fingers - Right pinky
|
||||||
'jbiprpinky1': standard_bones.get('pinkie_1_r', 'Pinky1.R'),
|
'jbiprpinky1': standard_bones.get('pinkie_1_r', 'Pinky1.R'),
|
||||||
'jbiprpinky2': standard_bones.get('pinkie_2_r', 'Pinky2.R'),
|
'jbiprpinky2': standard_bones.get('pinkie_2_r', 'Pinky2.R'),
|
||||||
'jbiprpinky3': standard_bones.get('pinkie_3_r', 'Pinky3.R'),
|
'jbiprpinky3': standard_bones.get('pinkie_3_r', 'Pinky3.R'),
|
||||||
|
'jbiprrrpinky1': standard_bones.get('pinkie_1_r', 'Pinky1.R'),
|
||||||
|
'jbiprrrpinky2': standard_bones.get('pinkie_2_r', 'Pinky2.R'),
|
||||||
|
'jbiprrrpinky3': standard_bones.get('pinkie_3_r', 'Pinky3.R'),
|
||||||
|
'jbiprlittle1': standard_bones.get('pinkie_1_r', 'Pinky1.R'),
|
||||||
|
'jbiprlittle2': standard_bones.get('pinkie_2_r', 'Pinky2.R'),
|
||||||
|
'jbiprlittle3': standard_bones.get('pinkie_3_r', 'Pinky3.R'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -168,32 +233,69 @@ def guess_unity_name_from_vrm(vrm_simplified: str) -> Optional[str]:
|
|||||||
# Left arm
|
# Left arm
|
||||||
'jbipllclavicle': 'LeftShoulder',
|
'jbipllclavicle': 'LeftShoulder',
|
||||||
'jbipllshoulder': 'LeftShoulder',
|
'jbipllshoulder': 'LeftShoulder',
|
||||||
|
'jbiplshoulder': 'LeftShoulder',
|
||||||
'jbiplupperarm': 'LeftUpperArm',
|
'jbiplupperarm': 'LeftUpperArm',
|
||||||
'jbipllforearm': 'LeftLowerArm',
|
'jbipllforearm': 'LeftLowerArm',
|
||||||
|
'jbipllowerarm': 'LeftLowerArm',
|
||||||
'jbipllhand': 'LeftHand',
|
'jbipllhand': 'LeftHand',
|
||||||
|
'jbiplhand': 'LeftHand',
|
||||||
|
|
||||||
# Right arm
|
# Right arm (both single and double R patterns)
|
||||||
'jbiprrclavicle': 'RightShoulder',
|
'jbiprrclavicle': 'RightShoulder',
|
||||||
'jbiprlshoulder': 'RightShoulder',
|
'jbiprlshoulder': 'RightShoulder',
|
||||||
|
'jbiprshoulder': 'RightShoulder',
|
||||||
|
'jbiprupperarm': 'RightUpperArm',
|
||||||
'jbiprrupperarm': 'RightUpperArm',
|
'jbiprrupperarm': 'RightUpperArm',
|
||||||
|
'jbiprforearm': 'RightLowerArm',
|
||||||
'jbiprrforearm': 'RightLowerArm',
|
'jbiprrforearm': 'RightLowerArm',
|
||||||
|
'jbiprlowerarm': 'RightLowerArm',
|
||||||
|
'jbiprhand': 'RightHand',
|
||||||
'jbiprrhand': 'RightHand',
|
'jbiprrhand': 'RightHand',
|
||||||
|
|
||||||
# Left leg
|
# Left leg
|
||||||
'jbiplupperleg': 'LeftUpperLeg',
|
'jbiplupperleg': 'LeftUpperLeg',
|
||||||
'jbipllowerleg': 'LeftLowerLeg',
|
'jbipllowerleg': 'LeftLowerLeg',
|
||||||
'jbipllfoot': 'LeftFoot',
|
'jbipllfoot': 'LeftFoot',
|
||||||
|
'jbiplfoot': 'LeftFoot',
|
||||||
'jbiplltoe': 'LeftToes',
|
'jbiplltoe': 'LeftToes',
|
||||||
|
'jbipltoebase': 'LeftToes',
|
||||||
|
|
||||||
# Right leg
|
# Right leg (both single and double R patterns)
|
||||||
|
'jbiprupperleg': 'RightUpperLeg',
|
||||||
'jbiprrupperleg': 'RightUpperLeg',
|
'jbiprrupperleg': 'RightUpperLeg',
|
||||||
|
'jbiprlowerleg': 'RightLowerLeg',
|
||||||
'jbiprrlowerleg': 'RightLowerLeg',
|
'jbiprrlowerleg': 'RightLowerLeg',
|
||||||
|
'jbiprfoot': 'RightFoot',
|
||||||
'jbiprrfoot': 'RightFoot',
|
'jbiprrfoot': 'RightFoot',
|
||||||
|
'jbiprtoe': 'RightToes',
|
||||||
'jbiprrtoe': 'RightToes',
|
'jbiprrtoe': 'RightToes',
|
||||||
|
'jbiprtoebase': 'RightToes',
|
||||||
|
|
||||||
# Eyes
|
# Eyes
|
||||||
'jbipcleye': 'LeftEye',
|
'jbipcleye': 'LeftEye',
|
||||||
'jbipcreye': 'RightEye'
|
'jbipcreye': 'RightEye',
|
||||||
|
'jadjlfaceeye': 'LeftEye',
|
||||||
|
'jadjrfaceeye': 'RightEye',
|
||||||
|
|
||||||
|
# Fingers - Left
|
||||||
|
'jbiplthumb1': 'LeftThumb1',
|
||||||
|
'jbiplthumb2': 'LeftThumb2',
|
||||||
|
'jbiplthumb3': 'LeftThumb3',
|
||||||
|
'jbiplindex1': 'LeftIndex1',
|
||||||
|
'jbiplindex2': 'LeftIndex2',
|
||||||
|
'jbiplindex3': 'LeftIndex3',
|
||||||
|
'jbiplmiddle1': 'LeftMiddle1',
|
||||||
|
'jbiplmiddle2': 'LeftMiddle2',
|
||||||
|
'jbiplmiddle3': 'LeftMiddle3',
|
||||||
|
'jbiplring1': 'LeftRing1',
|
||||||
|
'jbiplring2': 'LeftRing2',
|
||||||
|
'jbiplring3': 'LeftRing3',
|
||||||
|
'jbipllittle1': 'LeftPinky1',
|
||||||
|
'jbipllittle2': 'LeftPinky2',
|
||||||
|
'jbipllittle3': 'LeftPinky3',
|
||||||
|
'jbiprlittle1': 'RightPinky1',
|
||||||
|
'jbiprlittle2': 'RightPinky2',
|
||||||
|
'jbiprlittle3': 'RightPinky3'
|
||||||
}
|
}
|
||||||
|
|
||||||
return pattern_mappings.get(vrm_simplified)
|
return pattern_mappings.get(vrm_simplified)
|
||||||
@@ -221,10 +323,40 @@ def is_vrm_collider_object(obj_name: str) -> bool:
|
|||||||
return is_vrm
|
return is_vrm
|
||||||
|
|
||||||
|
|
||||||
def remove_vrm_colliders(armature: Object = None) -> Tuple[int, List[str]]:
|
def remove_collection_from_hierarchy(collection_to_remove) -> bool:
|
||||||
|
"""
|
||||||
|
Recursively remove a collection from all parent collections in the hierarchy
|
||||||
|
"""
|
||||||
|
removed_from_any_parent = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Check scene collection
|
||||||
|
scene_collection = bpy.context.scene.collection
|
||||||
|
if collection_to_remove in scene_collection.children:
|
||||||
|
scene_collection.children.unlink(collection_to_remove)
|
||||||
|
logger.debug(f" Unlinked '{collection_to_remove.name}' from scene collection")
|
||||||
|
removed_from_any_parent = True
|
||||||
|
|
||||||
|
# Check all other collections recursively
|
||||||
|
for parent_collection in list(bpy.data.collections):
|
||||||
|
if parent_collection != collection_to_remove and collection_to_remove in parent_collection.children:
|
||||||
|
try:
|
||||||
|
parent_collection.children.unlink(collection_to_remove)
|
||||||
|
logger.debug(f" Unlinked '{collection_to_remove.name}' from parent '{parent_collection.name}'")
|
||||||
|
removed_from_any_parent = True
|
||||||
|
except Exception as unlink_error:
|
||||||
|
logger.warning(f" Failed to unlink '{collection_to_remove.name}' from '{parent_collection.name}': {str(unlink_error)}")
|
||||||
|
|
||||||
|
return removed_from_any_parent
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error removing collection '{collection_to_remove.name}' from hierarchy: {str(e)}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def remove_vrm_colliders(armature: Object = None) -> Tuple[int, List[str], int]:
|
||||||
"""
|
"""
|
||||||
Simple approach: Remove ALL objects with 'collider' in their name and clean up empty collections
|
Simple approach: Remove ALL objects with 'collider' in their name and clean up empty collections
|
||||||
Returns tuple of (removed_count, removed_object_names)
|
|
||||||
"""
|
"""
|
||||||
objects_to_remove = []
|
objects_to_remove = []
|
||||||
removed_names = []
|
removed_names = []
|
||||||
@@ -279,34 +411,59 @@ def remove_vrm_colliders(armature: Object = None) -> Tuple[int, List[str]]:
|
|||||||
|
|
||||||
logger.info(f"Successfully removed {removed_count} collider objects")
|
logger.info(f"Successfully removed {removed_count} collider objects")
|
||||||
|
|
||||||
# Clean up empty collections
|
# Clean up empty collections (prioritize collider-related collections)
|
||||||
empty_collections_removed = 0
|
empty_collections_removed = 0
|
||||||
for collection in list(collections_to_check):
|
|
||||||
|
# Also check all collections in the scene for collider-related names
|
||||||
|
all_collections_to_check = set(collections_to_check)
|
||||||
|
for collection in bpy.data.collections:
|
||||||
|
collection_name_lower = collection.name.lower()
|
||||||
|
if any(pattern in collection_name_lower for pattern in ['collider', 'collision', 'physics', 'dynamic']):
|
||||||
|
all_collections_to_check.add(collection)
|
||||||
|
logger.debug(f"Found collider-related collection to check: {collection.name}")
|
||||||
|
|
||||||
|
for collection in list(all_collections_to_check):
|
||||||
try:
|
try:
|
||||||
# Check if collection is now empty and not the master collection
|
# Check if collection exists and is empty
|
||||||
if (len(collection.objects) == 0 and
|
if collection.name not in bpy.data.collections:
|
||||||
len(collection.children) == 0 and
|
logger.debug(f"Collection {collection.name} already removed")
|
||||||
collection.name != "Collection" and
|
continue
|
||||||
collection.name != "Master Collection"):
|
|
||||||
|
|
||||||
logger.info(f"Removing empty collection: {collection.name}")
|
collection_name_lower = collection.name.lower()
|
||||||
|
is_collider_collection = any(pattern in collection_name_lower for pattern in ['collider', 'collision', 'physics', 'dynamic'])
|
||||||
|
is_empty = len(collection.objects) == 0 and len(collection.children) == 0
|
||||||
|
is_protected = collection.name in ["Collection", "Master Collection"]
|
||||||
|
|
||||||
if collection in bpy.context.scene.collection.children:
|
# Remove if empty and (was used by colliders OR has collider-related name)
|
||||||
bpy.context.scene.collection.children.unlink(collection)
|
if is_empty and not is_protected and (collection in collections_to_check or is_collider_collection):
|
||||||
|
logger.info(f"Removing empty {'collider-related ' if is_collider_collection else ''}collection: {collection.name}")
|
||||||
|
|
||||||
bpy.data.collections.remove(collection)
|
# Use helper function to remove from all parent collections
|
||||||
empty_collections_removed += 1
|
removed_from_parents = remove_collection_from_hierarchy(collection)
|
||||||
logger.info(f" Successfully removed collection: {collection.name}")
|
|
||||||
|
if not removed_from_parents:
|
||||||
|
logger.debug(f" Collection {collection.name} was not found in any parent collections")
|
||||||
|
|
||||||
|
# Remove the collection data
|
||||||
|
try:
|
||||||
|
bpy.data.collections.remove(collection)
|
||||||
|
empty_collections_removed += 1
|
||||||
|
logger.info(f" Successfully removed collection: {collection.name}")
|
||||||
|
except Exception as remove_error:
|
||||||
|
logger.warning(f" Failed to remove collection {collection.name}: {str(remove_error)}")
|
||||||
|
# Continue with other collections even if this one fails
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Failed to remove empty collection {collection.name}: {str(e)}")
|
logger.warning(f"Failed to remove empty collection {collection.name}: {str(e)}")
|
||||||
|
import traceback
|
||||||
|
logger.debug(f"Collection removal traceback: {traceback.format_exc()}")
|
||||||
|
|
||||||
if empty_collections_removed > 0:
|
if empty_collections_removed > 0:
|
||||||
logger.info(f"Cleaned up {empty_collections_removed} empty collections")
|
logger.info(f"Cleaned up {empty_collections_removed} empty collections")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error during collider removal: {str(e)}")
|
logger.error(f"Error during collider removal: {str(e)}")
|
||||||
return 0, []
|
return 0, [], 0
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
if original_active and original_active.name in bpy.data.objects:
|
if original_active and original_active.name in bpy.data.objects:
|
||||||
@@ -318,16 +475,85 @@ def remove_vrm_colliders(armature: Object = None) -> Tuple[int, List[str]]:
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
logger.info(f"Collider removal complete. Removed {len(removed_names)} objects")
|
logger.info(f"Collider removal complete. Removed {len(removed_names)} objects and {empty_collections_removed} collections")
|
||||||
return len(removed_names), removed_names
|
return len(removed_names), removed_names, empty_collections_removed
|
||||||
|
|
||||||
|
|
||||||
def convert_vrm_to_unity(armature: Object, remove_colliders: bool = True) -> Tuple[bool, List[str], int]:
|
def remove_vrm_root_bone(armature: Object) -> Tuple[bool, str]:
|
||||||
|
"""
|
||||||
|
Remove unnecessary VRM root bone and make Hips the root bone
|
||||||
|
|
||||||
|
"""
|
||||||
|
if not armature or armature.type != 'ARMATURE':
|
||||||
|
return False, "No valid armature provided"
|
||||||
|
|
||||||
|
# Look for potential root bones and Hips bone
|
||||||
|
potential_roots = []
|
||||||
|
hips_bone = None
|
||||||
|
|
||||||
|
for bone in armature.data.edit_bones:
|
||||||
|
bone_name_lower = bone.name.lower()
|
||||||
|
|
||||||
|
# Check if this could be Hips (various naming conventions)
|
||||||
|
if any(hips_name in bone_name_lower for hips_name in ['hips', 'hip', 'pelvis', 'jbipchips']):
|
||||||
|
hips_bone = bone
|
||||||
|
logger.debug(f"Found Hips bone: {bone.name}")
|
||||||
|
|
||||||
|
# Check if this could be a root bone
|
||||||
|
if bone.parent is None and len(bone.children) > 0:
|
||||||
|
# Common VRM root bone names
|
||||||
|
if any(root_name in bone_name_lower for root_name in ['root', 'vrm', 'armature', 'rig']):
|
||||||
|
potential_roots.append(bone)
|
||||||
|
logger.debug(f"Found potential root bone: {bone.name}")
|
||||||
|
|
||||||
|
if not hips_bone:
|
||||||
|
return False, "Could not find Hips bone to promote as root"
|
||||||
|
|
||||||
|
if not potential_roots:
|
||||||
|
logger.info("No unnecessary root bone found - Hips may already be root")
|
||||||
|
return True, "No root bone removal needed"
|
||||||
|
|
||||||
|
# Find the root bone that is the parent of Hips
|
||||||
|
root_to_remove = None
|
||||||
|
for root_bone in potential_roots:
|
||||||
|
if hips_bone.parent == root_bone:
|
||||||
|
root_to_remove = root_bone
|
||||||
|
break
|
||||||
|
|
||||||
|
if not root_to_remove:
|
||||||
|
# Check if Hips is already parentless (already root)
|
||||||
|
if hips_bone.parent is None:
|
||||||
|
logger.info("Hips bone is already the root bone")
|
||||||
|
return True, "Hips is already root - no changes needed"
|
||||||
|
else:
|
||||||
|
logger.warning(f"Hips bone has parent '{hips_bone.parent.name}' but no matching root found")
|
||||||
|
return False, "Could not identify safe root bone to remove"
|
||||||
|
|
||||||
|
root_name = root_to_remove.name
|
||||||
|
logger.info(f"Removing root bone '{root_name}' and promoting Hips to root")
|
||||||
|
|
||||||
|
# Reparent all children of the root bone (except Hips) to Hips
|
||||||
|
children_to_reparent = []
|
||||||
|
for child in root_to_remove.children:
|
||||||
|
if child != hips_bone:
|
||||||
|
children_to_reparent.append(child)
|
||||||
|
)
|
||||||
|
hips_bone.parent = None
|
||||||
|
|
||||||
|
for child in children_to_reparent:
|
||||||
|
child.parent = hips_bone
|
||||||
|
logger.debug(f"Reparented {child.name} from {root_name} to {hips_bone.name}")
|
||||||
|
|
||||||
|
armature.data.edit_bones.remove(root_to_remove)
|
||||||
|
|
||||||
|
message = f"Removed root bone '{root_name}' - Hips is now the root bone"
|
||||||
|
logger.info(message)
|
||||||
|
return True, message
|
||||||
|
|
||||||
|
|
||||||
|
def convert_vrm_to_unity(armature: Object, remove_colliders: bool = True, remove_root: bool = True) -> Tuple[bool, List[str], int]:
|
||||||
"""
|
"""
|
||||||
Convert VRM armature bone names to Unity humanoid format
|
Convert VRM armature bone names to Unity humanoid format
|
||||||
|
|
||||||
Returns:
|
|
||||||
Tuple of (success, messages, converted_count)
|
|
||||||
"""
|
"""
|
||||||
if not armature or armature.type != 'ARMATURE':
|
if not armature or armature.type != 'ARMATURE':
|
||||||
return False, ["No valid armature selected"], 0
|
return False, ["No valid armature selected"], 0
|
||||||
@@ -351,15 +577,18 @@ def convert_vrm_to_unity(armature: Object, remove_colliders: bool = True) -> Tup
|
|||||||
try:
|
try:
|
||||||
# First, remove collider objects and bones if requested
|
# First, remove collider objects and bones if requested
|
||||||
if remove_colliders:
|
if remove_colliders:
|
||||||
collider_count, removed_colliders = remove_vrm_colliders(armature)
|
collider_count, removed_colliders, collections_removed = remove_vrm_colliders(armature)
|
||||||
if collider_count > 0:
|
if collider_count > 0 or collections_removed > 0:
|
||||||
messages.append(f"Removed {collider_count} VRM collider objects/bones")
|
if collections_removed > 0:
|
||||||
|
messages.append(f"Removed {collider_count} VRM collider objects and {collections_removed} empty collections")
|
||||||
|
else:
|
||||||
|
messages.append(f"Removed {collider_count} VRM collider objects")
|
||||||
logger.info(f"Removed {collider_count} VRM colliders: {removed_colliders}")
|
logger.info(f"Removed {collider_count} VRM colliders: {removed_colliders}")
|
||||||
|
|
||||||
vrm_bones = find_vrm_bones_in_armature(armature)
|
vrm_bones = find_vrm_bones_in_armature(armature)
|
||||||
|
|
||||||
if not vrm_bones:
|
if not vrm_bones:
|
||||||
if remove_colliders and collider_count > 0:
|
if remove_colliders and (collider_count > 0 or collections_removed > 0):
|
||||||
messages.append("No VRM bones found to convert (colliders were removed)")
|
messages.append("No VRM bones found to convert (colliders were removed)")
|
||||||
return True, messages, 0
|
return True, messages, 0
|
||||||
else:
|
else:
|
||||||
@@ -368,6 +597,13 @@ def convert_vrm_to_unity(armature: Object, remove_colliders: bool = True) -> Tup
|
|||||||
if bpy.context.mode != 'EDIT':
|
if bpy.context.mode != 'EDIT':
|
||||||
bpy.ops.object.mode_set(mode='EDIT')
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
|
|
||||||
|
# Remove unnecessary root bone if requested
|
||||||
|
if remove_root:
|
||||||
|
root_success, root_message = remove_vrm_root_bone(armature)
|
||||||
|
messages.append(root_message)
|
||||||
|
if not root_success:
|
||||||
|
logger.warning(f"Root bone removal failed: {root_message}")
|
||||||
|
|
||||||
# Rename bones
|
# Rename bones
|
||||||
for vrm_bone_name, unity_name in vrm_bones.items():
|
for vrm_bone_name, unity_name in vrm_bones.items():
|
||||||
if vrm_bone_name in armature.data.edit_bones:
|
if vrm_bone_name in armature.data.edit_bones:
|
||||||
|
|||||||
@@ -28,9 +28,11 @@ class AvatarToolkit_OT_ConvertVRMToUnity(Operator):
|
|||||||
|
|
||||||
logger.info(f"Starting VRM to Unity conversion for armature: {armature.name}")
|
logger.info(f"Starting VRM to Unity conversion for armature: {armature.name}")
|
||||||
|
|
||||||
# Get collider removal setting
|
# Get conversion settings
|
||||||
remove_colliders = context.scene.avatar_toolkit.vrm_remove_colliders
|
remove_colliders = context.scene.avatar_toolkit.vrm_remove_colliders
|
||||||
|
remove_root = context.scene.avatar_toolkit.vrm_remove_root
|
||||||
logger.info(f"Collider removal setting: {remove_colliders}")
|
logger.info(f"Collider removal setting: {remove_colliders}")
|
||||||
|
logger.info(f"Root bone removal setting: {remove_root}")
|
||||||
|
|
||||||
# Log all objects with 'collider' in name for debugging
|
# Log all objects with 'collider' in name for debugging
|
||||||
collider_objects = [obj.name for obj in bpy.data.objects if 'collider' in obj.name.lower()]
|
collider_objects = [obj.name for obj in bpy.data.objects if 'collider' in obj.name.lower()]
|
||||||
@@ -39,7 +41,7 @@ class AvatarToolkit_OT_ConvertVRMToUnity(Operator):
|
|||||||
for obj_name in collider_objects:
|
for obj_name in collider_objects:
|
||||||
logger.info(f" - {obj_name}")
|
logger.info(f" - {obj_name}")
|
||||||
|
|
||||||
success, messages, converted_count = convert_vrm_to_unity(armature, remove_colliders)
|
success, messages, converted_count = convert_vrm_to_unity(armature, remove_colliders, remove_root)
|
||||||
|
|
||||||
if not success:
|
if not success:
|
||||||
logger.warning(f"VRM conversion failed: {messages}")
|
logger.warning(f"VRM conversion failed: {messages}")
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ class AvatarToolKit_PT_VRMUnityPanel(Panel):
|
|||||||
|
|
||||||
toolkit = context.scene.avatar_toolkit
|
toolkit = context.scene.avatar_toolkit
|
||||||
col.prop(toolkit, 'vrm_remove_colliders', text="Remove Colliders")
|
col.prop(toolkit, 'vrm_remove_colliders', text="Remove Colliders")
|
||||||
|
col.prop(toolkit, 'vrm_remove_root', text="Remove Root Bone")
|
||||||
col.separator(factor=0.2)
|
col.separator(factor=0.2)
|
||||||
|
|
||||||
col.operator(
|
col.operator(
|
||||||
@@ -59,6 +60,7 @@ class AvatarToolKit_PT_VRMUnityPanel(Panel):
|
|||||||
info_col.label(text="Conversion Info:", icon='INFO')
|
info_col.label(text="Conversion Info:", icon='INFO')
|
||||||
info_col.label(text="• Renames VRM bones to Unity format")
|
info_col.label(text="• Renames VRM bones to Unity format")
|
||||||
info_col.label(text="• Removes collider bones (optional)")
|
info_col.label(text="• Removes collider bones (optional)")
|
||||||
|
info_col.label(text="• Removes root bone, makes Hips root (optional)")
|
||||||
info_col.label(text="• Maintains bone hierarchy")
|
info_col.label(text="• Maintains bone hierarchy")
|
||||||
info_col.label(text="• Validates conversion results")
|
info_col.label(text="• Validates conversion results")
|
||||||
info_col.label(text="• Preserves all animations")
|
info_col.label(text="• Preserves all animations")
|
||||||
|
|||||||
Reference in New Issue
Block a user