Description

When using AddOrUpdateWarpTargetFromComponent you can pass in a SceneComponent, Relative Location and Rotation as well as optionally choosing to have the warp target follow the object if it moves.If you pass in a SceneComponent with scale in the transform while bFollowComponent is true the Cached Target calculation ends up getting messed up by that scale.

From a licensee:

FMotionWarpingTarget::FMotionWarpingTarget(const FName& InName, const USceneComponent* InComp, FName InBoneName, bool bInFollowComponent, const FVector& InLocOffset, const FRotator& InRotOffset)
{
	if (ensure(InComp))
	{
		Name = InName;
		Component = InComp;
		BoneName = InBoneName;
		bFollowComponent = bInFollowComponent;
		LocationOffset = InLocOffset;
		RotationOffset = InRotOffset;

		FTransform Transform = FTransform::Identity;
		if (BoneName != NAME_None)
		{
			Transform = FMotionWarpingTarget::GetTargetTransformFromComponent(InComp, InBoneName);
		}
		else
		{
			Transform = InComp->GetComponentTransform();
		}

		Transform = FTransform(RotationOffset, LocationOffset) * Transform;

		Location = Transform.GetLocation();
		Rotation = Transform.Rotator();
	}
} 

 
At creation time notice that the scale is used when dealing with the offset location and rotation which is likely correct, but doesn't propagate any further.

FTransform FMotionWarpingTarget::GetTargetTrasform() const
{
	if (Component.IsValid() && bFollowComponent)
	{
		FTransform Transform = FTransform::Identity;
		if (BoneName != NAME_None)
		{
			Transform = FMotionWarpingTarget::GetTargetTransformFromComponent(Component.Get(), BoneName);
		}
		else
		{
			Transform = Component->GetComponentTransform();
		}

		return FTransform(RotationOffset, LocationOffset) * Transform;
	}

	return FTransform(Rotation, Location);
} 

 
In GetTargetTransform() though if bFollowComponent is true the resulting transform is returned INCLUDING the scale from any scaled component.
 
Down in URootMotionModifier_Warp::Update
This transform is used to transform anim provider offsets and then stored away for the modifiers to use in their warping.
 
SkewWarp luckly ends up only using the Location and Rotation from the cached transform.
 
But unfortunately if you are using an anim provider offset the transform is already incorrect when it is cached off in URootMotionModifier_Warp::Update.
 
A fix would be to not allow the scale to get outside of FMotionWarpingTarget::GetTargetTransform()

FTransform FMotionWarpingTarget::GetTargetTrasform() const
{
	if (Component.IsValid() && bFollowComponent)
	{
		FTransform Transform = FTransform::Identity;
		if (BoneName != NAME_None)
		{
			Transform = FMotionWarpingTarget::GetTargetTransformFromComponent(Component.Get(), BoneName);
		}
		else
		{
			Transform = Component->GetComponentTransform();
		}

		FTransform TargetTransformWithScale = FTransform(RotationOffset, LocationOffset) * Transform;
		return FTransform(TargetTransformWithScale.GetRotation(), TargetTransformWithScale.GetLocation());
	}

	return FTransform(Rotation, Location);
} 

 

Steps to Reproduce

Steps to repro the old behavior are in the description

Have Comments or More Details?

There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-305176 in the post.

0
Login to Vote

Fixed
ComponentUE - Anim - Gameplay
Affects Versions5.4
Target Fix38.00
Fix Commit44196951
CreatedJul 15, 2025
ResolvedJul 21, 2025
UpdatedAug 11, 2025
View Jira Issue