본문 바로가기
C#/Unity

Unity 레이어 및 레이어 마스크 사용법

by GangDev 2024. 4. 18.

개요

유니티의 레이어(Layer)는 게임 오브젝트를 분류하고, 특정 프로세스나 계산에서 선택적으로 포함하거나 제외하는 데 사용된다.

레이어를 사용하면 게임 오브젝트를 효율적으로 관리하고, 렌더링, 조명, 물리 충돌 등에 적용될 수 있다.

 

레이어를 사용하면 게임 오브젝트를 효율적으로 관리하고, 게임의 성능을 최적화할 수 있다.

레이어는 게임 오브젝트를 분류하고, 특정 프로세스나 계산에서 선택적으로 포함하거나 제외하는 데 사용되며, 이는 게임의 다양한 요소를 효율적으로 관리하는 데 중요한 역할을 한다.

 

레이어 생성 방법

레이어는 다음과 같은 방법으로 생성하고 게임 오브젝트에 할당할 수 있다:

* 레이어 생성:

유니티 에디터에서 "Edit > Project Settings > lTags and Layers"를 선택하여 태그 및 레이어 관리자 창을 열고, 사용자 레이어 중 하나를 선택하여 새 레이어를 생성한다.

* 레이어 할당:

생성한 레이어를 게임 오브젝트에 할당하려면, 게임 오브젝트의 인스펙터(Inspector) 창에서 "Layer" 드롭다운 메뉴를 열고, 생성한 레이어를 선택한다.

 

레이어 용도

레이어는 다음과 같은 용도로 사용된다:

* 렌더링 최적화:

카메라의 렌더링 마스크를 설정하여, 특정 레이어의 오브젝트만 렌더링하도록 할 수 있다.

이는 게임의 렌더링 성능을 향상시키는 데 중요한 역할을 한다.

 

조명 최적화:

조명 컴포넌트의 조명 마스크를 설정하여, 특정 레이어의 오브젝트만 조명하도록 할 수 있다.

이는 게임의 시각적 품질을 향상시키는 데 중요한 역할을 한다.

 

물리 충돌 최적화:

물리 충돌 설정에서 특정 레이어의 오브젝트만 충돌하도록 설정할 수 있다.

이는 게임의 물리 성능을 향상시키는 데 중요한 역할을 한다.

 

레이어 마스크(Layer Mask):

레이어 마스크를 사용하여, 특정 레이어의 오브젝트만 감지하거나 무시하도록 설정할 수 있다.

예를 들어, 레이캐스팅(Raycasting)을 사용할 때 특정 레이어의 오브젝트만 감지하도록 설정할 수 있다.

 

레이어 마스크 원리

유니티의 레이어 마스크는 특정 레이어에 속한 오브젝트만 카메라에 노출되도록 포함시키거나, 반대로 노출에서 제외시키는 기능을 제공한다.

이는 게임 오브젝트의 선별적인 렌더링(rendering)을 가능하게 한다.

레이어 마스크는 카메라의 렌더링 마스크(Culling Mask)를 설정할 때 주로 사용되며, 이를 통해 특정 레이어의 오브젝트만 할 수 있다.

 

레이어 마스크는 다음과 같은 방법으로 설정하고 사용할 수 있다:

* 레이어 마스크 설정:

유니티 에디터에서 레이어 마스크를 설정하는 가장 간단한 방법은 유니티의 LayerMask 클래스를 사용하는 프로퍼티를 만드는 것이다.

프로퍼티가 public이거나 SerializerField 속성을 사용하는 경우, 유니티는 레이어 마스크가 나타내는 레이어를 선택하는 데 사용할 수 있는 인터페이스를 인스펙터에서 제공한다.

 

using UnityEngine;

public class LayerMaskExample : MonoBehaviour
{
    [SerializeField] private LayerMask layermask;
}

 

* 레이어 전환:

런타임 시 스크립트에서 레이어를 레이어 마스크로 전환하려면, 바이너리 왼쪽 시프트 연산자를 사용하여 레이어에서 1을 왼쪽 시프트한다.

그 결과 단일 레이어를 나타내는 레이어 마스크로 전환된다.

 

using UnityEngine;

public class LayerExample : MonoBehaviour
{
    [SerializeField] private int layer = 10;
    private int layerAsLayerMask;

    private void Start()
    {
        layerAsLayerMask = (1 << layer);
    }
}

 

좀 더 자세히 설명하자면,

레이어를 레이어 마 스크로 전환하는 과정은 바이너리 왼쪽 시프트 연산자(<<)를 사용하여 이루어진다.

이 연산자는 왼쪽으로 비트를 이동시키는 역할을 하는데, 레이어 마스크는 32비트 정수(int)로 표현되며, 각 비트는 하나의 레이어를 나타낸다.

따라서, 레이어 마스크는 최대 32개의 레이어를 표현할 수 있다.

위 예시에서, 1<< layer의 연산은 1을 왼쪽으로 10번 시프트하여, 10번째 비트만 1로 설정된 레이어 마스크를 생성한다.

이는 레이어 10만을 포함하는 레이어 마스크를 나타낸다.

 

레이어 마스크는 비트 연산을 통해 여러 레이어를 조합할 수 있다.

예를 들어, 레이어 2와 레이어 3을 조합하려면 다음과 같이 나타낼 수 있다.

var layerMask = (1 << 2) | (1 << 3);

 

여기서 | 연산자는 비트 OR 연산자로, 두 레이어 마스크의 각 비트를 비교하여 결과 레이어 마스크를 생성한다.

이 경우, 2번쨰와 3번째 비트만 1로 설정된 레이어 마스크를 생성하며, 이는 레이어 2와 레이어 3을 포함하는 레이어 마스크를 나타낸다.

 

레이어 마스크는 게임 오브젝트를 효율적으로 관리하고, 게임의 성능을 최적화하는 데 중요한 역할을 한다.

예를 들어, 레이어 마스크를 사용하면 월드 공간의 게임 오브젝트를 선택(Picking)하기 위해 광선(Ray)이 발사되었을 때, 특정 오브젝트만 충돌에 반응할 수 있도록 허용하거나, RigidBody 컴포넌트를 지닌 게임 오브젝트가 특정한 게임 오브젝트와 충돌을 하더라도 이를 무시할 수 있도록 충돌 감지(Collider Detection)의 대상(Target)에서 해당 오브젝트를 제외시킬 수 있다.

또한, 유니티 스크립트에서 게임 오브젝트의 레이어를 레이어의 순서(Index)를 의미하는 숫자 형식으로 지정할 수 있으며, NameToLayer 메서드를 이용해서 레이어의 이름(Name)을 문자열(String) 형식으로 전달하는 방법도 있다.

 

tempObj.layer = 8; // 레이어의 순서를 숫자로 지정
tempObj.layer = LayerMask.NameToLayer("Monster"); // 레이어의 이름을 문자열로 지정

 

레이어와 레이어 마스크의 차이

* 레이어:

모든 게임 오브젝트는 단일 레이어에 존재한다.

레이어는 표준 정수로 표현되며, 게임 오브젝트를 분류하고, 특정 프로세스나 계산에서 선택적으로 포함하거나 제외하는 데 사용된다.
예를 들어, 레이어를 사용하여 특정 레이어의 오브젝트만 렌더링하거나, 물리 충돌 감지에서 특정 레이어의 오브젝트만 감지하도록 설정할 수 있다.

 

* 레이어 마스크:

레이어 마스크는 비트마스크로 포맷된 정수로, 여러 레이어를 조합하여 특정 프로세스나 계산에서 선택적으로 포함하거나 제외하는 데 사용된다.레이어 마스크는 모든 1은 포함할 레이어를 나타내고, 모든 0은 제외할 레이어를 나타낸다.

즉, 레이어 마스크를 사용하면 여러 레이어의 오브젝트를 한 번에 관리할 수 있다.

 

예를 들어, 레이어 9에 있는 게임 오브젝트에 대해 레이캐스트를 수행하려는 경우, 9를 레이어 마스크로 전달하면 실제로는 Unityt에서 레이어 3과 레이어 0의 게임 오브젝트에 대해 레이캐스트를 수행한다.

이는 9의 이진법 표기가 00001001이고, 이를 마스크로 해석하면 3과 0자리에 1이 있기 때문이다.

 

레이어 마스크를 사용하면, 특정 레이어의 오브젝트만을 대상으로 하는 레이캐스팅이나 물리 충도 감지(Collision Detection) 등의 작업을 수행할 수 있다.

예를 들어, 레이어 마스크를 레이캐스트 API 호출에 전달하지 않으면 Unity는 Ignore Raycast를 제외한 모든 레이어와 일치하는 Physics.DefaultRaycastLayers를 사용한다.

레이어 마스크의 모든 비트가 켜져 있으면 레이는 모든 콜라이더에 충돌한다.

레이어 마스크가 = 0 이면 어떤 것도 레이와 충돌하지 않는다.

 

레이어 마스크가 단일 레이어(Single Layer)보다 더 유용한 경우

레이어 마스크는 단일 레이어를 직접 사용하는 것보다 더 넓은 범위의 게임 오브젝트를 효율적으로 관리하고, 복잡한 게임 로직을 구현하는 데 더 유연하게 사용될 수 있다.

또한, 성능 최적화와 관련하여 특정 레이어의 오브젝트만을 대상으로 하는 작업을 효율적으로 처리할 수 있다.

 

* 여러 레이어 대상 작업

레이어 마스크를 사용하면, 여러 레이어의 오브젝트를 한 번에 대상으로 하는 작업을 수행할 수 있다.

예를 들어, 레이캐스팅을 수행할 때, 특정 레이어의 오브젝트만 감지하도록 설정하는 것이 아니라, 여러 레이어의 오브젝트를 동시에 감지하도록 설정할 수 있다.

이는 게임의 다양한 요소를 효율적으로 관리하고, 특정 조건에 따라 여러 오브젝트를 동시에 처리할 때 유용하다.

 

* 복잡한 게임 로직에서의 유연성:

레이어 마스크는 복잡한 게임 로직을 구현할 때 더 유연하게 사용될 수 있다.

예를 들어, 특정 조건에 따라 여러 레이어의 오브젝트를 동시에 처리하거나, 특정 레이어의 오브젝트를 제외하는 등의 로직을 구현할 때, 레이어 마스크를 사용하면 이러한 조건을 쉽게 적용할 수 있다.

 

성능 최적화:

레이어 마스크를 사용하면, 특정 레이어의 오브젝트만을 대상으로 하는 작업을 효율적으로 처리할 수 있다.

예를 들어, 카메랄의 렌더링 마스크를 설정하여, 특정 레이어의 오브젝트만 렌더링하도록 할 수 있다.

이는 게임의 렌더링 성능을 향상시키는 데 중요한 역할을 한다.

 

물리 충돌 감지 설정:

레이어 마스크를 사용하면, 물리 충돌 감지에서 특정 레이어의 오브젝트만을 대상으로 하는 작업을 수행할 수 있다.

예를 들어, 특정 레이어의 오브젝트만 충돌하도록 설정하거나, 특정 레이어의 오브젝트를 충돌 감지에서 제외하는 등의 설정을 할 수 있다.

이는 게임의 물리 성능을 향상시키는 데 중요한 역할을 한다.

 

예시:

 

게임 내에서 플레이어가 벽을 향해 총을 발사할 때, 벽 오브젝트만을 대상으로 하는 레이캐스팅을 수행하고 싶을 수 있다.

이런 경우, 벽 오브젝트를 포함하는 레이어 마스크를 설정하고, 이 레이어 마스크를 Physics.Raycast 메서드에 전달하여 벽 오브젝트만을 대상으로 하는 레이캐스팅을 수행할 수 있다.

 

using UnityEngine;

public class ExampleScript : MonoBehaviour
{
    private float cameraRotation;

    void Start()
    {
        Camera.main.transform.position = new Vector3(0, 0.5f, 0);
        cameraRotation = 0.0f;
    }

    void Update()
    {
        if (Input.GetKey("left"))
        {
            cameraRotation -= 1f;
            if (cameraRotation < -45.0f)
            {
                cameraRotation = -45.0f;
            }
        }

        if (Input.GetKey("right"))
        {
            cameraRotation += 1f;
            if (cameraRotation > 45.0f)
            {
                cameraRotation = 45.0f;
            }
        }

        Camera.main.transform.localEulerAngles = new Vector3(0.0f, cameraRotation, 0.0f);
    }

    void FixedUpdate()
    {
        Transform transform = Camera.main.transform;

        if (Input.GetKeyUp("space"))
        {
            LayerMask mask = LayerMask.GetMask("Wall");

            if (Physics.Raycast(transform.position, transform.forward, 20.0f, mask))
            {
                Debug.Log("Fired and hit a wall");
            }
        }
    }
}

 

위 스크립트에서는 먼저 카메라의 위치와 회전을 설정하고, 사용자의 입력에 따라 카메라를 회전시킨다.

그리고 사용자가 스페이스 키를 누르면, "Wall" 레이어를 대상으로 하는 레이캐스팅을 수행한다.

이때, LayerMask.GetMask("Wall")을 사용하여 "Wall" 레이어를 포함하는 레이어 마스크를 생성하고, 이 레이어 마스크를 Physics.Raycast 메서드에 전달하여 벽 오브젝트만을 대상으로 하는 레이캐스팅을 수행한다.