Quick Comparison
Transform의 local 값은 부모 기준, world 값은 씬 기준입니다. Inspector에서 GameObject Transform에 보이는 Position·Rotation·Scale은 보통 local 값으로 읽으며, API가 local/world 중 어느 공간을 바꾸는지 먼저 고릅니다.
| 목적 | 읽기/쓰기 API | 부모가 바뀌면 | 대표 사례 |
|---|---|---|---|
| 씬의 절대 위치·방향 | position, rotation | world pose를 유지하려면 계산 필요 | spawn 위치, raycast 결과에 맞추기 |
| 부모에 대한 장착 위치·방향 | localPosition, localRotation | 부모 이동·회전에 함께 변함 | 손의 무기, UI child, camera rig |
| local 크기 설정 | localScale | parent scale과 합쳐진 world 크기 | prefab 내부 크기 조정 |
| hierarchy 재배치 | SetParent(parent, worldPositionStays) | bool에 따라 local/world 보존이 갈림 | 장착·detach, UI reparent |
transform.position = new Vector3(0f, 1f, 0f); // world 위치
transform.localPosition = new Vector3(0f, 0f, 2f); // 부모 기준 위치Inspector와 좌표 변환
Transform Inspector의 Position·Rotation·Scale은 parent가 있는 GameObject에서 local transform 값입니다. position은 부모의 위치·회전·scale을 합성한 world position이고, rotation은 world rotation입니다. world pose를 직접 설정하면 Unity가 현재 parent를 기준으로 local 값을 다시 계산합니다.
localScale은 부모 scale과 독립적인 최종 world scale이 아닙니다. lossyScale은 합성된 world scale을 읽어 볼 수 있지만 read-only 근사값이며, 특히 부모에 non-uniform scale과 회전이 섞이면 단순한 local 값 역산이나 mesh·Collider 기대가 틀어질 수 있습니다. dynamic Rigidbody나 character hierarchy에 non-uniform scale을 계속 애니메이션하는 설계는 물리·충돌 모양까지 따로 검증합니다.
// 부모 기준으로 muzzle에 붙은 effect를 배치합니다.
effectTransform.localPosition = muzzleOffset;
effectTransform.localRotation = Quaternion.identity;
// hit point처럼 월드 좌표가 이미 주어진 경우에는 position을 사용합니다.
impactTransform.position = hit.point;
impactTransform.rotation = Quaternion.LookRotation(hit.normal);SetParent와 재배치
SetParent(parent)의 기본 worldPositionStays 값은 true입니다. 새 parent를 붙인 뒤에도 현재 world position·rotation·scale이 유지되도록 local 값을 계산합니다. 장착 슬롯처럼 새 부모 기준 local offset을 바로 적용할 때는 false를 사용한 뒤 local 값들을 명시하는 편이 읽기 쉽습니다.
public void AttachTo(Transform socket)
{
transform.SetParent(socket, worldPositionStays: false);
transform.localPosition = Vector3.zero;
transform.localRotation = Quaternion.identity;
transform.localScale = Vector3.one;
}
public void DropAt(Vector3 worldPosition)
{
transform.SetParent(null, worldPositionStays: true);
transform.position = worldPosition;
}worldPositionStays: false는 "world pose를 버리고 current local 값의 의미를 새 parent 아래에서 유지"하는 선택입니다. SetParent 후 localScale = Vector3.one을 무조건 넣으면 prefab이 의도한 크기를 지울 수 있으므로, socket의 scale policy를 먼저 정합니다.
이동 API의 좌표계
Transform.Translate도 Space.World와 Space.Self에 따라 이동축이 달라집니다. TransformDirection은 local direction을 world direction으로, InverseTransformPoint는 world point를 local point로 변환할 때 사용합니다. target의 "앞쪽"으로 움직여야 하는지, 씬 Z축 방향으로 움직여야 하는지 말로 먼저 정하면 API 선택이 명확해집니다.
Rigidbody가 붙어 물리를 소유하는 object는 Transform을 frame마다 직접 쓰는 대신 Rigidbody API와 physics update를 사용합니다. Transform parent 관계를 바꾸는 순간에도 Rigidbody·Collider·Animator·Cinemachine이 어느 Transform을 소유하는지 점검합니다.
자주 틀리는 부분
| 증상 | 원인 | 수정 |
|---|---|---|
| child가 world origin으로 날아감 | 장착 offset에 position = Vector3.zero 사용 | parent 기준 배치에는 localPosition 사용 |
| reparent 뒤 object가 엉뚱한 곳에 있음 | worldPositionStays 기본값을 의도하지 않음 | world 보존/로컬 보존을 bool로 명시 |
| 부모 scale 아래 mesh·Collider가 이상함 | non-uniform scale을 단순 크기 값으로 취급 | hierarchy scale·회전 조합과 physics를 실제 scene에서 검증 |
| Transform과 Rigidbody 이동이 충돌 | 서로 다른 update 루프가 같은 pose를 씀 | pose 소유자를 하나로 정하고 FixedUpdate 정책 맞춤 |
| inspector 값과 code 로그가 다름 | Inspector local과 position world를 비교 | 같은 좌표계의 값끼리 비교 |
참고 링크
3 sources