Core problems
In USkinnedMeshComponent::GetTypedSkinnedVertexPosition, it checks that it has the proper master pose component.
If it does, map the bone index to the index of master bones, like below:
int32 BoneIndex = Section.BoneMap[SrcSoftVertex->InfluenceBones[InfluenceIndex]];
if(MasterPoseComponentInst)
{
check(MasterBoneMap.Num() == SkeletalMesh->RefSkeleton.GetNum());
BoneIndex = MasterBoneMap[BoneIndex];
}
after then, it access the ref bases inverse matrix and component space transforms to get the RefToLocal matrix:
const FMatrix RefToLocal = SkeletalMesh->RefBasesInvMatrix[BoneIndex]
* BaseComponent->GetComponentSpaceTransforms()[BoneIndex].ToMatrixWithScale();
At this point, the Mapped BoneIndex can exceed the number of SkeletalMesh’s RefBasesInvMatrix
Situations
Preparations
- One character skeletal mesh with proper bone hierarchy.
- One additional skeletal mesh with almost same bone hierarchy.
- Character skeletal mesh has extra dummy bones which are not influence to the main bone hierarchy.
Setting up
- Import character skeletal mesh
- Import additional skeletal mesh with the same (using combobox)
- Set master pose of the additional mesh as Character skeletal mesh (in c++)
- When I call the GetSkinnedVertexPosition which calls the GetTypedSkinnedVertexPosition, It has crashed.
My solutions
Solution 1
I think, the index of RefBasesInvMatrix does not need to be mapped to the MasterBone’s one. So I just use the mapped bone index only for accessing Component space transforms of MasterPoseComponent.
int32 BoneIndex = Section.BoneMap[SrcSoftVertex->InfluenceBones[InfluenceIndex]];
int32 MappedIndex = BoneIndex;
if(MasterPoseComponentInst)
{
check(MasterBoneMap.Num() == SkeletalMesh->RefSkeleton.GetNum());
MappedIndex = MasterBoneMap[BoneIndex];
}
const FMatrix RefToLocal = SkeletalMesh->RefBasesInvMatrix[BoneIndex]
* BaseComponent->GetComponentSpaceTransforms()[MappedIndex].ToMatrixWithScale();
It seems that it resolved this problem. But I’m not quite sure I’ve corrected.
Solution 2
I’ve solved this with another way.
If the MasterPoseComponent is set, RefBasesInvMatrix also be used those of MasterPoseComponent. Look this:
const FMatrix RefToLocal = BaseComponent->RefBasesInvMatrix[BoneIndex]
* BaseComponent->GetComponentSpaceTransforms()[BoneIndex].ToMatrixWithScale();
I think it is more reasonable than the Solution1.
Requests
Whatever the solution is, If MasterPoseComponent must have the same hierarchy with those of target mesh, Engine should warn to us or leave some logs about this situation.
Testing version
I’ve tested this on UE4.13, but the part of code has no difference with UE4.15