✅  기능

Unity에서 MeshRenderer가 아닌 SpriteRenderer(이미지 렌더러)는 파이프라인에서 카메라 정면 방향을 기준으로 3D세계의 정점(벡터)의 위치가 아닌 단순히 Sorting 및 Order에 의해 렌더링 되는 순서가 달라집니다. 이는 Canvas에서 Order을 정하는 방식과 유사합니다. SpriteRenderer을 이용하여 월드를 구성할 때, Ordering을 적절히 해야 자연스러운 연출이 가능합니다. 자연스러운 Ordering을 하기 위한 간단한 방법과 스크립트를 정리하였습니다.

 

✅  적용 전

유니티에서 SpriteRenderer은 위치 기반이 아닌 Order에 의해 달라진다. 위치에 대해서는 영향이 없다는점을 꼭 알아두자.
나무에서 이미지들이 비 정상적으로 렌더링되는것을 볼 수 있다.

 

✅  흐름도

런타임 도중 움직이는 대상과, 움직이지 않는 대상에 대하여 서로 다른 알고리즘을 사용합니다.

 

✅ 사용(적용) 예시

정상적으로 렌더링 된 것을 볼 수 있다.

 

✅ 구현

1. 런타임 중 움직이지 않는 물체

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameManager : Singleton<GameManager>
{
    [SerializeField] private int mSortingOrderGap = 100;
    public int SortingOrderGap
    {
        get
        {
            return mSortingOrderGap;
        }
    }

    private void Awake()
    {
        SortingSpriteOrder();
    }

    private void SortingSpriteOrder()
    {
        foreach(SpriteRenderer renderer in FindObjectsOfType<SpriteRenderer>())
        {
            renderer.sortingOrder = -(int)(renderer.gameObject.transform.position.z * mSortingOrderGap) + renderer.sortingOrder;
        }
    }
}
[SerializeField] private int mSortingOrderGap = 100;
  • Z좌표를 기준으로 Sorting을 할 때, 소수점 단위를 올려주기 위한 수 입니다.
  • 예를들어 Z좌표가 1.05f, 1.50f인 SpriteRenderer가 두개 있을때, Ordering을 하면 모두 1로 나오게 됩니다.
  • 이를 해결하고 더욱 정밀하게 Sorting을 하기 위해 Gap을 사용합니다.

 

private void SortingSpriteOrder()
  • GameManager.cs에서 Awake에 의해 호출됩니다.
  • 씬 내의 모든 SpriteRenderer을 찾고, 해당 오브젝트의 위치를 기반으로 Order in Layer가 정렬됩니다.

 

2. 런타임 중 움직이지 않는 물체

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SpriteSortingOrder : MonoBehaviour
{
    private SpriteRenderer[] mSpriteRenderers;
    private int[] mOriginSortingOrders;

    private void Awake()
    {
        mSpriteRenderers = GetComponentsInChildren<SpriteRenderer>(true);

        mOriginSortingOrders = new int[mSpriteRenderers.Length];
        for(int i = 0; i < mSpriteRenderers.Length; ++i)
        {
            mOriginSortingOrders[i] = mSpriteRenderers[i].sortingOrder;
        }
    }

    private void OnEnable()
    {
        Sort();
    }

    private void Update()
    {
        Sort();
    }

    private void Sort()
    {
        for(int i = 0; i < mSpriteRenderers.Length; ++i)
        {
            mSpriteRenderers[i].sortingOrder = -(int)(mSpriteRenderers[i].gameObject.transform.position.z * GameManager.Instance.SortingOrderGap) + mOriginSortingOrders[i];
        }
    }
}
private SpriteRenderer[] mSpriteRenderers;
private int[] mOriginSortingOrders;
  • 자식 오브젝트의 SpriteRenderer을 저장하고, 미리 지정되어있는 Sorting Order을 저장합니다.
  • OriginSortingOrder가 있어야 런타임 도중 미리 지정해둔 순서가 변형되지 않습니다.

 

private void Sort()
  • Order을 정렬합니다. GameManager.cs에서 다룬 정렬과 같은 알고리즘입니다.

 

✅ 도움받은곳 (References)

 

2D Sprites in 3D world, depth sorting issue

Hello folks, I'm new to Unity as I am starting to transfer a large Flash MMO game to Unity. The game is a 2.5D perspective game. It uses an oblique...

forum.unity.com

 

 

should you exclusively use sorting layers instead of order in layer?

I find myself being confused about working with sorting orders in the GUI since they are just magic numbers. For example, if I have a player sprite on...

forum.unity.com

 

bonnate