Can't seem to get USkeletalMeshComponent::GetSkinnedVertexPosition to return correct positions for 'rigid' verts

Hey all, I’m having trouble getting the skinned position of vertex in a USkeletalMeshComponent from a UBlueprintFunctionLibrary subclass (bit of a mouth full).

This is a function I’ve written which I’m calling from a Blueprint:

FVector UVertexColorBPFunctionLibrary::GetSkinnedMeshSkinnedVertexPosition( USkinnedMeshComponent* mesh, const int32 &vertexIndex )
{
    if ( mesh )
    {
        FVector positionInComponentSpace = mesh->GetSkinnedVertexPosition( vertexIndex );
        return mesh->ComponentToWorld.TransformPosition( positionInComponentSpace );
    }

    return FVector();
}    

and this is some debug points rendered at the returned positions:

Initially I thought I was just getting garbage but I think actually whats happening is I’m getting correct positions returned for the ‘soft’ skinned vertices and the ‘rigid’ points (with skin weight 1) are just not getting correct positions returned. In the image above you can see clusters of correctly positioned verts along the soft boundaries between joints.

So, I flooded the root weight with 0.1 to pull weights off the other ‘rigid’ verts and turn them into ‘soft’ ones. And that does seem to prove the point:

I’m downloading the engine source now to put some debug statements inside USkeletalMeshComponent::GetSkinnedVertexPosition but figured I’d ask here in the mean time incase anyone has any bright ideas as to how I can get this to work for ‘rigid’ vertices?

Cheers,
Daniel

#Video

Hi there!

I did this during the beta, here’s a video!

I am obtaining the animated vertex positions and positioning particles systems to match the world space vertex locations!

And I got it to replicate over network!

Result: Creatures that animate normally but are made only of particles!

Below is the core of my code for how I did this, some of the data structures have changed since the beta but I think your issue is the transform part.

#Code

void AVictoryPlayerCharacterBase::GetAnimatedVertexLocationsAndNormals(
	TArray<FVector>& Locations, 
	TArray<FVector>& Normals 
)
{
	if(!Mesh) return;
	if(!Mesh->SkeletalMesh) return;
	//~~~~~~~~~
	
	Locations.Empty(); 
	Normals.Empty();
	//~~~~~~~~~~~~~~~~~~~
	
	//	Get the Verticies For Each Bone, Most Influenced by That Bone!
	//					Vertices are in Bone space.
	RV_BoneVertexInfos.Empty();
	GetVertexBone(Mesh->SkeletalMesh,RV_BoneVertexInfos,true); //true = only dominant influence
	
	//~~~~~~~~~~~~~~~~~~~~~
	int32 VertItr = 0;
	FBoneVertInfo* EachBoneVertInfo;
	FVector BoneWorldPos;
	int32 NumOfVerticies;
	for(int32 Itr=0; Itr < RV_BoneVertexInfos.Num() ; Itr++)
	{
		EachBoneVertInfo = &RV_BoneVertexInfos[Itr];
		//~~~~~~~~~~~~~~~~~~~~~~~~
		
		//Bone Transform To World Space, and Location
		RV_Transform = Mesh->GetBoneTransform(Itr);
		BoneWorldPos = RV_Transform.GetLocation();
		
		//How many verts is this bone influencing?
		NumOfVerticies = EachBoneVertInfo->Positions.Num();
		for(VertItr=0; VertItr < NumOfVerticies ; VertItr++)
		{
			//Animated Vertex Location!
			Locations.Add(  BoneWorldPos + RV_Transform.TransformVector(EachBoneVertInfo->Positions[VertItr])  );
		
			//Animated Vertex Normal for rotating the emitter!!!!!
			Normals.Add(  RV_Transform.TransformVector(EachBoneVertInfo->Normals[VertItr])  );
		}
	}
	
	//~~~ Cleanup ~~~
	RV_BoneVertexInfos.Empty();
}

#My Analysis

You are transforming the position but you are not adding the initial world space location of the bone like this:

//Bone World Space Center         //each vertex that is most-influenced by this bone
BoneWorldPos + RV_Transform.TransformVector(EachBoneVertInfo->Positions[VertItr]) 

you have this:

return mesh->ComponentToWorld.TransformPosition( positionInComponentSpace );

#Bone World Space Center

Remember your verticies are relative to their respective BONES

so you need to add the bone location!

return BoneLocOwningThisVert + mesh->ComponentToWorld.TransformPosition( positionInComponentSpace );

:slight_smile:

Rama

Hey Rama, Cheers for the help! I thought for sure my question was way too obscure to get a response :slight_smile:

So I got the Engine code checked out and it did look like USkeletalMeshComponent::GetSkinnedVertexPosition should already return positions post-deformed by the bones into ‘component space’ (as it says in the docs) and the internals did look like they should do this for rigid skinned vertices aswell.

Anywhoo, whilst in the code I spotted a potential bug where bExtraBoneInfluencesT wasn’t getting passed through to VertexBufferGPUSkin.GetVertexPtr for rigid skinned vertices like it was for ‘soft’ vertices and passing this through has fixed my issue!

Am going to look up submission guidelines now to submit back a patch.

Cheers again mate!

Hey Rama I have two questions

1 - what is the type of RV_BoneVertexInfos
2 - did you write “GetVertexBone” function ? because I cannot find such

the issue is that I want to get access to the position of the vertices of an skeletal position. exactly what you did in your video. can you share more information with me how can I do it with 4.3 or 4.4 ? because you mentioned you did it with beta version

thanks