Programming 

스크린 공간과 월드 공간

 

작성 기준 버전 :: 2019.2

 

[본 포스트는 유튜브 영상으로도 시청하실 수 있습니다]

 

이번 섹션에서는 스크린 공간와 월드 공간에 대해서 알아보자.

 

유니티의 좌표계 글에서 게임에서 사용되는 월드 좌표계와 로컬 좌표계에 대해서 알아보았다.

 

스크린 공간(Screen space)

 

유니티 엔진에서는 게임 속에서 사용되는 월드 좌표계와 로컬 좌표계로 대표되는 월드 공간 외에도 스크린 공간이 있다.

 

스크린 공간은 단어 그대로, 게임 화면 상에서의 좌표 공간을 의미한다. 그리고 일반적인 UI의 위치와 마우스 위치는 이 스크린 공간의 좌표를 기준으로 동작한다.

 

 

 

에디터에서는 게임 뷰 화면이 스크린 공간이고, 만약 전체화면인 게임이라면 모니터 전체가 스크린 공간이 된다.

 

 

우선 스크린 공간의 좌표를 테스트 하기 전에 게임 뷰의 Free Aspect라고 적힌 드롭다운 메뉴를 클릭해서 드롭다운 메뉴를 열어보자. 이것은 게임 뷰에서 보일 게임 화면의 해상도를 설정할 수 있는 곳이다. + 버튼을 누르면 해상도를 설정할 수 있는 대화상자가 표시된다.

 

 

1920 x 1080 해상도로 설정해보자.

 

 

설정하고나면 16:9 비율로 보이게 된다.

 

public class ScreenSpaceTest : MonoBehaviour

    void Update()

    {

        Debug.Log(Input.mousePosition);

    }

}

 

그럼 이제 C# 스크립트를 하나 생성해서, 마우스 좌표를 출력하는 코드를 작성한다.

 

 
그리고 플레이 버튼을 누른 뒤 게임 뷰의 화면 위에서 마우스를 움직여 보면 왼쪽 아래로 갈수록 출력되는 좌표가 (0, 0)에 가까워지고 오른쪽 위로 갈수록 아까 설정한 화면 해상도에 가까운 (1920, 1080)에 가까워지는 것을 알 수 있다. 지금 볼 수 있는 화면 해상도로 표현되는 공간이 바로 스크린 공간이다.

 

처음에 언급했듯이 이것을 통해서 UI의 위치를 컨트롤 하거나 마우스의 위치를 알아낼 수 있다.

 

공간 전환

 

게임의 기능을 구현할 때는 이 스크린 공간의 좌표를 월드 공간의 좌표로 변환하거나 그 반대로 변환하는 방법 역시 자주 사용하게 된다.

 

스크린 공간 -> 월드 공간

 

먼저 스크린 공간의 좌표를 월드 공간의 좌표로 변경하는 법을 알아보자. 스크린 공간의 좌표를 월드 공간으로 전환하는 예시는 주로 마우스를 클릭한 위치로 캐릭터를 이동시킨다던가 하는 종류의 처리를 하는데 사용된다.

 

스크린 공간의 좌표를 월드 공간의 좌표로 전환하는 방법을 배우기 전에 씬을 세팅해보자.

 

 

씬에 평면 하나를 만들고 그 평면을 내려다 보도록 카메라를 배치한다.

 

 

그리고 하이어라키 뷰에 우클릭하고 스피어 게임 오브젝트를 하나 만든다.

 

 

그 다음 생성된 스피어 게임 오브젝트를 프로젝트 뷰에 드래그해서 프리팹으로 만든다. 그 다음엔 씬에 배치되어 있는 스피어 게임 오브젝트는 삭제한다.

 

public class ScreenToWorld : MonoBehaviour

{

    public GameObject prefab;

    void Update()

    {

        if(Input.GetMouseButtonDown(0))

        {

            var ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            RaycastHit hit;

            if(Physics.Raycast(ray, out hit))

            {

                Instantiate(prefab, hit.point, Quaternion.identity);

            }

        }

    }

}

 

그리고 위와 같은 코드를 작성한다. 위 코드는 다음과 같은 과정으로 처리된다.

 

1. 카메라에 내장된 함수인 ScreenPointToRay() 함수로 클릭한 순간의 마우스 위치를 화면 공간의 좌표에서 카메라에서 쏘아지는 광선으로 변환

2. Physics.Raycast() 함수로 광선이 부딪힌 지점을 검출

3. 광선이 부딪힌 위치에 Instantiate() 함수로 게임 오브젝트를 생성

 

 

코드를 모두 작성하면 저장하고 에디터로 돌아가서 게임 오브젝트를 하나 배치한다. 그리고 그 게임 오브젝트에 작성한 ScreenToWorld 컴포넌트를 부착합니다. Prefab 프로퍼티에는 아까 만든 Sphere 프리팹을 할당한다.

 

 

 

플레이를 하고 게임 뷰에서 평면을 클릭해보면 마우스의 위치 좌표가 월드 공간의 좌표로 바뀌면서 클릭한 위치에 게임 오브젝트가 생성되는 것을 볼 수 있다.

 

월드 공간 -> 스크린 공간

 

스크린 공간에서 월드 공간으로 변환하는 것과 반대로 월드 공간에서 스크린 공간으로 변환하는 것 역시 게임에서 자주 사용된다. 대표적인 예로는 캐릭터의 머리 위에 HP UI를 띄우는 것이다.

 

유니티의 UI는 일반적으로 스크린 공간에 그려지는데, 월드 공간에서 움직이는 캐릭터를 따라가려면, 월드 공간의 캐릭터 좌표를 스크린 공간으로 전환해서 HP UI에게 알려줘야 한다.

 

테스트 하기 위한 씬을 세팅해보자.

 

 

하이어라키 뷰에 우클릭해서 스피어 하나와 [UI > Image]를 선택해서 이미지 UI를 하나 만들자.

 

 

그리고 이 이미지의 Width와 Height를 50으로 변경하고 색깔도 빨간색으로 변경한다.

 

public class WorldToScreen : MonoBehaviour

{

    public GameObject worldObject;

    void Update()

    {

        transform.position = Camera.main.WorldToScreenPoint(worldObject.transform.position);

    }

}

 

그 다음 WorldToScreen C# 스크립트 파일을 생성하고 코드를 작성한다.

 

 

코드를 모두 작성하면 에디터로 돌아가 이미지 게임 오브젝트에 WorldToScreen 컴포넌트를 추가하고 wolrdObject 프로퍼티에 씬에 배치한 게임 오브젝트를 할당한다.

 

 

모든 세팅을 마치고 플레이 버튼을 누른 뒤, 씬 뷰에서 스피어 게임 오브젝트를 선택하고 움직여보면 스크린 공간에 있는 이미지가 월드 공간의 게임 오브젝트를 정상적으로 따라다니는 모습을 볼 수 있다.

반응형

+ Recent posts