[Unity] Unity에서 안 건드린 scale이 변한다면? SetParent의 함정

심지섭·2025년 5월 16일
0

Troubleshooting

목록 보기
1/1

이번에 프로젝트를 하다가, UI 오브젝트의 scale을 조정하지도 않았는데 자꾸 scale이 달라지는 현상을 발견했다.
처음엔 버그인 줄 알고 디버그 로그를 찍어가며 누가 scale을 바꾸는지 추적했지만, 알고보니 원인은 Transform.SetParent()의 동작 방식에 있었다.

유니티 Transform의 Scale

Unity의 Transform의 Scale은 World Scale = Parent World Scale * Child Local Scale와 같은 구조로 동작한다.
즉, 어떤 오브젝트를 SetParent()로 부모에 붙이는 순간, 부모의 scale에 맞춰 자식의 localScale이 자동으로 조정되는 것이 일반적이다.

SetParent()에는 worldPositionStays 라는 매개변수가 있다.
이 값을 true로 설정하면(디폴트가 true), Unity는 자식 오브젝트가 월드 좌표계 기준으로 localScale을 강제로 조정한다.

예를 들어 부모가 (0.5, 0.5, 0.5)라면, 자식의 localScale(2, 2, 2)처럼 자동으로 바뀌게 된다.
그래야 월드 기준으로 동일한 크기를 유지할 수 있기 때문이다.
이러한 문제때문에 SetParent()를 사용할 때는 부모의 scale을 잘 고려해야하고, 되도록이면 scale을 1로 유지하는게 바람직하다.

Canvas Scaler의 Scale With Screen Size 모드

문제를 꼬이게 만든 것은 바로 Canvas ScalerScale With Screen Size 모드 였다.
이것은 설정에 따라 해상도에 맞춰 Canvas 자체의 scale을 자동으로 조정한다.
예를들어 Reference Resolution을 설정해두면 Rect Transform의 Width와 Height를 설정해둔 해상도 값으로 맞춰두고, 설정 해상도 대비 현재 화면 해상도의 비율값만큼 해당 canvas의 scale에 적용한다. 이렇게 Canvas ScalerScale With Screen Size는 scale을 조정하는 방식으로 해상도를 자동으로 맞춰준다.
아래 스크린샷을 보면 현재 해상도가 QHD일 때, Reference Resolution을 FHD로 설정해두면 scale이 1.333333이 되는 것을 확인할 수 있다.

이 둘의 환장(?)의 콜라보

그럼 다시 본론으로 돌아가 보자.
무엇이 문제였냐면…
이 프로젝트에서는 미리 만들어 둔 UI 오브젝트 프리팹을 필요한 만큼 Instantiate해서, SetParent()를 통해 UI Canvas 안으로 넣는 과정에서 발생했다.
이 과정에서 Canvas Scaler의 Scale With Screen Size 모드는 이미 화면 해상도에 따라 Canvas의 scale을 조정하고 있기 때문에, SetParent는 그걸 모른 채 다시 scale을 건드려버리는 상황이 생긴다.

즉,

  • Canvas는 해상도에 맞춰서 scale을 조정해놓았고,
  • Unity는 SetParent()를 하면서 또 scale을 조정하려고 든다.

결과적으로,

  • 월드 상에서는 자식 오브젝트의 scale이 변하지 않은 것처럼 보여야 하는데,
  • 실제로는 localScale이 예상치 못한 값으로 바뀌어버리고, 화면상의 크기도 미묘하게 틀어지게 된다.

두 시스템 모두 "잘 보이게 하겠다"고 나섰지만, 서로 조율 없이 각자 판단대로 scale을 만지다 보니 오히려 화면 출력이 꼬이는 아이러니한 상황이 생긴 것이다.

해결방안

이런 현상을 방지하기위해 2가지 방안을 찾았다.

첫번째는 SetParent의 worldPositionStays 매개변수를 false로 해주는 것이다.

두번째는 월드에 생성하고 Canvas의 자식으로 넣는 과정에서 문제가 생기는 것이므로, 그냥 아예 생성 자체를 Canvas의 자식으로 바로 넣어버리면 문제가 해결된다.

물론 Instantiate을 안하고 미리 씬에 배치해두고 활성/비활성화하는 방법도 있었다. 그러나 상황에 따라 매번 생성해야하는 개수가 달라지고, 성능 또한 위 두 방법도 스테이지 시작 전 초기화 단계에서만 실행되기에 크게 차이가 날 것이라고 생각하지 않아서, 유지보수 편의성을 위해 미리 씬에 배치하는 방법은 채택하지 않았다.

교훈

SetParent()를 사용할 때, 부모의 scale을 조심하자. (되도록이면 1로 유지)

특히 Canvas Scaler의 Scale With Screen Size 모드와 함께 사용할 땐 더더욱 주의하자.

Unity의 "도와주려고 해주는 일"이 꼭 내가 원하는 일은 아닐 수 있다.

profile
게임 개발을 하며 배운 것과 경험한 것을 기록하는 공간입니다.

0개의 댓글