animBP transform (modify) bone is not updating physical asset

Hi!

I’m doing an editable character, the way i’m doing that is updating bone position with animationBP transform node, but when i simulate physics all bones return to their original transforms, i was looking for an option in mesh detail panel to keep transforms, i tryed to enable some checks under physics section and skeletal mesh section but nothing happens save stops to update position and leave simulating parts floating in world space.

¿is there a way to update physical asset and preserve changes from animBP?

Thanks!

hey not sure if i understood you correct, but maybe Animation Snapshot helps?
https://docs.unrealengine.com/en-US/…hot/index.html

Thanks for reply, Spaehling, you probably not understood me because my english is so poor, sorry about that TT

I think pose snapshot allows you to use pose information into animationBP, that’s usefull to get result pose from physical simulation and make transitions between that saved pose and some animation. anyway i tried to apply this but isn’t useful for my case.

What i’m trying to do, in a general way, is modify skeleton ingame and preserving that changes when i simulate physics bodies.

look into physical animation then

Thanks for replying MostHost!

I don’t know if I’m losing something, but I understand that Physical animation runs over bind pose, let’s say that I changed my arm position, when I simulate, and even though I put a big number in position strenght, the constraint go back to bind pose reference bone, without consider AnimBP changes. I look into Physical animation component details, but i don’t see anything useful.

I made a test with an editable part, instead a transform bone AnimBP node I used an animation with the maximum displacement that a specific bone should have, I configured this animation as additive and used the offset information that I use with transform bone node to set alpha, but the result is the same.

Is there a way to update bind pose?
or pass animBP changes to physical asset?
or update constraint position?

Maybe physical asset doesn’t make an instance for every character that shares the skeleton

My problemo:

Thanks! ^^

Physical animation simulates the movement of parts from animation.

So you can offset the pose as you want, save the snapshot, apply it in amib bp, turn on the ohysics simulation, and you should be able to ragdoll in a specific position.

I have used this for MotoGP style falls, where just going into ragdoll makes no sense.

In your test video, the translation isnt applied to the underlaying skeleton, so the joint snaps back.

Hello again, MostHost!

Let me puntualize, it looks like Physical Animation gets data from AnimationBP, of cours, but Physical Asset does not do that (I don’t know if it can do, and that’s de main question), so, when I set up a physical asset, and I apply the offset position from animBP, when I simulate physics (without Physical Animation) these parts who I apply the offset will return to his respective original locations, and it ocurres because AnimBP is not updating Physical Asset, or is not updating the instanced constraints that comes from Physical Asset. So when I apply the Physical Animation, with offsets too, like in the last case, constraints keeps having the original location, locations without offsets, but it fights to reach the position of the animations coming from AnimBP that effectively have that offsets.

If I want to keep offsets and have a pure ragdoll I cannot do that because what Physical Animation do is try to reach a position and rotation in a physical simulation, but it does not make constraints to preserve offsets.

If I want to make the arm longer or shorter from my skeletal mesh, when I simulate physics, with or without Physical Animation, all constraints will return to their original position.

What I want is not to preserve a specific pose that my character make in a certaint runetime time, I want to modify Constraints from phyisical Asset, but not get or preserve a pose.

Sorry for my english, i know that it have to be difficult to understand me ^^’

maybe write a copy in your native language. Given I speak 4 chances are ill understand you better.

in short, it seems that what you want is not possible.

However, you can choose a preview animation within your PHAT asset (top left) to see how the physical animation would work with the given animation.
Maybe you can leverage that, but I really do not see the point other then for testing purposes / checking the rigidity of the constraints.
In the end, physical animation and the PHAT asset are meant to work at runtime, not in editor.

Thank you, MostHost, I appreciate that you spend your time replying my post ^^

I will keep looking for a solution, I have a solution that would definitely work, but I want to find out something more elegant and fastest to implement.

Whatever that i use to solve this, I will post the solution in this thread!

Cheers :3

Wow, I forgot to post the solution…

The thing is that constraints and bones have to be understood as unrelated concepts, when you create a constraint through the Physical asset editor, it sets specific values relative to the bones you’re constraining, and doesn’t matter if you transform bones in animation BP because animation doesn’t set constraint instance values, and constraint instances doesn’t read from animation, if you want to translate the relative position of some of the two bones that are constrained you have to acces to the instance of that constraint, as Unreal 4 doesn’t have any blueprint node to change constraint instance properties (Unreal 5 does) I had to create a C++ blueprint function library class, where I added this:

.h

UFUNCTION(blueprintCallable, meta = (DisplayName = "SetConstraintPosition"), Category = "octolex utilities|constraints")
		static void SetConstraintPos(USkeletalMeshComponent* targetMesh, FName constraintName, FVector newPos);

.cpp

void UConstraintUtilities::SetConstraintPos(USkeletalMeshComponent* targetMesh, FName constraintName, FVector newPos)
{
	if (IsValid(targetMesh)) {

		if ((targetMesh->FindConstraintInstance(constraintName)) != nullptr) {
			targetMesh->FindConstraintInstance(constraintName)->SetRefPosition(EConstraintFrame::Frame2, newPos);
		}
		else {
			UE_LOG(LogTemp, Warning, TEXT("constraint not valid"));
		}
	}
	else {
		UE_LOG(LogTemp, Warning, TEXT("mesh not valid"));
	}
}

This just bring acces to the FConstraintInstance::SetRefPosition C++ function from blueprints.

I know this is an old thread, I don’t want to bother anyone, but it’s worth just for, maybe, helping someone ^^

References:

FConstraintInstance

3 Likes

Dear Octolex, thank you so much for solving this extremely esoteric and mysterious problem! I just encountered this problem myself yesterday and your solution works perfectly! (I don’t think I would’ve figured it out in a million years myself).

I furthermore encountered another problem once I got the constraint to follow the position of the mouse (while I had set my SkeletalMesh to “Ragdoll” and I had two bones set to “Set All Bodies Below Simulate Physics” – I’m assuming anybody reading this thread already knows what the problem is, but this was just my exact particular setup) – if you try to set the “constraintName” (on the “SetConstraintPos” node) to the same one that appears inside of the Physics Asset Window (the window in which you edit the yellow Physics Bodies) – for a constraint that you created yourself – the “SetConstraintPos” Blueprint node will actually return “constraint not valid”

As I learned by doing a ForLoop on my SkeletalMesh for “FindConstraintBoneName” (thus returning all of the Constraints on my SkeletalMesh), I was able to determine that when you add your own Constraint, it actually does NOT get named to what you named it inside of the Physics Asset Window – it instead defaults to “UserConstraint,” and from what I can tell, it begins to increment starting at index 0; the next one after “UserConstraint” gets renamed to “UserConstraint_0”

So in order to get the node working, I had to put in that name instead, rather than the one that it is actually called inside of the Physics Asset Window.


These DO NOT Work

I likewise hope that this esoteric and mysterious information may also help some stranger on the internet some day.

Thank you!

:pray: :pray: :pray:

2 Likes

I’m glad I was able to help ^^

If you want to know the constraint names you can actually do that in the physical asset editor window!

You probably already know, it’s the official, fastest and easiest way to edit physics constraints after all, but just to be sure (~ ̄▽ ̄)~

Thank you! This works perfectly. If someone needs a “rotation” version, you can do it with this.

UFUNCTION(BlueprintCallable)
static void SetConstraintPosition2(USkeletalMeshComponent* targetMesh, FName constraintName, bool frame1, FVector priAxis, FVector secAxis)
{
	if (IsValid(targetMesh))
	{
		FConstraintInstance* constraint = targetMesh->FindConstraintInstance(constraintName);

		if (constraint != nullptr)
		{ 
			constraint->SetRefOrientation(frame1 ? EConstraintFrame::Frame1 : EConstraintFrame::Frame2, priAxis, secAxis);
		}
		else {
			UE_LOG(LogTemp, Warning, TEXT("constraint not valid"));
		}
	}
	else {
		UE_LOG(LogTemp, Warning, TEXT("mesh not valid"));
	}
}

1 Like

Thank you very much, I struggled with this problem for a very long time and made the same solution as yours!! And still good work, in my opinion this is the most exotic problem in Unreal that can be. I want to share my solution to help the Internet.
cpp:

#include "Components/SkeletalMeshComponent.h"
#include "PhysicsEngine/PhysicsAsset.h"
#include "PhysicsEngine/BodySetup.h"
#include "PhysicsEngine/AggregateGeom.h"
#include "Engine/Engine.h" 
#include "Containers/Array.h"
#include "UObject/NameTypes.h"
#include "PhysicsEngine/ConstraintInstance.h"
#include "Engine/SkeletalMesh.h"
#include "PhysicsEngine/PhysicsConstraintTemplate.h"
#include "Animation/Skeleton.h"
#include "PhysicsEngine/PhysicsConstraintComponent.h"

TArray<UPhysicsConstraintTemplate*> GetConstraintsByBoneName(USkeletalMeshComponent* SkeletalMeshComp, const FName& BoneName)
{
    TArray<UPhysicsConstraintTemplate*> Constraints;

    UPhysicsAsset* PhysicsAsset = SkeletalMeshComp->GetPhysicsAsset();
    if (!PhysicsAsset)
    {
        return Constraints;
    }

    for (UPhysicsConstraintTemplate* ConstraintTemplate : PhysicsAsset->ConstraintSetup)
    {
        if (!ConstraintTemplate)
        {
            continue;
        }

        FName BoneName1 = ConstraintTemplate->DefaultInstance.ConstraintBone1;
        FName BoneName2 = ConstraintTemplate->DefaultInstance.ConstraintBone2;

        if (BoneName1 == BoneName || BoneName2 == BoneName)
        {
            Constraints.Add(ConstraintTemplate);
        }
    }

    return Constraints;
}


bool UPhysicsFunctions::SetConstraintReferencePosition_BP(
    EBlueprintConstraintFrame Frame,
    FVector RefPosition,
    UPhysicsAsset* PhysicsAsset,
    int32 ConstraintIndex
)
{
    if (!PhysicsAsset || !PhysicsAsset->ConstraintSetup.IsValidIndex(ConstraintIndex))
    {
        UE_LOG(LogTemp, Warning, TEXT("SetConstraintReferencePosition_BP: Некорректный ConstraintIndex."));
        return false;
    }

    UPhysicsConstraintTemplate* ConstraintTemplate = PhysicsAsset->ConstraintSetup[ConstraintIndex];

    FConstraintInstance& ConstraintInstance = ConstraintTemplate->DefaultInstance;

    EConstraintFrame::Type ConstraintFrame;
    switch (Frame)
    {
    case EBlueprintConstraintFrame::Frame1:
        ConstraintFrame = EConstraintFrame::Frame1;
        break;
    case EBlueprintConstraintFrame::Frame2:
        ConstraintFrame = EConstraintFrame::Frame2;
        break;
    default:
        UE_LOG(LogTemp, Warning, TEXT("SetConstraintReferencePosition_BP: Неизвестный фрейм."));
        return false;
    }

    ConstraintInstance.SetRefPosition(ConstraintFrame, RefPosition);

    return true;
}


FVector UPhysicsFunctions::GetConstraintReferencePosition_BP(
    EBlueprintConstraintFrame Frame,
    UPhysicsAsset* PhysicsAsset,
    int32 ConstraintIndex,
    bool& bSuccess
)
{
    bSuccess = false;

    if (!PhysicsAsset || !PhysicsAsset->ConstraintSetup.IsValidIndex(ConstraintIndex))
    {
        UE_LOG(LogTemp, Warning, TEXT("GetConstraintReferencePosition_BP: Некорректный PhysicsAsset или ConstraintIndex."));
        return FVector::ZeroVector;
    }

    UPhysicsConstraintTemplate* ConstraintTemplate = PhysicsAsset->ConstraintSetup[ConstraintIndex];
    if (!ConstraintTemplate)
    {
        UE_LOG(LogTemp, Warning, TEXT("GetConstraintReferencePosition_BP: ConstraintTemplate не найден."));
        return FVector::ZeroVector;
    }

    const FConstraintInstance& ConstraintInstance = ConstraintTemplate->DefaultInstance;

    EConstraintFrame::Type ConstraintFrame;
    switch (Frame)
    {
    case EBlueprintConstraintFrame::Frame1:
        ConstraintFrame = EConstraintFrame::Frame1;
        break;
    case EBlueprintConstraintFrame::Frame2:
        ConstraintFrame = EConstraintFrame::Frame2;
        break;
    default:
        UE_LOG(LogTemp, Warning, TEXT("GetConstraintReferencePosition_BP: Неизвестный фрейм."));
        return FVector::ZeroVector;
    }

    FTransform RefTransform = ConstraintInstance.GetRefFrame(ConstraintFrame);

    FVector RefPosition = RefTransform.GetLocation();

    bSuccess = true;
    return RefPosition;
}

TArray<FConstraintInfo> UPhysicsFunctions::GetAllConstraintsInfo(UPhysicsAsset* PhysicsAsset, bool& bSuccess)
{
    TArray<FConstraintInfo> ConstraintsInfo;
    bSuccess = false;

    int32 ConstraintCount = PhysicsAsset->ConstraintSetup.Num();

    for (int32 Index = 0; Index < ConstraintCount; ++Index)
    {
        UPhysicsConstraintTemplate* ConstraintTemplate = PhysicsAsset->ConstraintSetup[Index];
        if (ConstraintTemplate)
        {
            FConstraintInfo Info;
            Info.Index = Index;
            Info.Name = ConstraintTemplate->GetName();
            ConstraintsInfo.Add(Info);
        }
    }

    bSuccess = true;
    return ConstraintsInfo;
}

.h:

	UFUNCTION(BlueprintCallable, Category = "Physics")
	static bool SetConstraintReferencePosition_BP(
		EBlueprintConstraintFrame Frame,
		FVector RefPosition,
		UPhysicsAsset* PhysicsAsset,
		int32 ConstraintIndex
	);

	UFUNCTION(BlueprintCallable, Category = "Physics")
	static FVector GetConstraintReferencePosition_BP(
		EBlueprintConstraintFrame Frame,
		UPhysicsAsset* PhysicsAsset,
		int32 ConstraintIndex,
		bool& bSuccess
	);

	UFUNCTION(BlueprintCallable, Category = "Physics")
	static TArray<FConstraintInfo> GetAllConstraintsInfo(UPhysicsAsset* PhysicsAsset, bool& bSuccess);

And all strunc and enums in .h File:

UENUM(BlueprintType)
enum class EBlueprintConstraintFrame : uint8
{
	Frame1 UMETA(DisplayName = "Frame 1"),
	Frame2 UMETA(DisplayName = "Frame 2")
};

USTRUCT(BlueprintType)
struct FConstraintInfo
{
	GENERATED_BODY()

	UPROPERTY(BlueprintReadOnly, Category = "Physics")
	int32 Index;

	UPROPERTY(BlueprintReadOnly, Category = "Physics")
	FString Name;
};

I would like to draw your attention to the fact that my code works with Physis Asset instance.
I did it this way specifically so that I could more flexibly control the skeletons of different characters. If you just change the position of the constraints, it will apply to all meshes. That’s why I recommend creating temporary copies. Here’s the code for that:

UPhysicsAsset* UPhysicsFunctions::CreatePhysicsAssetInstance(USkeletalMeshComponent* SkeletalMeshComponent)
{
    UPhysicsAsset* OriginalPhysicsAsset = SkeletalMeshComponent->GetPhysicsAsset();
    UPhysicsAsset* PhysicsAssetInstance = DuplicateObject<UPhysicsAsset>(OriginalPhysicsAsset, SkeletalMeshComponent);
    if (!PhysicsAssetInstance)
    {
        UE_LOG(LogTemp, Warning, TEXT("CreatePhysicsAssetInstance: Failed to duplicate PhysicsAsset."));
        return nullptr;
    }
    return PhysicsAssetInstance;
}

void UPhysicsFunctions::ApplyPhysicsAssetInstance(USkeletalMeshComponent* SkeletalMeshComponent,UPhysicsAsset* PhysicsAssetInstance)
{
    SkeletalMeshComponent->SetPhysicsAsset(PhysicsAssetInstance, false);
    SkeletalMeshComponent->RecreatePhysicsState();
    UE_LOG(LogTemp, Log, TEXT("ApplyPhysicsAssetInstance: Applied physics asset instance to SkeletalMeshComponent."));
}

Do not forget past this include in your .h file:
include “PhysicsEngine/ConstraintInstance.h”
include “PhysicsEngine/PhysicsAsset.h”
Good luck to everyone with solving the problem. I’m also waiting for corrections to my code if you think they are needed. Engine version 5.3.2 (I’m not sure if this works on engine > 5.0).

After 10 minute of reserch finde this https://www.fab.com/listings/11c4ef85-c8e6-4377-adbb-99139c0e23fb
If someone has a lot of money and is incredibly annoyed by the problem that such things have appeared… I am not the creator of this, and now I am interested in how it works and whether it really helps, because I personally do not like my version, and I constantly feel how it works, but with very big “BUTs”. Maybe someone else will appear or the developers of Unreal will make a universal Check box to solve such problems like this. But write how have only 2 posible way of this problem.