diff --git a/03-UnrealEngine/Animation/UE5商城动画重定向插件笔记.md b/03-UnrealEngine/Animation/UE5商城动画重定向插件笔记.md index 8ea35ad..b2895c0 100644 --- a/03-UnrealEngine/Animation/UE5商城动画重定向插件笔记.md +++ b/03-UnrealEngine/Animation/UE5商城动画重定向插件笔记.md @@ -15,8 +15,103 @@ rating: ⭐ 重定向逻辑位于:FMixamoSkeletonRetargeter::Retarget() -## 判断骨骼格式 +## 生成TPose ```c++ +static const TArray Mixamo_PreserveComponentSpacePose_BoneNames = { + "Head", + "LeftToeBase", + "RightToeBase" + +#ifdef MAR_UPPERARMS_PRESERVECS_EXPERIMENTAL_ENABLE_ + ,"RightShoulder" + ,"RightArm" ,"LeftShoulder" ,"LeftArm"#endif +}; + +static const TArray> Mixamo_ParentChildBoneNamesToBypassOneChildConstraint = { + {"LeftUpLeg", "LeftLeg"}, + {"LeftLeg", "LeftFoot"}, + {"LeftFoot", "LeftToeBase"}, + {"LeftToeBase", "LeftToe_End"}, + {"RightUpLeg", "RightLeg"}, + {"RightLeg", "RightFoot"}, + {"RightFoot", "RightToeBase"}, + {"RightToeBase", "RightToe_End"}, + {"Hips", "Spine"}, // Heuristic to try to align better the part. + {"Spine", "Spine1"}, + {"Spine1", "Spine2"}, + {"Spine2", "Neck"}, // Heuristic to try to align better the part. + {"Neck", "Head"}, + {"Head", "HeadTop_End"}, + {"LeftShoulder", "LeftArm"}, + {"LeftArm", "LeftForeArm"}, + {"LeftForeArm", "LeftHand"}, + {"LeftHand", "LeftHandMiddle1"}, // Heuristic to try to align better the part. + {"LeftHandIndex1", "LeftHandIndex2"}, + {"LeftHandIndex2", "LeftHandIndex3"}, + {"LeftHandIndex3", "LeftHandIndex4"}, + {"LeftHandMiddle1", "LeftHandMiddle2"}, + {"LeftHandMiddle2", "LeftHandMiddle3"}, + {"LeftHandMiddle3", "LeftHandMiddle4"}, + {"LeftHandPinky1", "LeftHandPinky2"}, + {"LeftHandPinky2", "LeftHandPinky3"}, + {"LeftHandPinky3", "LeftHandPinky4"}, + {"LeftHandRing1", "LeftHandRing2"}, + {"LeftHandRing2", "LeftHandRing3"}, + {"LeftHandRing3", "LeftHandRing4"}, + {"LeftHandThumb1", "LeftHandThumb2"}, + {"LeftHandThumb2", "LeftHandThumb3"}, + {"LeftHandThumb3", "LeftHandThumb4"}, + {"RightShoulder", "RightArm"}, + {"RightArm", "RightForeArm"}, + {"RightForeArm", "RightHand"}, + {"RightHand", "RightHandMiddle1"}, // Heuristic to try to align better the part. + {"RightHandIndex1", "RightHandIndex2"}, + {"RightHandIndex2", "RightHandIndex3"}, + {"RightHandIndex3", "RightHandIndex4"}, + {"RightHandMiddle1", "RightHandMiddle2"}, + {"RightHandMiddle2", "RightHandMiddle3"}, + {"RightHandMiddle3", "RightHandMiddle4"}, + {"RightHandPinky1", "RightHandPinky2"}, + {"RightHandPinky2", "RightHandPinky3"}, + {"RightHandPinky3", "RightHandPinky4"}, + {"RightHandRing1", "RightHandRing2"}, + {"RightHandRing2", "RightHandRing3"}, + {"RightHandRing3", "RightHandRing4"}, + {"RightHandThumb1", "RightHandThumb2"}, + {"RightHandThumb2", "RightHandThumb3"}, + {"RightHandThumb3", "RightHandThumb4"} +}; + +RetargetBasePose( + SkeletalMeshes, + ReferenceSkeleton, + Mixamo_PreserveComponentSpacePose_BoneNames, + UEMannequinToMixamo_BoneNamesMapping.GetInverseMapper(), + Mixamo_ParentChildBoneNamesToBypassOneChildConstraint, + /*bApplyPoseToRetargetBasePose=*/true, + UIKRetargeterController::GetController(IKRetargeter_UEMannequinToMixamo) +); +``` + + + +## 判断骨骼结构是否符合要求 +```c++ +bool FMixamoSkeletonRetargeter::IsMixamoSkeleton(const USkeleton * Skeleton) const +{ + // We consider a Skeleton "coming from Mixamo" if it has at least X% of the expected bones. + const float MINIMUM_MATCHING_PERCENTAGE = .75f; + + // Convert the array of expected bone names (TODO: cache it...). + TArray BoneNames; + UE4MannequinToMixamo_BoneNamesMapping.GetDestination(BoneNames); + // Look for and count the known Mixamo bones (see comments on IndexLastCheckedMixamoBone and UEMannequinToMixamo_BonesMapping). + constexpr int32 NumBones = (IndexLastCheckedMixamoBone + 1) / 2; + BoneNames.SetNum(NumBones); + FSkeletonMatcher SkeletonMatcher(BoneNames, MINIMUM_MATCHING_PERCENTAGE); + return SkeletonMatcher.IsMatching(Skeleton); +} + bool FSkeletonMatcher::IsMatching(const USkeleton* Skeleton) const { // No Skeleton, No matching... @@ -35,3 +130,73 @@ bool FSkeletonMatcher::IsMatching(const USkeleton* Skeleton) const return MatchedPercentage >= MinimumMatchingPerc; } ``` + + + +enum class ETargetSkeletonType +{ + ST_UNKNOWN = 0, + ST_UE4_MANNEQUIN, + ST_UE5_MANNEQUIN, + + ST_SIZE +}; + +static const char* const kUE4MannequinToMixamo_BoneNamesMapping[] = { + // UE Mannequin bone name MIXAMO bone name + "root", "root", + "pelvis", "Hips", + "spine_01", "Spine", + "spine_02", "Spine1", + "spine_03", "Spine2", + "neck_01", "Neck", + "head", "head", + "clavicle_l", "LeftShoulder", + "upperarm_l", "LeftArm", + "lowerarm_l", "LeftForeArm", + "hand_l", "LeftHand", + "clavicle_r", "RightShoulder", + "upperarm_r", "RightArm", + "lowerarm_r", "RightForeArm", + "hand_r", "RightHand", + "thigh_l", "LeftUpLeg", + "calf_l", "LeftLeg", + "foot_l", "LeftFoot", + "ball_l", "LeftToeBase", + "thigh_r", "RightUpLeg", + "calf_r", "RightLeg", + "foot_r", "RightFoot", + "ball_r", "RightToeBase", + // From here, ignored to determine if a skeleton is from Mixamo. + // From here, ignored to determine if a skeleton is from UE Mannequin. "index_01_l", "LeftHandIndex1", + "index_02_l", "LeftHandIndex2", + "index_03_l", "LeftHandIndex3", + "middle_01_l", "LeftHandMiddle1", + "middle_02_l", "LeftHandMiddle2", + "middle_03_l", "LeftHandMiddle3", + "pinky_01_l", "LeftHandPinky1", + "pinky_02_l", "LeftHandPinky2", + "pinky_03_l", "LeftHandPinky3", + "ring_01_l", "LeftHandRing1", + "ring_02_l", "LeftHandRing2", + "ring_03_l", "LeftHandRing3", + "thumb_01_l", "LeftHandThumb1", + "thumb_02_l", "LeftHandThumb2", + "thumb_03_l", "LeftHandThumb3", + "index_01_r", "RightHandIndex1", + "index_02_r", "RightHandIndex2", + "index_03_r", "RightHandIndex3", + "middle_01_r", "RightHandMiddle1", + "middle_02_r", "RightHandMiddle2", + "middle_03_r", "RightHandMiddle3", + "pinky_01_r", "RightHandPinky1", + "pinky_02_r", "RightHandPinky2", + "pinky_03_r", "RightHandPinky3", + "ring_01_r", "RightHandRing1", + "ring_02_r", "RightHandRing2", + "ring_03_r", "RightHandRing3", + "thumb_01_r", "RightHandThumb1", + "thumb_02_r", "RightHandThumb2", + "thumb_03_r", "RightHandThumb3", + // Un-mapped bones (at the moment). Here for reference. + //"lowerarm_twist_01_l", nullptr, //"upperarm_twist_01_l", nullptr, //"lowerarm_twist_01_r", nullptr, //"upperarm_twist_01_r", nullptr, //"calf_twist_01_l", nullptr, //"thigh_twist_01_l", nullptr, //"calf_twist_01_r", nullptr, //"thigh_twist_01_r", nullptr, //"ik_foot_root", nullptr, //"ik_foot_l", nullptr, //"ik_foot_r", nullptr, //"ik_hand_root", nullptr, //"ik_hand_gun", nullptr, //"ik_hand_l", nullptr, //"ik_hand_r", nullptr,}; \ No newline at end of file