Quick answer: Use KeepWorld if you want the attached child to stay at its current visible position. Use KeepRelative if you want to apply an existing local offset. Use SnapToTarget only if you want the child exactly at the parent’s transform. Typoed socket names fall back silently to the root.
Here is how to fix Unreal AttachActorToComponent wrong transform. You pick up a weapon actor and attach it to your character’s right hand socket. The weapon appears at the character’s feet, or at world origin, or rotated 90 degrees off. You set the weapon’s transform before attaching — no help. The attachment rules in Unreal’s AttachToComponent are three-way decisions that interact non-obviously with socket positions.
The Symptom
After calling AttachToComponent (C++) or Attach Actor To Component (Blueprint), the attached actor’s visible position is wrong:
- Appears at world origin (0,0,0)
- Appears at the parent’s pivot instead of the intended socket
- Position correct but rotation wrong
- Visibly jumps when attachment happens (expected: smooth snap to socket)
What Causes This
Attachment rule misunderstanding. Three options per component (Location, Rotation, Scale):
- KeepRelative: preserve existing relative transform (child keeps its local offset)
- KeepWorld: preserve world transform (child’s relative is recomputed)
- SnapToTarget: zero relative transform (child snaps exactly to parent pivot or socket)
Choosing “SnapToTarget” for location when you wanted “KeepWorld” snaps the child into the parent’s pivot — usually not where you want it unless a socket is specified.
Socket name typo or missing. AttachToComponent takes a SocketName parameter. If the socket does not exist on the target (skeletal or static mesh), attachment falls back to the component’s root. Silent misplacement.
Non-uniform scale interaction. A parent component with scale (2, 1, 1) applies that scale to children attached with SnapToTarget. A weapon attached to a zoomed-in character becomes oversized.
Order of operations. Setting transform before attachment with KeepRelative uses that transform as the post-attachment relative. Setting after attachment with KeepWorld recomputes relative based on world position. Understanding order prevents surprises.
The Fix
Step 1: Use the right attachment rules.
// Weapon in character's hand: snap exactly to hand socket
void AWeapon::Equip(AActor* Wearer, FName SocketName)
{
USkeletalMeshComponent* Mesh = Cast<ACharacter>(Wearer)->GetMesh();
if (Mesh)
{
AttachToComponent(Mesh,
FAttachmentTransformRules::SnapToTargetNotIncludingScale,
SocketName);
}
}
// Pickup item following player: preserve current world position
void APickup::Follow(AActor* Player)
{
AttachToActor(Player,
FAttachmentTransformRules::KeepWorldTransform);
}
// Child with existing authored local offset
void AAttachment::AttachWithOffset(USceneComponent* Parent)
{
AttachToComponent(Parent,
FAttachmentTransformRules::KeepRelativeTransform);
}
Predefined FAttachmentTransformRules constants save typing: KeepRelativeTransform, KeepWorldTransform, SnapToTargetNotIncludingScale, SnapToTargetIncludingScale.
Step 2: Verify socket names. Open the skeletal mesh asset. In the Skeleton editor, expand the skeleton tree and check sockets. Socket names are case-sensitive.
Test with a Blueprint breakpoint or log the result:
bool bSuccess = AttachToComponent(Mesh,
FAttachmentTransformRules::SnapToTargetNotIncludingScale,
TEXT("RightHandSocket"));
// Verify with:
FVector SocketPos = Mesh->GetSocketLocation(TEXT("RightHandSocket"));
UE_LOG(LogTemp, Log, TEXT("Socket at: %s, Actor at: %s"),
*SocketPos.ToString(), *GetActorLocation().ToString());
If the socket location and actor location match, attachment worked. If they diverge, the socket name is wrong or the attachment rule snapped elsewhere.
Step 3: Choose SnapToTargetIncludingScale carefully. Use NotIncludingScale if your child has authored scale you want to preserve (a weapon at scale 1 should stay at scale 1 even if the hand socket has non-unit scale). Use IncludingScale for snap-exactly-to-parent behavior, including any zoom.
Step 4: Detach with matching rules. When detaching, use similarly symmetric rules:
void AWeapon::Drop()
{
DetachFromActor(FDetachmentTransformRules::KeepWorldTransform);
// Weapon now sits at its visible world location
}
KeepWorldTransform on detach keeps the weapon in place visually. KeepRelativeTransform would revert to whatever local transform it had before attachment, which is rarely what you want.
Blueprint Equivalents
In Blueprint, Attach Actor To Component node has three dropdowns (Location/Rotation/Scale Rule) with the same three options each. Set based on the patterns above.
Common Gotcha: Instigator Transform
When spawning an actor and immediately attaching, the SpawnActor’s transform is ignored if you then SnapToTarget. Use KeepWorld if you want the spawn position to be the attached position:
AActor* Spawned = GetWorld()->SpawnActor<AActor>(Class, SpawnTransform);
Spawned->AttachToActor(Parent, FAttachmentTransformRules::KeepWorldTransform);
// Spawned stays at SpawnTransform, parent tracks it
“Attachment rules are a three-way choice times three axes. Pick intentionally, use the predefined constants, and verify with a log.”
Related Issues
For skeletal mesh issues, see Skeletal Mesh Merge Not Combining Materials. For UMG issues, UMG Widget Not Visible covers related Unreal setup gotchas.
KeepWorld for existing-position-is-good. SnapToTarget for snap-to-socket. KeepRelative for authored offset.