오픈월드 엔진은 아주 순조롭게 개발되고 있습니다.
일단 지금까지 개발된 내용들을 보여드릴까 합니다. 오픈월드를 위해서 씬을 빌드한다고 가정해보도록 하겠습니다.
아마 아래와 같이 수많은 오브젝트들이 넓게 포진되어있겠죠?
1 x 1 km 범위, 하얀 건물 200개, 나무 1000개의 간소한 씬
여기선 간단한 씬을 예시로 들었지만, 실제로는 수 킬로미터 범위에, 수만~수십만개 이상의 오브젝트가 존재할겁니다.
그 모든 오브젝트를 전부 로드해서 게임을 할 수는 없습니다. 그랬다가는 메모리가 터질테니까요!
몸에서 멀어지면 마음에서도 멀어지는 법…
이 오브젝트들은 플레이어가 있는 위치 근처에서만 로드되고, 플레이어와의 거리가 멀어지면 언로드되어야 합니다.
멀리 있는 오브젝트는 어차피 잘 안보이니까 로드 될 필요가 없겠죠?
게임에서도, 그리고 우리의 마음에서도 내려놓으면 됩니다.
오브젝트가 있는 씬(좌), 씬을 분할하는 에디터 윈도우(우)
오브젝트는 크기별로 각기 다른 씬레이어로 지정해서 작업합니다. 여기서는 Large와 Small의 두가지로만 구분했습니다.
실제 게임에선 Terrain, Large, Medium, Small 정도로 구분하면 적당할 것 같습니다.
그 외 자잘한 오브젝트를 최적화하는 기능도 추가해뒀는데, 그건 나중에 또 글을 올리겠습니다.
씬 이름 뒤의 접미사가 바로 씬 레이어인데요, 우측 스크린샷에서 각 레이어를 분할하기 위한 설정을 할 수 있습니다.
스크린샷에선 레이어의 이름을 House, Tree로 구분했는데, 어차피 오브젝트가 두 종류밖에 없어서 그런거고, 보통은 크기로 구분해줍니다.
그런데 가만보면, 씬 이름도 있고, 접미사도 있는데 이게 대채 뭐냐! 싶으실텐데요.
접미사를 별개로 둔 이유는, 씬을 접미사로 구분하면 레벨 디자인 과정에서 구획별로 나눠서 작업하기 편하기 때문입니다.
예를 들어, 사막과 해변 두 구획이 있을때, 각각의 구획에도 크기별로 구분 가능한 오브젝트들이 존재하겠죠.
그때는 Desert[Large], Desert[Small], Beach[Large], Beach[Small]처럼 씬으로 구획을 나눠주고, 접미사로 크기를 나눠주면 됩니다.
이렇게 접미사만 붙여놓으면 우측의 Scene Builder Window에서 정해진 폴더 아래의 씬 별로 접미사를 확인하여 레이어로 구분한 후, 분할을 실시합니다.
씬이 분할되는 각 타일의 영역
이번 예시에선, Large레이어 (건물 오브젝트)는 100x100m 사이즈로, Small레이어 (나무 오브젝트)는 50x50m 사이즈로 분할해보겠습니다.
위의 그리드에서 주황색 그리드가 Large레이어의 각 씬의 위치와 영역이고, 녹색이 Small레이어의 것입니다.
Scene Builder Window에서 빌드를 누르면 씬을 분할하여 빌드합니다.
씬 분할 프로세스 (좌), 분할 생성된 씬들 (우)
씬 분할 중에는 임시 폴더에 씬을 생성한 후, 모든 작업이 완료되었을때만 기본 디렉토리를 덮어씁니다.
결과적으로, 원본 씬들은 그대로 보존되고
씬 빌드 도중에 오류가 나거나 수동으로 취소하여 멈추더라도 이전에 빌드했던 내용들을 덮어쓰지 않기때문에 아주 안전하게 작업할 수 있습니다.
그리고 씬들은 모두 자동으로 유니티의 어드레서블 에셋으로 등록됩니다.
만약 어드레서블 패키지가 없으면 자동으로 설치하고, 기본 어드레서블 그룹까지 생성합니다.
쩔죠? 귀찮은건 다 자동으로 되게 작업했습니다.
아래는 분할된 씬들을 실제로 로딩하는 영상입니다.
OpenWorld Player 컴포넌트를 가진 오브젝트의 주위에서만 분할된 씬이 로드되고, 멀어지면 언로드 되는 모습을 보실 수 있습니다.
그리고 원하지 않는 레이어는 비활성화 하는 식으로 추가적인 최적화도 가능합니다.
동굴이나 던전은 씬을 별도로 나눠서, 동굴에 들어가있을때는 지상 레이어를 끄고, 지상에 있을때는 동굴 레이어를 끄는 식으로 활용할 수 있겠네요.
그리고 로드 & 언로드는 플레이어의 위치가 현재 타일에서 벗어났을때만 이루어지고, 각 업데이트의 인터벌을 설정해줄 수 있어서 성능상 비용이 많이 들지 않습니다.
약 8000개의 씬을 업데이트 할 때, 약 4~8ms가 걸리는데, 매 프레임 이렇게 소요되는게 아니라 업데이트 시점에만 소요됩니다.
그리고 이렇게 많은 씬이 한 레이어에 있는 경우는 거의 없겠죠.
만약 10x10km 씬에 100x100m짜리 그리드가 있다면 10000개의 씬이 생성되는게 아니냐고 생각할 수 있겠지만,
실제로는 월드 내에 빈공간에는 씬을 생성하지 않기때문에, 그 절반정도인 약 5000개의 씬이 있을겁니다.
그리고 각 레이어마다 다른 프레임에서 업데이트가 이루어지기때문에 병목현상도 발생하지 않습니다.
개발해놓은 내용은 더 있지만… 다음 개발 일지에 쓸 내용도 남겨둬야하기 때문에 나머지는 다음에 또 적겠습니다.
그럼 이만~