[Unity] 유니티 파일 입출력(File IO), 최적화를 위한 기본 개념 Batching & Drawcall 알아보기

728x90

파일 입출력(File IO)과 스트림(Stream), prefab 인스턴스

유니티에서 슈팅 게임을 제작할 때 bulletFactory에서 prefab화 되어있는 bullet 인스턴스를 생성하는 방식을 자주 사용한다. 해당 방식이 유니티 내에서 어떤 절차를 거쳐 실행되는지에 대한 내용을 작성해보고자 한다.

먼저 스트림(Stream)은 '데이터가 흐르는 통로'로 데이터를 옮길 때, 스트림을 만들어 둘 사이를 연결한다. 메모리 <-> 하드 디스크와 같이 저장 매체에 데이터를 저장하고 불러오는 역할을 하는 것이다.

 

우리가 스크립트에서 bullet 변수를 선언하고 하이라키창에 bullet 오브젝트를 생성하는 것은 동적 메모리 할당(임시적)이기 때문에 프로그램을 종료하면 사라지게 된다. 하지만 bullet 오브젝트를 하드디스크에 저장해 프로그램 종료 여부와 관계 없이 영구적으로 저장하기 위해서는 파일(File)로 변환해 디스크에 저장하면 된다. 즉, 하이라키에서 생성했던 bullet 오브젝트를 bulletFactroy라는 File(파일)에 프리팹 instance로 저장하면 오브젝트에 연결된 스크립트(변수들)까지 하드디스크에 저장되어 언제든지 꺼내쓸 수 있는 데이터가 되는 것이다. 

 

그리고 해당 데이터를 다시 가지고와 프로그램 실행 시 재사용하는 과정을 스트림(Stream)이라고 이해하면 된다. 그 과정에서 Stream 과정을 최적화하는 패턴이 오브젝트 풀링(Object Pooling)인 것이다.

유니티에서 오브젝트 풀(Object Pool)과 비슷한 개념으로 네트워크에는 커넥션 풀(Connection Pool)이라는 개념이 있다. 컴퓨터 공학에서 Pool은 미리 여유 공간을 만들어 놓는 집합의 개념이기 때문에 둘의 의미는 일맥상통한다. 오브젝트 풀이 미리 메모리 공간을 할당해 언제든지 꺼내 쓸 수 있는 의미인 것처럼, 커넥션 풀 역시 server - conenction - client 순으로 유저가 해당 웹사이트에 접속할 때 할당되는 메모리 공간을 미리 여유있게 만들어놓아 매끄러운 실행이 가능하도록 하는 역할을 한다. 가끔 동시 접속이 폭주해 서버가 터지는 현상은 바로 이 커넥션 풀의 메모리 할당 과정에서 과부하가 걸린 것이고, 이를 악용한 경우 DDos(디도스) 공격이 되는 것이다.

 

player를 target으로 하는 bullet 프리팹 생성 시 target public 필드가 player과 연결이 해제되는 문제

간단한 동작인 것 같지만 프리팹 변환 과정에서 다음과 같은 문제가 계속 발생했다. 해당 문제의 발생 원인은 컴퓨터 저장공간이 다르기 때문이었다. 먼저 prefab은 prefab 폴더라는 컴퓨터 '하드디스크'에 저장된 파일이고 해당 프리팹 instance는 유니티 에디터가 실행되야 생성된다. 하지만 하이라키창에 있는 player는 프리팹이 아니기 때문에 동적으로 저장된 인스턴스의 개념이다. 결국, 유니티 에디터에서 프리팹으로 저장된 bullet 오브젝트는 하이라키 창에 있는 player를 인식하지 못하게 되어 퍼블릭 필드 연결이 해제되는 것이었다. 

 

따라서 플레이어와 총알이 서로 다른 공간에 저장되어 있기 때문에, 총알 인스턴스가 생성될 때 다음과 같이 동적으로 플레이어를 찾아주는 작업이 필요하다. 

target = GameObject.Find("Player").transform;
void Start()
    {
        GameObject player = GameObject.Find("Player");
        // 만약 플레이어가 있다면
        // if(player != null) 아래와 같은 의미
        if(player)
        {
            // 타겟 방향으로 이동하도록 한다
            target = player.transform;
            dir = target.position - transform.position;
            dir.Normalize();
        }
        else // 그렇지 않으면
        {
            // 그냥 아래로 이동시키자
            dir = Vector3.down;
        }
    }

 

배칭(Batching)과 DrawCall, 최적화 방법

유니티에서 배칭(Batching)은 일괄 처리를 의미한다. 보통 드로우콜(Drawcall)과 같이 쓰이는 개념으로, 오브젝트 렌더링 과정을 한꺼번에 처리하여 최적화를 달성하는 일련의 프로세스라고 보면 된다.

 

유니티 씬 뷰에서 Cube 오브젝트를 생성할 때 가장 길고 복잡한 컴퓨터 작업 구간은 Drawcall 구간으로 CPU가 GPU에게 렌더링 실행 명령을 내리는 시점으로 보면 된다. 게임 제작사에서는 이 드로우콜 과정을 최소화시키는 것을 중요한 작업으로 생각한다. 가령, 10개의 큐브를 1개씩 생성하도록 드로우콜하는 것이 아닌, 10개의 큐브를 한 꺼번에 생성하도록 명령을 내리는 작업이 최적화에 가장 효율적인 방법이기 때문이다. 

728x90