Rampage

Terrain - 지형 (1)

J'Heel; 2023. 1. 28. 19:45

어떤 게임이든 기본적으로 반드시 필요한 요소를 말하자면 그중에서도 지형을 빼놓을 수 없을 것이다.

 

 

실제 사용자가 조작하게 될 캐릭터나 사용자 인터페이스 등 사실 중요한 것들은 차고 넘치는 것이 현실이지만 그래도 발 디딜 땅 정도는 있어야 하지 않을까?

 

 

그래서 이번에 만들 것은 Terrain(지형)이다.

 

 

고로 Terrain 구현을 진행해 볼 것인데....... 사실 저번 학기 동안에 만들었던 터레인이 이미 있다.

 

대충 이렇게 생겨 먹었다

보는 것처럼 대충 산봉우리 몇 개 보이고, 물도 있고, 저 멀리 보면 잔디도 보이고, 스카이 박스도 돼있고, 이상한 헬기들도 보이고.... 아무튼 이것저것 보인다.

 

 

이것 자체로도 어느정도 써먹을 수 있는 지형이라 말할 수는 있겠으나 엄연히 말하자면 이걸론 부족하다.

 

 

게임 월드라 부르기엔 아무래도 그 형태가 조약하고 휑한 데다 땅 모양도 그리 현실적이지 않다.

 

 

보다 정교한 게임 월드 구성을 위해선 오브젝트도 적절히 배치해야 할 것이며 잔디도 저렇게 무분별하게 놓아서는 안된다. 이를 위해서는 아무래도 터레인을 편집할 수 있는 툴이 절실한 상황인데.... 이것도 녹록지 않은 일이다.

 

 

구태어 말하자면 맵 하나 달랑 만들고 말 프로그램에서 터레인 편집 툴을 만들어 쓰겠다는 것인데... 상당히 난해하고 비효율적이다. 우리가 할 일은 타격감 시뮬레이터를 만드는 게 메인이지 터레인 편집 툴이 아니다.

 

 

그래서 차선책으로 택한 방법이

이미 존재하는 터레인 편집 툴을 활용하여 터레인을 구성하고, 이를 익스포트 하여 우리 프로젝트에 이식하는 것이다.

 

 

그럼 이제 이미 존재하는 편집 툴을 찾는 것이 문제인데, 이건 어렵지 않다. 우린 이미 답을 알고 있다.

 

유니티 엔진

대부분의 게임 엔진엔 터레인과 관련된 실시간 편집 기능을 제공한다. 그 중에서 유니티를 이용해 터레인을 구성하고 이를 익스포트 하여 우리 프로젝트에 이식하는 것이 이번 목표가 되겠다.

 

 

그리하여 먼저 해볼 것은,

터레인의 HeightMap(높이맵) 정보를 익스포트하고, 터레인의 BaseTexture를 익스포트 하여 플레이어가 밟게 될 기본적인 땅에 대한 정보들을 얻어내는 것이다.

 

 

이 중에서 높이맵을 얻는 것은 비교적 간단하다

터레인 컴포넌트는 인스펙터창을 통하여 높이맵을 익스포트 하는 기능을 자체적으로 제공한다. 위 이미지에 보이는 Export Raw... 를 누르면 아주 쉽게 높이맵을 얻어낼 수 있다.

 

 

그래서 이렇게 얻어낸 높이맵을 이용하여 기존에 만들었던 터레인 코드에 올리기만 하면 터레인의 기본 메쉬를 이식하는 것은 쉽게 끝난다.

 

 

다만 문제는 텍스쳐인데, 저번 학기에 만들었던 터레인의 텍스쳐링 방식은

전체 지형을 덮는 BaseTexture에 보다 오밀조밀하게 매핑되는 DetailTexture 두 개를 이용하여 터레인 텍스쳐 매핑을 하는 반면, 유니티의 Terrain 컴포넌트는 텍스쳐 스플래팅 기법을 이용하여 터레인을 구성하고 있는 것으로 보인다.(코드를 직접 본 게 아니라 시스템으로 미루어봤을 때 추측한 부분이다.)

 

 

그래서 유니티에서 만든 터레인의 텍스쳐를 가져온다고 해서 내 프로젝트에서 올바르게 텍스쳐 매핑이 이루어지지 않는다. 고로 이전에 만들었던 코드를 수정할 필요가 있다.

 

 

그러면 이제 우리가 해야할 일은 터레인 코드를 수정하는 것... 은 당연히 아니고,

먼저 유니티가 어떤 식으로 터레인을 구성하고 있으며 내가 필요한 데이터를 어떻게 익스포트 하여 사용할지를 분석하고 결정해야 한다.

 

 

유니티 터레인의 텍스쳐 매핑은 쉽게 생각하면 화장실 바닥과 비슷하다.

터레인의 각 면들이 일종의 타일이며 이 위에 텍스쳐가 반복되어 매핑된다. 이 방식이 텍스쳐 스플래팅 방식이며 여기에는  Terrain Layer라는 것이 있다.

 

 

Terrain Layer는 BaseTexture와 NormalMap, 각 타일의 크기 등의 정보를 가지고 있다. 이 정보를 토대로 터레인 표면에 텍스쳐를 입히게 되는데, 이때 각 타일이 어느 부분에 매칭되어 칠해지고 어느 부분은 칠해지면 안 되는 지를 알아야 할 필요가 생긴다.

 

이를 위한 데이터가 AlphaTexture인데, 이 텍스쳐는 그레이스케일 이미지로 검은색인 부분은 칠해지면 안 되는 곳, 반대로 흰색이면 칠해지는 곳으로 구분하게 하여 각 Terrain Layer들이 어느 위치에 그려지면 되는 지를 결정한다.

 

유니티에서는 Paint Texture라는 기능을 통해 실시간으로 터레인 표면에 그림을 그리듯 터레인을 칠할 수 있는데, 이때 터레인 내부에서 AlphaTexture의 값을 적절히 변경시켜 해당 위치에 Terrain Layer가 놓일 수 있도록 하는 것이다.

 

 

여기까지 이해를 했다면 이제 우리는 터레인 익스포터를 만들 수 있다.

필요한 함수는 사실상 딱 하나면 되는데, TerrainData::GetAlphamapTexture() 이 함수를 이용하면 유니티 터레인에서 알파텍스쳐를 얻어올 수 있고 이 데이터를 파일로 저장하면 최종적으로 알파텍스쳐를 익스포트 할 수 있게 된다.

 

Terrain Layer를 구성하는 BaseTexture와 NormalMap을 얻어내는 것은 그냥 파일이 저장된 경로로 가서 텍스쳐 파일을 복사해 가져오기만 하면 되므로 이 부분은 굳이 익스포터로 구현할 필요가 없다.

 

 

그러면 필요한 코드는 이렇게면 충분하다.

이렇게 Terrain 컴포넌트를 가져와 터레인의 TerrainData(여기에 터레인에 관련된 데이터들이 담겨있다)를 얻어온 다음, 알파 텍스쳐의 개수만큼 반복문을 돌며 GetAlphamapTexture()를 이용해 알파 텍스쳐를 얻는다.

 

이를 EncodeToTGA()로 TGA(꼭 TGA일 필요는 없다. 4개의 채널에 대한 데이터를 저장만 하면 되므로 jpg 형식처럼 rgb만 사용하는 데이터 형식만 피하면 뭐든 상관없으리라) 형식으로 데이터를 변경시켜 준 뒤 파일로 저장하면 알파 텍스쳐를 익스포트 하는 것은 굉장히 쉬운 일이다.

 

 

그럼 이제 이걸 써서 내 프로젝트에서 사용하기만 하면 되나?..... 싶지만 주의할 점이 한 가지 있다.

 

이렇게 해서 얻어낸 알파텍스쳐의 개수는 터레인 레이어의 개수가 8개라면 알파 텍스쳐도 8개가 되는 것이 아니라 단 2개만 존재한다.

 

앞서 말한 것에 따르면 알파 텍스쳐는 그레이스케일 이미지니 rgba 중 하나의 채널만 있으면 데이터를 표현하는데 문제가 없어 일반적으로 그레이스케일 이미지의 rgba 값은 모두 동일한 값들로 채워지게 된다.

 

그러나 유니티에서는 메모리 낭비를 최소화하기 위함인지 알파 텍스쳐의 모든 채널을 활용한다.

 

그래서 예시를 들어 설명하자면,

터레인 레이어의 개수가 8개라면 알파 텍스쳐(AlphamapTexture1, AlphamapTexture2)는 2개이며 각 레이어에 대한 알파 값 정보는 AlphamapTexture1 - R, G, B, A  -> AlphamapTexture2 - R, G, B, A 각 채널에 순서대로 들어가게 된다.

 

3번째 터레인 레이어에 대한 알파 정보에 접근하고자 한다면 AlphamapTexture1의 B 채널을 사용하면 되는 것이다.

 

 

그런 고로 이런 부분을 주의해서 내 프로젝트의 터레인 코드를 수정할 필요가 있다.

 

 

그럼 구조 분석과 데이터 익스포트도 끝냈으니 이제 진짜로 프로그래밍을 시작할 시간이지만... 그건 다음에 이어서..

'Rampage' 카테고리의 다른 글

Detail Object Map - 지형 위에 풀숲 (2)  (0) 2023.07.29
Detail Object Map - 지형 위에 풀숲 (1)  (0) 2023.07.24
Terrain - 지형 (2)  (1) 2023.07.07
Rampage - 소개 및 개요 (2)  (0) 2023.01.21
Rampage - 소개 및 개요 (1)  (0) 2023.01.14