Unity 는 지형을 생성하고 디자인하는 방법이 마치 포토샾에서 이미지 리터칭하는 것과 같이 브러쉬를 이용하여 높이의 고저를 표현할 수 있다. 또한 지형에 텍스쳐를 드로잉하는 방법도 같은 방법으로 alpha map 이라고 하는 splat map 을 사용하여 해당 텍스쳐의 맵 데이타를 구분하여 저장, 각각을 서로 블렌딩하여 표현해주는 방법을 사용하고 있다.
하지만 툴자체에서 텍스쳐링을 하는 방법은 상당히 쉬운반면, script 로 접근하여 해당 위치의 텍스쳐를 얻어내는 방법은 위 내용을 알지 못하고서는 상당히 난해한 내용일 수 있을 것이다.
만약 player 가 지형을 움직이고 있을 때 각각 다른 지형텍스쳐 위에서의 발자국 소리를 구현한다고 했을때 가장 명괘한 방법이 어떤것일까?
가장 먼저 쉽게 접근할 수 있는 방법으로는 collider 의 trigger mode 를 이용하여 체크하는 방법이 있다. 하지만 이 방법은 실내와 같이 명확하게 오브젝트 중심의 mesh 형태의 구성에 알맞다. 즉, 지형과 같은 오브젝트일 경우 실내에 비해 크기가 훨씬 커서 정확하게 collider 로 체크하는것이 비효율적일 수 있다.
여기에서 위에서 설명한 alpha map 을 활용하여 접근한다면 한결 수월하게 위 문제를 해결 할 수 있을 것이다. 우선 아래 지형 이미지와 코드를 살펴보자.

using UnityEngine; public class PlayerHitCheck : MonoBehaviour { private TerrainData terrainData; private Vector3 terrainPos; private string resultText; void Start () { terrainData = Terrain.activeTerrain.terrainData; terrainPos = Terrain.activeTerrain.transform.position; } float textureIndex1; float textureIndex2; void Update(){ int mapX = Mathf.RoundToInt(((transform.position.x - terrainPos.x) / terrainData.size.x) * terrainData.alphamapWidth); int mapZ = Mathf.RoundToInt(((transform.position.z - terrainPos.z) / terrainData.size.z) * terrainData.alphamapHeight); float[,,] splatmapData = terrainData.GetAlphamaps(mapX, mapZ, 1, 1); textureIndex1 = splatmapData[0,0,0]; //grass texture textureIndex2 = splatmapData[0,0,1]; //sand texture resultText = " grass : "+textureIndex1+"\n sand : "+textureIndex2; } void OnGUI(){ GUI.BeginGroup (new Rect (10, 10, 200, 40)); GUI.Box(new Rect (0, 0, 200, 40),resultText); GUI.EndGroup (); } }
지형 텍스쳐는 간단하게 잔디와 모래 2종류로 구성되어있고 해당 텍스쳐 위로 FPC(First Person Controller) 가 접근할때 그 아래있는 텍스쳐의 alpha map 데이타를 추적하는 샘플이다. 가장 핵심적인 역할을 하는 부분이
//Method //float[,,] GetAlphamaps (int x,int y,int width,int height) float[,,] splatmapData = terrainData.GetAlphamaps(mapX, mapZ, 1, 1);
이 부분으로 player 가 있는 영역을 기준으로 TerrainData 에서 3차원 배열 텍스쳐 값을 얻어내는 메서드이다. 이 메서드는 Unity 2.6.x 에서는 공식적으로 명문화된(undocumented) 메스드가 아니지만 Unity 3 에서는 문서화 되어 공식화 되었다. 2.6.x 버전사용자들도 물론 사용가능하다.
여기서는 player 바로 아래 1×1 픽셀 짜리 영역만 체크하면 되므로 width 와 height 값을 모두 1로 설정하였다. x,y 값은 alpha map 사이즈를 기준으로 한 player 의 정수 좌표를 의미한다. 더 넓은 영역을 추출하려면 width,height 값을 원하는 값만큼 설정하면 된다. 이를 통해 splatmapData 라는 3차원배열(float[,,]) 을 얻을 수 있는데 의미는 다음과 같다.
해당 영역에서의 alpha map 가중치(0~1)) = splatmapData[x축의 pixel index, z축의 pixel index , 텍스쳐 layer index]
예를들어 player 아래에 2×2 영역의 alpha map을 체크한다고 했을 때 아래와 같은 이미지로 정리할 수 있다.


샘플에는 2개의 텍스처만 사용했기 때문에 splatmapData 의 texture layer index가 1까지 존재하였지만 만약 더 등록한다면 등록된 순서대로 인덱스가 정해지게 된다.
위에서 설명했듯이 샘플의 경우는 1×1 픽셀 한개를 체크한 경우라 splatmapData[0,0,0], splatmapData[0,0,1] 과 같이 2개의 가중치만을 얻었다.
그리고 이 가중치는 0~1 까지의 범위의 값인데 해당텍스쳐의 알파값의 정도를 의미하는 것으로 이 값이 0일 경우는 해당 텍스쳐가 없는 경우이고 반대로 1일 경우는 해당 텍스쳐만 존재한다는 의미이다.
따라서 이 값을 사용하면 여러가지 텍스쳐가 알파블렌딩 된 지형텍스쳐를 사용한다고 해도 그 가중치에 맞게 player 발자국 소리를 조합하여 사용할 수 있을 것이다.
0 Responses to “[Unity] How to get a texture on the terrain”