During runtime I want to know the worldposition of some vertices of my model.
My approach after several trial and errors is to querry the BoneIndex from the SkeletalMeshComponent by FName
int32 boneIndex = Skel->GetBoneIndex(boneName1);
and then I would get Indices influenced by that bone, using the FSkinWeightVertexBuffer
const FSkeletalMeshLODRenderData& LOD = Skel->GetSkeletalMeshRenderData()->LODRenderData[LODIndex];
const FSkinWeightVertexBuffer& Buffer = LOD.SkinWeightVertexBuffer;
TArray<uint32> vertices;
for (uint32 it = 0; it < Buffer.GetNumVertices(); ++it) {
for (uint32 bonInfluence = 0; bonInfluence < Buffer.GetMaxBoneInfluences(); ++bonInfluence) {
int32 bonIndex = static_cast<int32>(Buffer.GetBoneIndex(it, bonInfluence));
uint8 boneWeight = Buffer.GetBoneWeight(it, bonInfluence);
if (bonIndex == boneIndex) {
vertices.Add(it);
}
}
}
and get the Locations of those vertices with
Skel->GetSkinnedVertexPosition(Skel, vertices[i], LOD, Buffer)
I visualize those vertices later and it shows that vertices are the wrong ones!
If I get for instance the boneIndex 458 from Skel->GetBoneIndex(boneName1), the actual index I would need is 444 to get the right vertices
My actual question is, why do they differ, and how do I get reliably the correct boneIndex, or rather the vertices that are influenced by a certain bone?
@starot found the trick here: How to get TRUE bone index by vertex in 5.1.1 <3
Have to works with Lod RenderSections and BoneMap
// Iterate over all sections
for (const FSkelMeshRenderSection& SkelMeshSection : LODData.RenderSections)
{
const TArray<FBoneIndexType>& BoneMap = SkelMeshSection.BoneMap;
// Retrieve vertex indices for this section
TArray<uint32> SectionVertexIndices;
LODData.MultiSizeIndexContainer.GetIndexBuffer(SectionVertexIndices);
for (uint32 i = SkelMeshSection.BaseIndex; i < static_cast<uint32>(SkelMeshSection.BaseIndex + SkelMeshSection.NumTriangles * 3); i++)
{
int32 VertexIndex = SectionVertexIndices[i];
for (int32 InfluenceIdx = 0; InfluenceIdx < MaxInfluences; InfluenceIdx++)
{
int32 LocalBoneIndex = SkinWeightVertexBuffer.GetBoneIndex(VertexIndex, InfluenceIdx);
if (LocalBoneIndex >= BoneMap.Num()) continue; // Ensure we are within bounds
int32 GlobalBoneIndex = BoneMap[LocalBoneIndex];
float BoneWeight = SkinWeightVertexBuffer.GetBoneWeight(VertexIndex, InfluenceIdx) / 65535.0f;
FName CurrentBoneName = SkeletalMeshComponent->GetBoneName(GlobalBoneIndex);
if (GlobalBoneIndex == BoneIndexInRefSkeleton && BoneWeight > 0)
{
FVector VertexWorldPosition = Locations[VertexIndex];
FLinearColor A = FLinearColor::Blue;
FLinearColor B = FLinearColor::Red;
FLinearColor VertexColor = A + BoneWeight * (B - A);
DrawDebugPoint(SkeletalMeshComponent->GetWorld(), VertexWorldPosition, Size, VertexColor.ToFColor(false), false, Duration);
}
}
}
}