Unity - 레이어 마스크

땡구의 개발일지·2025년 5월 12일

Unity마스터

목록 보기
26/78
post-thumbnail

게임 오브젝트를 그룹으로 나누어서 처리하고 싶을 때 사용한다. 물리 처리에서 유용하다

레이어 마스크

  • Layer Mask
  • 게임 오브젝트들의 분류를 나누기 위한 용도로 쓰이는 기능. 태그랑 같은 기능이다. - 그래픽, 물리엔진과 같이 선별적으로 동작해야 하는 기준을 정할때 사용!
  • 충돌 처리할 때의 경우, 레이어를 사용하는 편. 프로젝트 세팅에서 레이어 충돌 처리를 설정할 수 있기 때문이다. 게임 오브젝트를 이름으로 간단하게 구분하고 싶다면 태그. 특정 그룹들 간의 처리를 한다면 레이어

레이어 설정

  • 카메라에서 원하는 물체만 표현하는 방법으로 레이어를 사용할 수도 있다

  • 이렇게 레이어를 직접 설정해 줄 수 있다

레이어 컬링

  • 메인 카메라를 선택 후, Culling Mask에서 표시할 레이어들만 선택할 수 있다. 여기서 큐브, 스피어만 체크하고 실린더는 체크 해제 해본다
  • 그러면 화면과 같이 게임 씬에서는 실린더가 제외되는 것을 볼 수 있다

비트 연산으로 레이어 제어

  • 유니티에서 레이어마스크는 32자리의 이진법(Bit)을 통해 표현
  • 런타임중 레이어를 변경해야 할 경우 문자열로도 레이어마스크를 제어할 수 있지만, 비트 연산을 사용하면 성능 면에서 이득을 볼 수 있다

비트 표현

  • 32개의 레이어 마스크를 사용할 수 있으며, 예시로 다섯번째 레이어를 선택하고자 한다면 코드는 아래와 같이 작성

비트 시프트로 레이어 선정

// 0, 어떤 레이어도 선택되지 않음
// 00000000000000000000000000000000
private int _layerMask = 0;

// 1을 좌측으로 0칸 이동, 즉 첫번째 레이어
// 00000000000000000000000000000001
private int _layerMask = (1 << 0);

// 1을 좌측으로 4칸 이동, 즉 다섯번째 레이어
// 00000000000000000000000000010000
private int _layerMask = (1 << 4);
  • 대상이 되는 레이어에 대해서는 1, 대상이 되지 않는 레이어에 대해서는 0으로 표기하므로, 정수형 숫자를 표기하기보다는 32자리의 bool타입 배열처럼 사용하는 것이다.

다른 방법으로 이해하기

  • 1번 레이어는 0000 0000 0000 0001(2)=200000\ 0000\ 0000\ 0001_{(2)} = 2^0
    • 0번 왼쪽으로 밀기
  • 2번 레이어는 0000 0000 0000 0010(2)=210000\ 0000\ 0000\ 0010_{(2)} = 2^1
    • 1번 왼쪽으로 밀기
  • 10번 레이어는 0000 0100 0000 0000(2)=220000\ 0100\ 0000\ 0000_{(2)} = 2^2
    • 9번 왼쪽으로 밀기

비트 연산자

기호의미설명
&AND이진법의 동일한 자리가 둘 다 1이라면 1로 치환
|OR이진법의 동일한 자리가 하나만 1이어도 1로 치환
~NOT0과 1을 반전시킨다

AND

  • 하나라도 0이면 0이 나온다.
    ...1010 0010
AND ...0010 0100
---------------
=>  ...0010 0000

OR

  • 중첩하고 싶은 레이어를 더할 때 쓸 수 있음
    ...1000 0000
 OR ...0000 1000
 ---------------
 => ...1000 1000

NOT

  • 뒤집어버림
        ...0101 0010
 NOT => ...1010 1101
  • LayerMaskstruct 구조체다. 그래서 LayerMask 타입의 변수 값을 변경하려면 함수에서 ref 키워드를 써야 한다

LayerUtil

  • 레이어 추가, 삭제를 간편화 하기 위해 함수를 모은 클래스
public static class LayerUtil
{
    // LayerMask는 구조체이기 때문에, 값을 변경하려면 ref 타입으로 해야 된다
    public static void AddLayer(ref LayerMask target, params string[] name)
    {
        // params parameter로 이름을 배열로 받아 여러이름을 추가할 수 있다
        foreach(string n in name)
        {
            target |= 1 << LayerMask.NameToLayer(n);
        }
    }
    public static void RemoveLayer(ref LayerMask target, string name)
    {
        target &= ~(1 << LayerMask.NameToLayer(name));
        // name이 8번 레이어 일 경우, 8번만 제외된다
    }
}

예시) CameraRayCaster

  • 몬스터만 카메라의 레이어에서 제외시키는 스크립트
public class CameraRaycaster : MonoBehaviour
{
    private Camera _cam;

    [Header("Set Raycast Config")]
    [SerializeField][Range(0, 100)] private float _rayDistance = 100;
    [SerializeField] private KeyCode _actionKey = KeyCode.Mouse0;
    [SerializeField] private LayerMask _targetLayer = 0;

    private void Awake() => Init();
    private void Update() => RayShoot();

    private void Init()
    {
        _cam = Camera.main;

        // LayerUtil.AddLayer(ref _targetLayer, "Player", "Monster");
        LayerUtil.RemoveLayer(ref _targetLayer, "Item");
    }

    private void RayShoot()
    {
        if(!Input.GetKeyDown(_actionKey)) return;

        Ray ray = _cam.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;

        if(Physics.Raycast(ray, out hit, _rayDistance, _targetLayer))
        {
            // 0000 0000 _ 0000 0000 _ 0000 0000 _ 0000 0000

            // EX> Monster (9 Layer) 를 클릭해서 '제외'한다고 가정.
            
            // hitLayerNumber = 9
            int hitLayerNumber = hit.transform.gameObject.layer;

            // ...0000 0010 0000 0000
            int hitLayer = (1 << hitLayerNumber);

            // ...1111 1101 1111 1111
            int notLayer = ~hitLayer;

            // _cam.cullingMask =  ...1111 1111 1111 1111
            // not Layer        =  ...1111 1101 1111 1111
            // And              => ...1111 1101 1111 1111
            _cam.cullingMask &= notLayer;
        }
    }
}

LayerMask를 사용해 특정 레이어만 추가하기

  • 예를 들어, 현재의 레이어 layer에 5번 레이어 추가
layer |= 1<<5;

LayerMask를 사용해 여러 레이어 추가하기

  • 3,5,6번 추가
layer |= (1<<3|1<<5|1<<6);

LayerMask를 사용해 특정 레이어만 삭제하기

  • 4번 레이어 제거
layer &= ~(1<<4);

LayerMask를 사용해 여러 레이어 삭제하기

  • 3, 5, 6번 레이어 제거
layer &= ~(1<<3|1<<5|1<<6);

TIP
지금의 LayerUtil과 같이 쓸만한 기능들은, 미리미리 static class에 함수를 구현해서 쓰는 것을 추천한다. 코딩이 쉬워진다

profile
개발 박살내자

0개의 댓글