Unity 3 preview : Lightmapping

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

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

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

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

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

How to get a texture on the terrain [Unity]

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

Unity 3D Basic API Hierarchy

Unity 는 스크립트 언어로 Javascript 와 C# 를 지원하는데 둘의 차이는 크지 않다.  전반적인 구조는 일반적인 프로그래밍 언어와 마찬가지로 Object 를 중심으로 상속관계를 맺어가는 구조이다. 그리고 Component 와 Behaviour 를 주축으로 확장해 나가는 방식으로 구성되어있다.  간략한 형태로 아래와 같이 상속관계를 도식화하여 나타내보았는데 물론 하위에 수많은 확장클래스는 제외하고 어느정도 Unity 에서 가장 기본이 되는 것들 위주로 정리해 보았다.

왠만한 기능들은 엔진 자체에서 처리해 주는 것들이 많아 생각보다 Class 의 갯수가 많지 않다고 생각들 수 있지만 C# 을 기본 언어로 지원하는 만큼 C# 의 System namespace 의 기능들을 고스란히 사용할 수 있다는 점에서는 알아야 할 내용이 적다고는 할 수 는 없을 것이다.

그래도 강력한 비쥬얼 에디터를 지원하는 만큼 3D 공간을 머리속으로만 상상하면서 코딩하는 어려움을 상당부분 해결할 수 있으면서  그만큼 엉청난 코드의 양이 줄어들 수 있다는 점에서 정말 혁신적인 툴인것 같다.

Project epilogue : 3D Sensing Installation

이전 버전의 Swing H (J4) 솔루션이 회사의 첫번째 R&D 결과물로서 가능성을 확인한거라면 이번 버전은 좀더 직관적인 형태의 인터페이스의 추가와 정보전달의 용이성을 위한 하단부에 LCD 디스플레이가 추가로 크게 변경되어 개발되었다.  Swing H 에서의 인터랙션 장비는 반지를 통해 이루어졌는데 이 부분이 상당히 사용성에 여러가지 문제점을 드러내 차기버전에서는 좀더 이상적이라고 할 수 있는 아무런 도구없이 단지 손의 제스쳐로만 화면을 제어할 수 있게 개발하는것이 가능 큰 목표였다.

하지만 위 기능을 위해서는 손의 제스처를 인지하고 처리할 수 있는  별도의 처리가 필요했는데 이를 위해 카메라 영상을 통해 공간좌표까지 얻어올 수 있는 3D  Depth camera 인 TOF(time of flight) camera 를 사용하여 이미지 처리를 하였다.

FOTONIC-B70 by Fotonic

SwissRanger 4000 by MESA Imaging

PMD CamCube by PMDTechnologies

.

.

.

.

.

.

from Wikidipedia

이 장비는 고유의 illumination wave 를 송출하여 반사되어 나오는 파장의 시간을 계산하여 정확하게 거리를 측정할 수 있다. 고유의 주파수를 사용하기 때문에 할로겐 조명과 같은 외부광원의 영향이 거의  없는 것과 빠른 FPS  지원이  장점이다. 하지만 상대적으로 2D camera 에 비해 상당히 고가인점이 단점으로 작용한다. 이런 TOF camera 로 부터 depth 정보가 담겨져 있는 영상을 이용해 CV(computer vision) 처리를 하여 특정 제스쳐를 검출하거나 추적할 수 있다.

이 솔루션이 검출할 수 있는 제스쳐는 기본적으로 주먹(Rock),가위(Sissors),보(Paper) 의 형태를 기본으로 한다. 손을 이용하는 제스쳐일 경우 이 세가지 형태의 제스쳐 사인이 가장 사용자가 이용하기에 편하고 인지하기 쉽기 때문에 모든 제스쳐의 구성은 이 세가지를 기반으로 설계되었다.


처음부터 이전 버전의 문제점에 대해 파악하고 같은 문제점을 일으키지 않기 위해 다각도로 고민하고 노력했지만 어느 프로젝트와 마찬가지로 결과물 그자체로서는 참 아쉬움이 많이 남았다. 아직까지 사용자가 제스쳐로 무언가를 조절한다는 생각이 조성되지 않았을 뿐더러 아무리 센서 작동이 정밀하더라도 컴퓨터는 사람만큼 인지능력이 뛰어나진 않다. 누구나 다 아는 직관적인 제스쳐 하나를 구현할려고 하더라도 절대 그것이 생각만큼 제작이 쉽지 않을 뿐더러 단지 개발자의 룰에 갇혀 간과하는 점이 무척 많다는 점이다.

사용자를 고려해 쓰기쉽게 제작하면 이 솔루션의 장점인 다양한 제스쳐를 보여줄수 없고, 그렇다고 다양한 제스쳐를 적용할려고 하니 사용자는 무엇을 어떻게 작동시켜야 할 지 모르는 상황이 반복되는 것이다.

참 어려운 문제였다. 어쩌면 영원히 풀 수 없는 문제일 수도라는 생각도 들었다. 단지 재미있고 신기한것은 기술이 발전하면 만들 수가 있다. 하지만 그것이 돈이 될 수 있는냐는 질문에는 항상 머뭇거리게 만든다.

.

J4 from d’strict on Vimeo.

3d sensing hologram installation from vkimone on Vimeo.

2009.3 ~ 2009.7

R&D Project – 3D Sensing Hologram Installation  (J4 ver 2.0)

Project manager : 김기정,김정헌
Planning : 김정헌,양희수,김기정,김정빈
Visual / UI Design : 김기정,김정빈
Interaction Design : 김기정,김정빈
Product Design : 박진이
3D Modeling : 신백호

view detail

Tween in Unity3D

심리스(seamless)한 컨텐츠 제작에 있어 필수적인 요소중 하나가 트윈(tween) 스크립트 일것이다. Flash 가 점점 인터랙티브 컨텐츠 제작툴로서 자리를 잡아가면서 TweenLite,Tweener 와 같은 Falsh Open API  트윈엔진들이 개발되어 트윈 스크립트에 대한 부담감을 상당히 덜어주었다. 사실 이런 트윈엔진들의 도움없이 정교한 script animation easing 조절이 쉽지 않을 뿐더러 컨텐츠 제작시에 오히려 주객전도가 되어 이런처리들을 하느라 많은 시간을 할애해야 하는 경우가 발생한다. 물론 간단한 이징공식을 이용하여 구현하는 것이 가능하긴하지만  이런경우는 다양한 이징함수의 움직임을 이용하여 좀더 다이나믹한 움직임을 구현하는것과는 분명 움직임에 있어 차이가 나는것이 사실이다. 따라서 새로운 개발툴을 접할 시에는 항상 이런 기본적인 트윈엔진의 유무를 살펴보곤한다.

Unity3D 를 다루면서도 이런 트윈엔진이 분명있을거라 생각하고 찾아봤는데 Flash 만큼은 아니지만 3~4개 정도 찾을 수 있었다. 다만, 아직 많이 사용하는 툴이 아니다 보니 개인적으로 만들어 쓰는 형태라 아직까지는 대부분 기능이 다양하지 못하고 체졔적이지 못한게 약간은 아쉬운 부분이긴하다. 그중에서도 가장 완성도가 높은 iTween 이라는 Unity3d Tween Engine 을 소개할까 한다.

우선 공식 사이트를 한번 살펴보자. 언듯보면 TweenLite,TweenMax 의 사용법과 비슷하다. 아니 거의 같다고 보면 된다.  그도 그럴것이 위 엔진들을 기반으로 해서 만들었다고 하니 사용경험이 있는 Flash 개발자들은 한두번만 사용한다면 어렵지 않게 적용할 수 있을 것이다.

private var targetGameObject : GameObject;
 
function Awake(){
	targetGameObject = gameObject;
}
 
function Start(){
	iTween.moveTo(tweenTarget,{"x":1.7,"y":3,"time":1.3,"transition":"easeInExpo","delay":1.2,"onComplete":"TweenComplete"});
}
 
function TweenComplete(){
 print("TweenComplete");
}

Unity3D 의 스크립트 언어가 Javascript / C# 으로 Flash  Actionscript 와 문법이 비슷한지라 기본적인 코드를 읽는데 큰 어려움이 없어 Flash 개발자가 접근하기 한결 수월 하다. 아마도 Flash 에서의 3D 구현에 아쉬움을 느낀 많은 Flash 개발자들의 참여로 인해 올한해 가장 기대가 되는 툴이기도 하다.