개발블로그
[유니티 UGUI] UI의 부모 Canvas와 depth 관리를 위한 Canvas의 분할과 드로우 콜 최적화 방법 본문
🤷♀️
게임을 개발할 때 UI는 거의 필수적인 요소로 들어가게 된다.
유니티에서 UI를 배치할 때 모든 UI 요소는 Canvas 안에 위치해야 하므로 모든 UI의 부모인 Canvas를 뜯어보고,
Canvas를 여러 개로 분할하여 사용하며 UI의 depth 관리를 용이하게 하는 방법과 불필요한 낭비를 줄이는 최적화 방법 또한 정리를 해 보려고 한다.
🔶 Canvas
캔버스는 Canvas 컴포넌트가 있는 UI의 기본 컴포넌트이며, 모든 UI 요소는 캔버스 안에 위치해야 한다.
하이어라키 뷰에서 UI 요소를 생성할 때, 캔버스가 없는 경우에는
Create > UI > Image로 이미지를 생성하면 자동으로 캔버스를 생성하며 Image는 캔버스의 자식으로 생성된다.
캔버스가 없는 상태에서 Image 컴포넌트를 눌러서 Image를 생성해보자. 그림-1
Image가 자동으로 Canvas의 자식으로 생성된다. 그림-2
✔ 그렇다면 이미 Canvas가 있는 상태에서 Button을 추가해보면 어떻게 될까?
이미 Canvas가 있기 때문에 UI 요소를 추가하면 생성되어 있던 Canvas로 자동으로 들어간다.
(꼬리에 꼬리를 무는 궁금증)
🤷♀️ Canvas를 분할해서 사용할 시, UI 요소를 추가하면 어떤 Canvas로 들어갈까?
캔버스를 3개 생성 후 구분하기 쉽게 빈 게임오브젝트(Create Empty)로 구분선을 만들어주었다.
(구분선의 용도는 그냥 내가 구분하려고 만든 것이기 때문에 큰 쓸모는 없다.)
하이어라키뷰에 캔버스를 3개 배치 후에 Image 컴포넌트를 추가해보았다.
Canvas를 분할해서 여러 개 사용하는 상황에서는
UI요소를 추가하면 하이어라키 뷰 상 가장 마지막 순서에 있는 캔버스를 찾아 자동으로 UI 요소가 들어가게 된다. 그림2-1
✔ 캔버스의 분할, 캔버스를 분할해서 사용하는 이유는?
캔버스를 분할해서 사용하는 경우는 크게 두 가지로 볼 수 있겠다.
(1) 씬에 배치한 UI 요소들의 Depth관리를 용이하게 하기 위함.
(2) UI 요소들이 변경 될 때 메시를 다시 생성하기 때문에 드로우 콜 횟수를 줄이기 위함.
(1) 첫 번째 방법, Depth 관리
첫 번째 방법은 씬에 여러 UI 요소를 배치할 때, UI의 Depth를 분할된 캔버스의 레이어를 변경해서 위치를 용이하게 바꿀 수 있다.
Photoshop 에서의 레이어 개념을 이해하면 쉬운데, 포토샵에서는 레이어가 위에 올라와있을 수록 가장 위에 그려지지만유니티에서는 그 반대로 캔버스 내에서 순서가 가장 밑에 있는 것이 가장 위로그려진다.
💁♀️ 하지만 주의할 점이 있다.
캔버스를 분할 후 캔버스마다 레이어를 변경해주지 않는다면 같은 레이어로 인식해서
depth가 변경 되지 않을 수 있기 때문에 캔버스 분할 후 꼭 레이어를 나눠서 변경해줘야 한다.
캔버스를 각각 3개씩 만들어서 Layer와 Sort Order를 변경해주었다.
Canvas_1은 Layer를 UI_1로 변경하고, Sort Order를 1로 변경했다. 나머지 캔버스들도 동일하게 (2, 3 ...) 으로 작업했다.
✔ 런타임 시 이렇게 되도록 작업을 해보려 한다.
(1) 화면이 페이드아웃 된다. - Canvas_1에서 작업
(2) 버튼이 보인다. - Canvas_2 에서 작업
(3) 버튼을 클릭하면 토스트 메세지가 나타난다. - Canvas_3 에서 작업
FadeManager.cs
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class FadeManager : MonoBehaviour
{
[SerializeField] Image _imgDim = null;
[SerializeField] float _fadeOutTime = 0f;
void Start()
{
StartCoroutine(CoFadeOut(_fadeOutTime));
}
IEnumerator CoFadeOut(float fadeOutTime)
{
Color dimColor = _imgDim.color;
while (dimColor.a >= 0f)
{
dimColor.a -= Time.deltaTime / fadeOutTime;
_imgDim.color = dimColor;
if (dimColor.a <= 0)
{
dimColor.a = 0f;
_imgDim.gameObject.SetActive(false);
}
yield return null;
}
_imgDim.color = dimColor;
}
}
ToastMsg.cs
using UnityEngine;
public class ToastMsg : MonoBehaviour
{
[SerializeField] GameObject _gbjMsg = null;
public void OnBtnToast()
{
_gbjMsg.SetActive(true);
}
}
씬을 실행하면 Canvas_3 에 있는 FadeManager가 depth상 가장 마지막에 있으므로 가장 위쪽에 올라온다.
이후에 Canvas_1에 있는 Button(BtnToast)을 클릭하면 Canvas_2에 있는 토스트 메세지가 버튼의 위로 렌더링된다.
이를 통해 UI depth 구조를 캔버스 레이어를 통해서 효과적으로 관리하는 방법을 알아봤다.
(2) 두번째 방법, 드로우콜 낭비 최소화.
두번째 방법은 드로우 콜의 낭비를 줄이기 위함인데,
한가지 캔버스에 여러 UI를 다 넣었을 때 그 중 한가지 요소만 변경되도 캔버스는 전체가 변경된 것으로 인식한다.
UI 요소가 변경될 때 마다 캔버스는 메시를 다시 생성하며, GPU에 드로우 콜을 발행하여 UI가 표시되게 한다.
이런 메시를 생성하는 것은 많은 자원이 소모되므로 UI요소를 잘 배치해서 드로우 콜 횟수를 줄여서 최적화 하는 것이 좋다.
UI가 그려지는 과정은 프레임 디버거(Frame Debugger)를 실행해서 알 수 있다.
프레임 디버거는 게임에서 각 프레임이 그려질 때 어떤 과정을 거쳐서 그려지는지 보여주는 편리한 디버깅 툴이다.
그럼 위와 같이 그림 4-1 프레임 디버거 창이 나타난다.
프레임 디버거 창을 띄운 뒤 실행하고 프레임 디버거 창에서 Enable 버튼을 누르면
한 프레임이 그려지는데 어떤 과정으로 몇단계를 거쳐서 실행하는지 확인할 수 있다.
* 공부하는 단계입니다. 잘못된 정보가 있다면 피드백 부탁드립니다😊
* e-mail : heehee970@naver.com
'Unity > UI' 카테고리의 다른 글
[유니티 UGUI] Image와 Sprite의 차이점. 그리고 Panel (0) | 2021.07.22 |
---|---|
[유니티 UGUI] 퍼즐 게임에서 많이 사용하는 스테이지 UI, 그리고 Image 컴포넌트의 Maskable (0) | 2021.07.22 |
[유니티 UGUI] RectTransform (0) | 2021.07.15 |
게임에서의 UI(User Interface)와 UX(User Experience)의 차이점 (0) | 2021.07.15 |