None.
Steps to Reproduce
if the FCompactPoseBoneIndex is not valid for the pose you can crash in Pose.GetComponentSpaceTransform and Pose[FCompactPoseBoneIndex(BoneIndex)]. The comment in GetComponentSpaceTransform seems to imply this is expected. Given UMotionWarpingUtilities::ExtractBoneTransformFromAnimationAtTime is a BPFL node would you be open to checking the valid index and early out with an ensure?
What is the case where the bone index is valid but not the compact bone?
Hi, thanks for flagging this one. It’s a bug in how UMotionWarpingUtilities::ExtractBoneTransformFromAnimationAtTime attempts to access the required bones buffer. That buffer only contains bones for the LOD that is currently active, but ExtractBoneTransformFromAnimationAtTime is trying to index into it via GetPoseBoneIndexForBoneName, which gets the bone index from the mesh’s reference skeleton. So the bone index isn’t guaranteed to include the required bones. Instead, the code should be doing the following, where we map from the mesh bone index to the required bones index:
void UMotionWarpingUtilities::ExtractBoneTransformFromAnimationAtTime(const UAnimInstance* AnimInstance, const UAnimSequenceBase* Animation, float Time, bool bExtractRootMotion, FName BoneName, bool bLocalSpace, FTransform& OutTransform)
{
OutTransform = FTransform::Identity;
if (AnimInstance && Animation)
{
FMemMark Mark(FMemStack::Get());
const int32 MeshBoneIndex = AnimInstance->GetRequiredBones().GetPoseBoneIndexForBoneName(BoneName);
const FCompactPoseBoneIndex PoseBoneIndex = AnimInstance->GetRequiredBones().GetBoneContainer().MakeCompactPoseIndex(FMeshPoseBoneIndex(MeshBoneIndex));
if (PoseBoneIndex != INDEX_NONE)
{
if (bLocalSpace)
{
FCompactPose Pose;
ExtractLocalSpacePose(Animation, AnimInstance->GetRequiredBones(), Time, bExtractRootMotion, Pose);
OutTransform = Pose[PoseBoneIndex];
}
else
{
FCSPose<FCompactPose> Pose;
UMotionWarpingUtilities::ExtractComponentSpacePose(Animation, AnimInstance->GetRequiredBones(), Time, bExtractRootMotion, Pose);
OutTransform = Pose.GetComponentSpaceTransform(PoseBoneIndex);
}
}
}
}
I’m going to get this change integrated, but it’d be useful if you could confirm that it resolves the problem for you.
Quick follow up - there was a typo in the code that I included in my previous message. The new version of the function should look like this instead:
void UMotionWarpingUtilities::ExtractBoneTransformFromAnimationAtTime(const UAnimInstance* AnimInstance, const UAnimSequenceBase* Animation, float Time, bool bExtractRootMotion, FName BoneName, bool bLocalSpace, FTransform& OutTransform)
{
OutTransform = FTransform::Identity;
if (AnimInstance && Animation)
{
FMemMark Mark(FMemStack::Get());
const int32 MeshBoneIndex = AnimInstance->GetRequiredBones().GetPoseBoneIndexForBoneName(BoneName);
const FCompactPoseBoneIndex PoseBoneIndex = AnimInstance->GetRequiredBones().MakeCompactPoseIndex(FMeshPoseBoneIndex(MeshBoneIndex));
if (PoseBoneIndex != INDEX_NONE)
{
if (bLocalSpace)
{
FCompactPose Pose;
ExtractLocalSpacePose(Animation, AnimInstance->GetRequiredBones(), Time, bExtractRootMotion, Pose);
OutTransform = Pose[PoseBoneIndex];
}
else
{
FCSPose<FCompactPose> Pose;
UMotionWarpingUtilities::ExtractComponentSpacePose(Animation, AnimInstance->GetRequiredBones(), Time, bExtractRootMotion, Pose);
OutTransform = Pose.GetComponentSpaceTransform(PoseBoneIndex);
}
}
}
}
Thanks! we’ll see if we can get a repro again and report back
Sounds good. The thread will stay open for a couple of weeks so hopefully that’ll be enough time to confirm everything is working.
We’ve had it in for a few days and it seems to be good with that change.
Thanks!
Great, thanks for confirming. I’ve already committed this change so you’ll be able to remove the modification if/when you upgrade to 5.8.