2024-03-03 18:19:53 +08:00
#region
using System.Collections.Generic ;
2022-12-10 12:33:05 +08:00
using System.Collections.Immutable ;
2024-02-05 20:52:34 +08:00
using System.Linq ;
2023-06-19 19:18:34 +08:00
using System.Text.RegularExpressions ;
2022-12-10 12:33:05 +08:00
using UnityEditor ;
using UnityEngine ;
2024-03-03 18:19:53 +08:00
#endregion
2022-12-10 12:33:05 +08:00
namespace nadena.dev.modular_avatar.core.editor
{
internal class HeuristicBoneMapper
{
2023-06-19 19:18:34 +08:00
private static readonly Regex PAT_END_NUMBER = new Regex ( @"[_\.][0-9]+" ) ;
2022-12-10 12:33:05 +08:00
// This list is originally from https://github.com/HhotateA/AvatarModifyTools/blob/d8ae75fed8577707253d6b63a64d6053eebbe78b/Assets/HhotateA/AvatarModifyTool/Editor/EnvironmentVariable.cs#L81-L139
// Copyright (c) 2021 @HhotateA_xR
// Licensed under the MIT License
2023-05-14 22:40:11 +08:00
// In addition, some part is copied from from https://github.com/Azukimochi/BoneRenamer/blob/6ec12b848830f467e35ddf7ff105aaa72be02908/BoneNames.xml
2023-03-12 21:08:00 +08:00
// Copyright (c) 2023 Azukimochi
// Licensed under the MIT License
2022-12-10 12:33:05 +08:00
private static string [ ] [ ] boneNamePatterns = new [ ]
{
2024-08-19 09:56:21 +08:00
new [ ] { "Hips" , "Hip" , "pelvis" } ,
2023-06-19 19:18:34 +08:00
new [ ]
{
"LeftUpperLeg" , "UpperLeg_Left" , "UpperLeg_L" , "Leg_Left" , "Leg_L" , "ULeg_L" , "Left leg" , "LeftUpLeg" ,
2024-08-26 10:00:10 +08:00
"UpLeg.L" , "Thigh_L"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"RightUpperLeg" , "UpperLeg_Right" , "UpperLeg_R" , "Leg_Right" , "Leg_R" , "ULeg_R" , "Right leg" ,
2024-08-26 10:00:10 +08:00
"RightUpLeg" , "UpLeg.R" , "Thigh_R"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
2024-09-14 09:07:02 +08:00
"LeftLowerLeg" , "LowerLeg_Left" , "LowerLeg_L" , "Knee_Left" , "Knee_L" , "LLeg_L" , "Left knee" , "LeftLeg" , "leg_L" , "shin.L"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"RightLowerLeg" , "LowerLeg_Right" , "LowerLeg_R" , "Knee_Right" , "Knee_R" , "LLeg_R" , "Right knee" ,
2024-09-14 09:07:02 +08:00
"RightLeg" , "leg_R" , "shin.R"
2023-06-19 19:18:34 +08:00
} ,
new [ ] { "LeftFoot" , "Foot_Left" , "Foot_L" , "Ankle_L" , "Foot.L.001" , "Left ankle" , "heel.L" , "heel" } ,
new [ ] { "RightFoot" , "Foot_Right" , "Foot_R" , "Ankle_R" , "Foot.R.001" , "Right ankle" , "heel.R" , "heel" } ,
2024-08-19 09:56:21 +08:00
new [ ] { "Spine" , "spine01" } ,
2024-09-18 10:56:15 +08:00
new [ ] { "Chest" , "Bust" , "spine02" , "upper_chest" } ,
2022-12-10 12:33:05 +08:00
new [ ] { "Neck" } ,
new [ ] { "Head" } ,
new [ ] { "LeftShoulder" , "Shoulder_Left" , "Shoulder_L" } ,
new [ ] { "RightShoulder" , "Shoulder_Right" , "Shoulder_R" } ,
2023-06-19 19:18:34 +08:00
new [ ]
{
"LeftUpperArm" , "UpperArm_Left" , "UpperArm_L" , "Arm_Left" , "Arm_L" , "UArm_L" , "Left arm" , "UpperLeftArm"
} ,
new [ ]
{
"RightUpperArm" , "UpperArm_Right" , "UpperArm_R" , "Arm_Right" , "Arm_R" , "UArm_R" , "Right arm" ,
"UpperRightArm"
} ,
2024-08-26 10:00:10 +08:00
new [ ] { "LeftLowerArm" , "LowerArm_Left" , "LowerArm_L" , "LArm_L" , "Left elbow" , "LeftForeArm" , "Elbow_L" , "forearm_L" , "ForArm_L" } ,
new [ ] { "RightLowerArm" , "LowerArm_Right" , "LowerArm_R" , "LArm_R" , "Right elbow" , "RightForeArm" , "Elbow_R" , "forearm_R" , "ForArm_R" } ,
2023-03-12 21:08:00 +08:00
new [ ] { "LeftHand" , "Hand_Left" , "Hand_L" , "Left wrist" , "Wrist_L" } ,
new [ ] { "RightHand" , "Hand_Right" , "Hand_R" , "Right wrist" , "Wrist_R" } ,
2023-06-19 19:18:34 +08:00
new [ ]
{
"LeftToes" , "Toes_Left" , "Toe_Left" , "ToeIK_L" , "Toes_L" , "Toe_L" , "Foot.L.002" , "Left Toe" ,
"LeftToeBase"
} ,
new [ ]
{
"RightToes" , "Toes_Right" , "Toe_Right" , "ToeIK_R" , "Toes_R" , "Toe_R" , "Foot.R.002" , "Right Toe" ,
"RightToeBase"
} ,
2022-12-10 12:33:05 +08:00
new [ ] { "LeftEye" , "Eye_Left" , "Eye_L" } ,
new [ ] { "RightEye" , "Eye_Right" , "Eye_R" } ,
new [ ] { "Jaw" } ,
2023-06-19 19:18:34 +08:00
new [ ]
{
"LeftThumbProximal" , "ProximalThumb_Left" , "ProximalThumb_L" , "Thumb1_L" , "ThumbFinger1_L" ,
2024-08-19 09:56:21 +08:00
"LeftHandThumb1" , "Thumb Proximal.L" , "Thunb1_L" , "finger01_01_L"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"LeftThumbIntermediate" , "IntermediateThumb_Left" , "IntermediateThumb_L" , "Thumb2_L" , "ThumbFinger2_L" ,
2024-08-19 09:56:21 +08:00
"LeftHandThumb2" , "Thumb Intermediate.L" , "Thunb2_L" , "finger01_02_L"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"LeftThumbDistal" , "DistalThumb_Left" , "DistalThumb_L" , "Thumb3_L" , "ThumbFinger3_L" , "LeftHandThumb3" ,
2024-08-19 09:56:21 +08:00
"Thumb Distal.L" , "Thunb3_L" , "finger01_03_L"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"LeftIndexProximal" , "ProximalIndex_Left" , "ProximalIndex_L" , "Index1_L" , "IndexFinger1_L" ,
2024-09-14 09:07:02 +08:00
"LeftHandIndex1" , "Index Proximal.L" , "finger02_01_L" , "f_index.01.L"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"LeftIndexIntermediate" , "IntermediateIndex_Left" , "IntermediateIndex_L" , "Index2_L" , "IndexFinger2_L" ,
2024-09-14 09:07:02 +08:00
"LeftHandIndex2" , "Index Intermediate.L" , "finger02_02_L" , "f_index.02.L"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"LeftIndexDistal" , "DistalIndex_Left" , "DistalIndex_L" , "Index3_L" , "IndexFinger3_L" , "LeftHandIndex3" ,
2024-09-14 09:07:02 +08:00
"Index Distal.L" , "finger02_03_L" , "f_index.03.L"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"LeftMiddleProximal" , "ProximalMiddle_Left" , "ProximalMiddle_L" , "Middle1_L" , "MiddleFinger1_L" ,
2024-09-14 09:07:02 +08:00
"LeftHandMiddle1" , "Middle Proximal.L" , "finger03_01_L" , "f_middle.01.L"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"LeftMiddleIntermediate" , "IntermediateMiddle_Left" , "IntermediateMiddle_L" , "Middle2_L" ,
2024-09-14 09:07:02 +08:00
"MiddleFinger2_L" , "LeftHandMiddle2" , "Middle Intermediate.L" , "finger03_02_L" , "f_middle.02.L"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"LeftMiddleDistal" , "DistalMiddle_Left" , "DistalMiddle_L" , "Middle3_L" , "MiddleFinger3_L" ,
2024-09-14 09:07:02 +08:00
"LeftHandMiddle3" , "Middle Distal.L" , "finger03_03_L" , "f_middle.03.L"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"LeftRingProximal" , "ProximalRing_Left" , "ProximalRing_L" , "Ring1_L" , "RingFinger1_L" , "LeftHandRing1" ,
2024-09-14 09:07:02 +08:00
"Ring Proximal.L" , "finger04_01_L" , "f_ring.01.L"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"LeftRingIntermediate" , "IntermediateRing_Left" , "IntermediateRing_L" , "Ring2_L" , "RingFinger2_L" ,
2024-09-14 09:07:02 +08:00
"LeftHandRing2" , "Ring Intermediate.L" , "finger04_02_L" , "f_ring.02.L"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"LeftRingDistal" , "DistalRing_Left" , "DistalRing_L" , "Ring3_L" , "RingFinger3_L" , "LeftHandRing3" ,
2024-09-14 09:07:02 +08:00
"Ring Distal.L" , "finger04_03_L" , "f_ring.03.L"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"LeftLittleProximal" , "ProximalLittle_Left" , "ProximalLittle_L" , "Little1_L" , "LittleFinger1_L" ,
2024-09-14 09:07:02 +08:00
"LeftHandPinky1" , "Little Proximal.L" , "finger05_01_L" , "f_pinky.01.L"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"LeftLittleIntermediate" , "IntermediateLittle_Left" , "IntermediateLittle_L" , "Little2_L" ,
2024-09-14 09:07:02 +08:00
"LittleFinger2_L" , "LeftHandPinky2" , "Little Intermediate.L" , "finger05_02_L" , "f_pinky.02.L"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"LeftLittleDistal" , "DistalLittle_Left" , "DistalLittle_L" , "Little3_L" , "LittleFinger3_L" ,
2024-09-14 09:07:02 +08:00
"LeftHandPinky3" , "Little Distal.L" , "finger05_03_L" , "f_pinky.03.L"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"RightThumbProximal" , "ProximalThumb_Right" , "ProximalThumb_R" , "Thumb1_R" , "ThumbFinger1_R" ,
2024-08-19 09:56:21 +08:00
"RightHandThumb1" , "Thumb Proximal.R" , "Thunb1_R" , "finger01_01_R"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"RightThumbIntermediate" , "IntermediateThumb_Right" , "IntermediateThumb_R" , "Thumb2_R" ,
2024-08-19 09:56:21 +08:00
"ThumbFinger2_R" , "RightHandThumb2" , "Thumb Intermediate.R" , "Thunb2_R" , "finger01_02_R"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"RightThumbDistal" , "DistalThumb_Right" , "DistalThumb_R" , "Thumb3_R" , "ThumbFinger3_R" ,
2024-08-19 09:56:21 +08:00
"RightHandThumb3" , "Thumb Distal.R" , "Thunb3_R" , "finger01_03_R"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"RightIndexProximal" , "ProximalIndex_Right" , "ProximalIndex_R" , "Index1_R" , "IndexFinger1_R" ,
2024-09-14 09:07:02 +08:00
"RightHandIndex1" , "Index Proximal.R" , "finger02_01_R" , "f_index.01.R"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"RightIndexIntermediate" , "IntermediateIndex_Right" , "IntermediateIndex_R" , "Index2_R" ,
2024-09-14 09:07:02 +08:00
"IndexFinger2_R" , "RightHandIndex2" , "Index Intermediate.R" , "finger02_02_R" , "f_index.02.R"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"RightIndexDistal" , "DistalIndex_Right" , "DistalIndex_R" , "Index3_R" , "IndexFinger3_R" ,
2024-09-14 09:07:02 +08:00
"RightHandIndex3" , "Index Distal.R" , "finger02_03_R" , "f_index.03.R"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"RightMiddleProximal" , "ProximalMiddle_Right" , "ProximalMiddle_R" , "Middle1_R" , "MiddleFinger1_R" ,
2024-09-14 09:07:02 +08:00
"RightHandMiddle1" , "Middle Proximal.R" , "finger03_01_R" , "f_middle.01.R"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"RightMiddleIntermediate" , "IntermediateMiddle_Right" , "IntermediateMiddle_R" , "Middle2_R" ,
2024-09-14 09:07:02 +08:00
"MiddleFinger2_R" , "RightHandMiddle2" , "Middle Intermediate.R" , "finger03_02_R" , "f_middle.02.R"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"RightMiddleDistal" , "DistalMiddle_Right" , "DistalMiddle_R" , "Middle3_R" , "MiddleFinger3_R" ,
2024-09-14 09:07:02 +08:00
"RightHandMiddle3" , "Middle Distal.R" , "finger03_03_R" , "f_middle.03.R"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"RightRingProximal" , "ProximalRing_Right" , "ProximalRing_R" , "Ring1_R" , "RingFinger1_R" ,
2024-09-14 09:07:02 +08:00
"RightHandRing1" , "Ring Proximal.R" , "finger04_01_R" , "f_ring.01.R"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"RightRingIntermediate" , "IntermediateRing_Right" , "IntermediateRing_R" , "Ring2_R" , "RingFinger2_R" ,
2024-09-14 09:07:02 +08:00
"RightHandRing2" , "Ring Intermediate.R" , "finger04_02_R" , "f_ring.02.R"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"RightRingDistal" , "DistalRing_Right" , "DistalRing_R" , "Ring3_R" , "RingFinger3_R" , "RightHandRing3" ,
2024-09-14 09:07:02 +08:00
"Ring Distal.R" , "finger04_03_R" , "f_ring.03.R"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"RightLittleProximal" , "ProximalLittle_Right" , "ProximalLittle_R" , "Little1_R" , "LittleFinger1_R" ,
2024-09-14 09:07:02 +08:00
"RightHandPinky1" , "Little Proximal.R" , "finger05_01_R" , "f_pinky.01.R"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"RightLittleIntermediate" , "IntermediateLittle_Right" , "IntermediateLittle_R" , "Little2_R" ,
2024-09-14 09:07:02 +08:00
"LittleFinger2_R" , "RightHandPinky2" , "Little Intermediate.R" , "finger05_02_R" , "f_pinky.02.R"
2023-06-19 19:18:34 +08:00
} ,
new [ ]
{
"RightLittleDistal" , "DistalLittle_Right" , "DistalLittle_R" , "Little3_R" , "LittleFinger3_R" ,
2024-09-14 09:07:02 +08:00
"RightHandPinky3" , "Little Distal.R" , "finger05_03_R" , "f_pinky.03.R"
2023-06-19 19:18:34 +08:00
} ,
2023-01-02 15:03:06 +08:00
new [ ] { "UpperChest" , "UChest" } ,
2022-12-10 12:33:05 +08:00
} ;
2024-02-27 18:02:04 +08:00
internal static readonly Regex Regex_VRM_Bone = new Regex ( @"^([LRC])_(.*)$" ) ;
2024-11-26 11:09:12 +08:00
internal static ImmutableHashSet < string > AllBoneNames =
boneNamePatterns . SelectMany ( x = > x ) . Select ( NormalizeName ) . ToImmutableHashSet ( ) ;
2022-12-10 12:33:05 +08:00
internal static string NormalizeName ( string name )
{
2024-02-27 18:02:04 +08:00
name = name . ToLowerInvariant ( ) ;
2024-08-19 09:56:21 +08:00
name = Regex . Replace ( name , "^bone_|[0-9 ._]" , "" ) ;
2023-06-19 19:18:34 +08:00
2024-02-27 18:02:04 +08:00
return name ;
2022-12-10 12:33:05 +08:00
}
2024-02-05 20:52:34 +08:00
internal static readonly ImmutableDictionary < string , List < HumanBodyBones > > NameToBoneMap ;
2022-12-10 12:33:05 +08:00
internal static readonly ImmutableDictionary < HumanBodyBones , ImmutableList < string > > BoneToNameMap ;
2024-11-03 06:17:24 +08:00
[InitializeOnLoadMethod]
private static void InsertboneNamePatternsToRuntime ( )
{
ModularAvatarMergeArmature . boneNamePatterns = boneNamePatterns ;
2024-11-26 11:09:12 +08:00
ModularAvatarMergeArmature . AllBoneNames = AllBoneNames ;
ModularAvatarMergeArmature . NormalizeBoneName = NormalizeName ;
2024-11-03 06:17:24 +08:00
}
2022-12-10 12:33:05 +08:00
static HeuristicBoneMapper ( )
{
2023-06-19 19:18:34 +08:00
var pat_end_side = new Regex ( @"[_\.]([LR])$" ) ;
2024-02-05 20:52:34 +08:00
var nameToBoneMap = new Dictionary < string , List < HumanBodyBones > > ( ) ;
2022-12-10 12:33:05 +08:00
var boneToNameMap = new Dictionary < HumanBodyBones , ImmutableList < string > > ( ) ;
for ( int i = 0 ; i < boneNamePatterns . Length ; i + + )
{
var bone = ( HumanBodyBones ) i ;
foreach ( var name in boneNamePatterns [ i ] )
{
RegisterNameForBone ( NormalizeName ( name ) , bone ) ;
2023-06-19 19:18:34 +08:00
var match = pat_end_side . Match ( name ) ;
if ( match . Success )
{
var altName = name . Substring ( 0 , name . Length - 2 ) ;
altName = match . Groups [ 1 ] + "." + altName ;
RegisterNameForBone ( NormalizeName ( altName ) , bone ) ;
}
2024-02-27 18:02:04 +08:00
else
{
// VRM pattern: J_Bip_C_[non-sided bone, e.g. hips]
var altName = "C." + name ;
RegisterNameForBone ( NormalizeName ( altName ) , bone ) ;
}
2022-12-10 12:33:05 +08:00
}
}
void RegisterNameForBone ( string name , HumanBodyBones bone )
{
2024-02-05 20:52:34 +08:00
if ( ! nameToBoneMap . TryGetValue ( name , out var list ) )
{
list = new List < HumanBodyBones > ( ) ;
nameToBoneMap [ name ] = list ;
}
list . Add ( bone ) ;
2022-12-10 12:33:05 +08:00
if ( ! boneToNameMap . TryGetValue ( bone , out var names ) )
{
names = ImmutableList < string > . Empty ;
}
if ( ! names . Contains ( name ) )
{
boneToNameMap [ bone ] = names . Add ( name ) ;
}
}
NameToBoneMap = nameToBoneMap . ToImmutableDictionary ( ) ;
BoneToNameMap = boneToNameMap . ToImmutableDictionary ( ) ;
}
/// <summary>
/// Examines the children of src, and tries to map them to the corresponding child of newParent.
/// Unmappable bones will not be added to the resulting dictionary. Ensures that each parent bone is only mapped
/// once.
/// </summary>
internal static Dictionary < Transform , Transform > AssignBoneMappings (
ModularAvatarMergeArmature config ,
GameObject src ,
2024-02-27 18:02:04 +08:00
GameObject newParent ,
List < Transform > skipped = null ,
2024-11-03 06:17:24 +08:00
HashSet < Transform > unassigned = null ,
Animator avatarAnimator = null ,
Dictionary < Transform , HumanBodyBones > outfitHumanoidBones = null
2022-12-10 12:33:05 +08:00
)
{
Dictionary < Transform , Transform > mappings = new Dictionary < Transform , Transform > ( ) ;
List < Transform > heuristicAssignmentPass = new List < Transform > ( ) ;
2024-02-27 18:02:04 +08:00
if ( unassigned = = null )
2022-12-10 12:33:05 +08:00
{
2024-02-27 18:02:04 +08:00
unassigned = new HashSet < Transform > ( ) ;
foreach ( Transform child in newParent . transform )
{
unassigned . Add ( child ) ;
}
2022-12-10 12:33:05 +08:00
}
foreach ( Transform child in src . transform )
{
var childName = child . gameObject . name ;
2024-03-03 18:19:53 +08:00
if ( childName . StartsWith ( config . prefix ) & & childName . EndsWith ( config . suffix )
& & childName . Length >
config . prefix . Length + config . suffix . Length )
2022-12-10 12:33:05 +08:00
{
var targetObjectName = childName . Substring ( config . prefix . Length ,
childName . Length - config . prefix . Length - config . suffix . Length ) ;
var targetObject = newParent . transform . Find ( targetObjectName ) ;
if ( targetObject ! = null & & unassigned . Contains ( targetObject ) )
{
mappings [ child ] = targetObject ;
unassigned . Remove ( targetObject ) ;
}
else
{
heuristicAssignmentPass . Add ( child ) ;
}
}
}
Dictionary < string , Transform > lcNameToXform = new Dictionary < string , Transform > ( ) ;
foreach ( var target in unassigned )
{
lcNameToXform [ NormalizeName ( target . gameObject . name ) ] = target ;
}
foreach ( var child in heuristicAssignmentPass )
{
var childName = child . gameObject . name ;
var targetObjectName = childName . Substring ( config . prefix . Length ,
childName . Length - config . prefix . Length - config . suffix . Length ) ;
2024-11-03 06:17:24 +08:00
List < HumanBodyBones > bodyBones = null ;
var isMapped = false ;
if ( outfitHumanoidBones ! = null & & outfitHumanoidBones . TryGetValue ( child , out var outfitHumanoidBone ) )
{
if ( avatarAnimator ! = null )
{
var avatarBone = avatarAnimator . GetBoneTransform ( outfitHumanoidBone ) ;
if ( avatarBone ! = null & & unassigned . Contains ( avatarBone ) )
{
mappings [ child ] = avatarBone ;
unassigned . Remove ( avatarBone ) ;
lcNameToXform . Remove ( NormalizeName ( avatarBone . gameObject . name ) ) ;
isMapped = true ;
} else {
bodyBones = new List < HumanBodyBones > { outfitHumanoidBone } ;
}
} else {
bodyBones = new List < HumanBodyBones > ( ) { outfitHumanoidBone } ;
}
}
if ( ! isMapped & & bodyBones = = null & & ! NameToBoneMap . TryGetValue (
NormalizeName ( targetObjectName ) , out bodyBones ) )
2022-12-10 12:33:05 +08:00
{
continue ;
}
2024-11-03 06:17:24 +08:00
if ( ! isMapped )
2022-12-10 12:33:05 +08:00
{
2024-11-03 06:17:24 +08:00
foreach ( var bodyBone in bodyBones )
2022-12-10 12:33:05 +08:00
{
2024-11-03 06:17:24 +08:00
if ( avatarAnimator ! = null )
{
var avatarBone = avatarAnimator . GetBoneTransform ( bodyBone ) ;
if ( avatarBone ! = null & & unassigned . Contains ( avatarBone ) )
{
mappings [ child ] = avatarBone ;
unassigned . Remove ( avatarBone ) ;
lcNameToXform . Remove ( NormalizeName ( avatarBone . gameObject . name ) ) ;
isMapped = true ;
break ;
}
}
}
}
if ( ! isMapped )
{
foreach ( var otherName in bodyBones . SelectMany ( bone = > BoneToNameMap [ bone ] ) )
{
if ( lcNameToXform . TryGetValue ( otherName , out var targetObject ) )
{
mappings [ child ] = targetObject ;
unassigned . Remove ( targetObject ) ;
lcNameToXform . Remove ( otherName . ToLowerInvariant ( ) ) ;
isMapped = true ;
break ;
}
2022-12-10 12:33:05 +08:00
}
}
2024-02-27 18:02:04 +08:00
if ( ! mappings . ContainsKey ( child ) & & bodyBones . Contains ( HumanBodyBones . UpperChest ) & & skipped ! = null )
{
// Avatars are often missing UpperChest bones, try skipping over this...
skipped . Add ( child ) ;
foreach ( var kvp in AssignBoneMappings ( config , child . gameObject , newParent , skipped , unassigned ) )
{
mappings . Add ( kvp . Key , kvp . Value ) ;
}
}
2022-12-10 12:33:05 +08:00
}
return mappings ;
}
2024-11-03 06:17:24 +08:00
internal static void RenameBonesByHeuristic ( ModularAvatarMergeArmature config , List < Transform > skipped = null , Dictionary < Transform , HumanBodyBones > outfitHumanoidBones = null , Animator avatarAnimator = null )
2022-12-10 12:33:05 +08:00
{
2023-10-15 17:44:53 +08:00
var target = config . mergeTarget . Get ( RuntimeUtil . FindAvatarTransformInParents ( config . transform ) ) ;
2022-12-10 12:33:05 +08:00
if ( target = = null ) return ;
2024-02-27 18:02:04 +08:00
if ( skipped = = null ) skipped = new List < Transform > ( ) ;
2022-12-10 12:33:05 +08:00
Traverse ( config . transform , target . transform ) ;
2024-02-27 18:02:04 +08:00
2022-12-10 12:33:05 +08:00
void Traverse ( Transform src , Transform dst )
{
2024-11-03 06:17:24 +08:00
var mappings = AssignBoneMappings ( config , src . gameObject , dst . gameObject , skipped : skipped , outfitHumanoidBones : outfitHumanoidBones , avatarAnimator : avatarAnimator ) ;
2022-12-10 12:33:05 +08:00
foreach ( var pair in mappings )
{
2023-09-27 19:10:57 +08:00
var newName = config . prefix + pair . Value . gameObject . name + config . suffix ;
2022-12-10 12:33:05 +08:00
var srcGameObj = pair . Key . gameObject ;
var oldName = srcGameObj . name ;
if ( oldName ! = newName )
{
Undo . RecordObject ( srcGameObj , "Applying heuristic mapping" ) ;
srcGameObj . name = newName ;
PrefabUtility . RecordPrefabInstancePropertyModifications ( srcGameObj ) ;
}
Traverse ( pair . Key , pair . Value ) ;
}
}
}
}
2024-08-19 09:56:21 +08:00
}