Monthly Archive for August, 2010

[Unity] Unity 3 preview : Lightmapping

Unity 3 에서 여러가지 새로운 기능들이 추가되었지만 가장 눈의 띄는 것중에 하나가 Beast 라는 lightmapping 툴이 통합된 점이다. 3D 에서 렌더링 퀄리티의 판단은 아마 광원(lighting) 과 그림자(shadow) 표현이 대부분을 차지할 것이다.

하지만 이런 프로세스를 게임과 같은 컨텐츠에서 실시간으로 처리하기에는 너무 프로세스의 양이 많기 때문에 정적인 광원과 그림자는 실시간으로 렌더링하지 않고 미리 라이트맵 이라는 것을 사용하여 좀더 사실적인 3D 환경을 구성한다.

view demo

이전 버전(2.6.x) 에서는 이런 라이트맵 생성을 3D Max 나 Maya 과 같은 외부 렌더링 툴을 이용하여 라이트맵을 베이킹하여 사용하였지만 3.0 버전에서는 Unity 에서  Beast 라는  라이트맵 툴이 이 역할을 대신 해 준다. 아래 메뉴가 unity 에 통합되어있는 라이트 맵툴에서 가장 옵션이 많은 부분이다. 기존의 다른 렌더러에 수많은 라이트 옵션에 비하면 상당히 간단한 편이다.

GI(global illumination) 기능을 사용한 실사의 라이팅 표현 및 라이트 UV 맵까지 자동으로 알아서 생성해줘서 일일이 맵을 잡아줘야하는 수고를 엄청 덜 수 있다. 하지만 고퀄리티의 라이트 표현을 하는 만큼 라이트 맵 렌더링 시간이 옵션에 따라 기하급수적으로 늘어날 수도 있어 적절하게 조절을 해야한다.

가장 렌더링 시간을 잡아먹는 부분이 라이트맵의 사이즈를 결정하는 Resolution 부분이다. 단위 unit 당 texture 를 나타내는  pixel 갯수를 얼마로 할지 나타내는 값으로 이 값이 커질수록 맵사이즈가 늘어나게되어 퀄리티가 정교해지긴하지만 상대적으로 렌더링 시간이 오래 걸리게 된다.

Download the source file….

[Unity] How to get a texture on the terrain

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 발자국 소리를 조합하여 사용할 수 있을 것이다.

download sample files