Transform skeletal bone in C++

Hello!

Is there way to transform bone of ASkeletalMeshActor? I tried to do it following ways:

(SkeletalMeshComponent from actor instance)

  1. by changing SpaceBases and LocalAtoms for required bone

     		auto BoneIdx = SkeletalMeshComponent->GetBoneIndex(TEXT("SheKRArm2"));
     		SkeletalMeshComponent->LocalAtoms[BoneIdx].AddToTranslation(FVector(100, 100, 100));
     		SkeletalMeshComponent->FillSpaceBases();
    
  2. by applying body transform using PhysX

     		auto Transform = SkeletalMeshComponent->SpaceBases[BoneIdx] * SkeletalMeshComponent->ComponentToWorld;
     		Transform.AddToTranslation(FVector(100, 100, 100));
     		SkeletalMeshComponent->GetBodyInstance(TEXT("SheKRArm2"))->SetBodyTransform(Transform, true);
    

So, what wrong I do?

Thanks.

#Skeletal Controller Single Bone + Custom C++ Anim Instance

In your Anim BP

Make a Skeletal Controller for Single Bone

Extend your Anim BP class, making your own AnimInstance class that has your custom FTransform or FVector or FRotator Vars in it

Then set these vars any time from anywhere c++ after accessing your custom anim instance.

You can even implement custom logic in the tick of the animation instance itself!

#My Wiki Tutorials

Custom Anim BP Vars in C++

Custom Logic in Anim BP Tick in C++

#Advantages

You can modify animations that are playing if the Skeletal Controller is applied after the animation blends / montages / Slots

It’s easy to use

Can do it with multiple bones and handle each case separately without one interfering with the other, enabling/disabling each modification as per your C++ logic / gameplay flow

#Enjoy!

Rama

1 Like

Thanks Rama, but is there way w/o using BP ?

I don’t think Rama’s answer really addresses the question because it involves blueprints. That being said I’d still consider it still useful.

##Transform Bones in C++ Only
You’ll have to inherit from UAnimInstance and override EvaluateAnimation. Once you’ve done that you can use USkeletalMeshComponent::SetAnimInstanceClass on a Skeletal Mesh Component to your new inherited anim instance.

EvaluateAnimation and FPoseContext is pretty undocumented at this point, but it’s fairly simple to figure out.

Hope that helps! It sure helped me once I found it.

Was this ever solved? It looks like the bone data is private except for the names:
FReferenceSkeleton* RefSkeleton = &Mesh1P->SkeletalMesh->RefSkeleton;
for (int32 i = 0; i < DebugRequiredBones; i++)
DebugBoneNames.Add(RefSkeleton->GetBoneName(i));

I would like to get the positions and change them if possible :confused: arg…

Hello,

There is a UPoseableMeshComponent class that allow you to manually move any bone in the C++ code.
You can use it instead of USkeletalMeshComponent and set any transformation to the LocalAtoms[].

Worked perfectly for me, though I don’t know is it possible to add an animation blueprint to it (if you need one).

Hi,

There is a UPoseableMeshComponent
class that allow you to manually move
any bone in the C++ code. You can use
it instead of USkeletalMeshComponent
and set any transformation to the
LocalAtoms.

Could you explain how you converted class USkeletalMeshComponent to class UPoseableMeshComponent ?
I am almost in the same situation as Numat, the only difference is that I work with the ACharacter class.

Hi,

You can’t convert it. You need to create the UPoseableMeshComponent instead of USkeletalMeshComponent, and then you can set the same mesh to poseable component

First of all, thank you for answering my question.

Could you show me a sample code for Acharacter class?

Hi ,

Here is an example how to create a posable mesh in C++:

USkeletalMesh* yourMesh = …;

UPoseableMeshComponent* posableMeshComponent = PCIP.CreateDefaultSubobject(this, TEXT(“MeshComponent”));

posableMeshComponent->SetSkeletalMesh(yourMesh);

You can do this in your ACharacter class instead of creating the USkeletalMeshComponent.

If I do as you say, I’ll have the same results that I already have.

  • 2 characters

    static ConstructorHelpers::FObjectFinder skeletalMesh1(TEXT(“SkeletalMesh’/Game/ThirdPerson/Character/ThirdPersonSkeletalMesh.ThirdPersonSkeletalMesh’”));
    Mesh->SetSkeletalMesh(skeletalMesh1.Object);
    MeshComponent = ObjectInitializer.CreateDefaultSubobject(this, TEXT(“Mesh”));
    MeshComponent->SetSkeletalMesh(skeletalMesh1.Object);
    RootComponent = MeshComponent;

How do I change to avoid having duplicates?

If someone has a better solution that does not hesitate

AMyCharacter::AMyCharacter(const FObjectInitializer& ObjectInitializer) 
{
	static ConstructorHelpers::FObjectFinder<USkeletalMesh> skeletalMesh1(TEXT("SkeletalMesh'/Game/ThirdPerson/Character/ThirdPersonSkeletalMesh.ThirdPersonSkeletalMesh'"));
	GetMesh()->SetSkeletalMesh(NULL);

	MeshComponent = ObjectInitializer.CreateDefaultSubobject<UPoseableMeshComponent>(this, TEXT("MeshComponent"));
	MeshComponent->SetSkeletalMesh(skeletalMesh1.Object);
	MeshComponent->SetMobility(EComponentMobility::Movable);
	RootComponent = MeshComponent;

	GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);
	UCapsuleComponent* capsule = this->GetCapsuleComponent();
	capsule->AttachTo(RootComponent);

	// Create a camera boom (pulls in towards the player if there is a collision)
	CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
	CameraBoom->AttachTo(RootComponent);
	CameraBoom->TargetArmLength = 300.0f; // The camera follows at this distance behind the character	
	CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller
	
	// Create a follow camera
	FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
	FollowCamera->AttachTo(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation
	FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm
}

Disadvantage is that my character class has no mesh :frowning:

If you need to use it in the ACharacter class I think you need to use that UPoseableMeshComponent instead of the character Mesh, not creating it beside the skeletal one. Try to not use and initialise the ACharacter::Mesh at all.