제가 쓰는 내용은 일리히트엔진에 관한 내용이 주가 되다보니 일반적인 이론은 좀 소홀히 하는 경향이 있습니다.
사실 이론적인 부분은 저보다 실력있는 필자분들이 많이 계시니 저는 엔진을 분석하는 데 촛점을 두려고합니다.
-메쉬란?
폴리곤들을 단위별로 모아서 랜더링 작업을 체계적으로 하기 위해 만들어 놓은 자료 구조입니다. 2디 게임으로 치면 픽셀이 폴리건 이고 비트멥 이미지가 메쉬가 되겠습니다.
잘 이해가 안되 신다면 위 그림 처럼 Mesh 스타킹을 연상하시면됩니다.
이전 시간에 버텍스 와 인덱스 리스트를 직접 다뤄 보았는데요. 사실 이렇게 drawprimitive 함수등으로 버텍스를 직접 넣어서 쓸거면 엔진을 쓰는 의미는 거의 없습니다. 그냥 랜더러 랩핑한 라이브러리 수준이겠죠. 사실 제가 어린시절(1994년도 쯤...) 처음 3D프로그램시작할때 메쉬라는것도 모르고 게임을 만든적이있었는데 그때 정말 진정한 카오스를 경험 한적이 있었습니다.
그래서 어느순간부터 버텍스와인덱스 정보를 쌍으로 관리해서 사용을 했었는데 나중에 그런것들을 사람들이 메쉬라고 하던 거였더군요. 그리고 어느순간부터 dxsdk에 메쉬기능이 붙어서 나오기도 하더군요.
- 일리히트엔진에서의 메쉬 구현
일리히트엔진은 메쉬구조내에 메쉬버퍼라는 구조를 여러개 따로 가질 수 있습니다.
메쉬버퍼는 메트리얼이 따로 적용될수있는 최소 단위 이기도 합니다. 메트리얼은 참조본이 아닌 원본을 가지고있으며 고유하게 하나의 메쉬 버퍼에만 사용됩니다.
일리히트엔진의 특징중 하나는 씬노드 단에서는 메트리얼객체를 포인터나 참조를 써서 공유할수없다는 것입니다. 이 점이 대부분의 엔진과 가장 큰 차이점 중하나입니다. 대부분 메트리얼을 따로 만들고 그것을 여러곳에서 참조할수있는 반면 일리히트엔진은 메쉬버퍼와 메트리얼이 일부일처제 입니다.
그래서 메쉬버퍼를 필요이상으로 많이 나눠서 만들경우 상당히 메모리가 낭비되어지는 것에 주의 하셔야합니다.
실제로 씬노드들은 각자 한개 이상의 인스턴스화된 원본들만 가지고 있습니다.( 씬노드 편에서 다시 한번 다루도록하겠습니다.)
다수의 메쉬 버퍼(irr::scene::IMeshBuffer)들이 모여서 메쉬(irr::scene::IMesh) 가 됩니다. DXSDK와 좀 비슷합니다.(거의 같다고 봐야할지도??)
기본 메쉬형 이외에 아래와 같이 에니메이션을 위한 확장된 형태의 메쉬들을 제공합니다.
- 메쉬 생성하기
일리히트엔진에서는 기본적으로 평면 ,큐브, 실린더,구,원뿔형태의 기본 메쉬를 만들어 주는 함수들을 제공합니다.
SceneManager::getGeometryCreator() 라는 함수를 이용해서 IGeometryCreator 받아옵니다. 그리고 이 객체의 멤버 함수들을 이용해서 기본 메쉬 들을 생성할 수 있습니다.
이함수들을 써서 메쉬를 만들경우 따로 메쉬 버퍼를 만들지 않아도 됩니다. 도우미 함수들이 내부적으로 알아서 만든 다음 먹기(?) 좋은 상태로 메쉬객체를 반환 해주기 때문입니다.
- 메쉬 버퍼 생성하기
또한 메쉬 버퍼도 직접 만들어볼 수 있습니다.
irr::scene::SMeshBuffer* pbuffer;
pbuffer = newirr::scene::SMeshBuffer();
메쉬버퍼는 따로 만들어주는 도우미 함수 들이 없기 때문에 위와 같이 직접 메모리를 할당해서 만들어 줍니다.
할당받은 메쉬 버퍼의 객체 (pbuffer)내용물속에 있는 Vertices, Indices 직접 체워 넣을수있습니다.
아래 소스 처럼 SMeshBuffer 는 CMeshBuffer탬플릿 기반으로 만들어 진 클래스 입니다.
메쉬버퍼종류는 기본적으로 3 종류가 있습니다.
//! Standard meshbuffer
typedefCMeshBuffer<video::S3DVertex> SMeshBuffer;
//! Meshbuffer with two texture coords per vertex, e.g. for lightmaps
양성평등을 위해 이번 사과의 짤은 남자 사진으로 올려드립니다.
저는 이렇듯 녀성부와 셧다운제를 찬성하는 녀성님들을 존중합니다.
1. C/S의 생명주기
Scott Meyers의 명저서, Effective C++을 한마디로 정의하지면 객체의 잘 생성해서 잘 써먹다가, 필요없는때는 잘 제거하는 차가운 도시남자의 객체 관리법이라고 할수 있습니다. 그리고 이 객체라는 것은 C++ 클래스의 객체 만이 아닌 한 인스턴스(Instance) 그 자체라고도 볼수 있습니다.
흔한 올바른 객체 제거 방법. 비단 컴퓨터 내부 뿐만 아니라 현실에도 제거를 잊은 객체들이 많습니다.
따라서 인스턴스는 나름의 객체 수명이 있습니다.
이 객체 수명은 인스턴스 자기가 결정하는 것이 아니라 OS나 자신을 Embeding하는 컨테이너에 의해 결정됩니다.
Win32 API를 처음 배울 때부터 우리는 이것을 알게 모르게 배워왔습니다.
RegisterClassEx()로 윈도우를 등록하고 CreateWindow()로 창을 생성하고 각종 메시지를 받아 해당 작업을 하다가 WM_DESTROY 메시지가 날라올때 new로 만들어진 객체들을 지워주어야 합니다.
이런 것은 비단 Win32만이 아닙니다, 아래 이미지는 아이폰 앱의 수명 주기의 일부분인데 대부분의 인스턴스의 생명주기는 이와 같은 구조를 지닙니다.
출처 : https://developer.apple.com
뻔한 이야기를 왜 하냐면 Clinet/Server의 평등한 관계라는 시각에서 볼때,
클라이언트와 서버도 이같은 네트워크 생명주기를 지닌다는 점을 강조하기 싶기 때문입니다.
다시 말해, 게임룸에 들어가기전, 로비(Lobby)에서 C/S에서 필요로 하는 객체의 초기화 과정이 필요합니다.
게임 서버가 아닌 로비 서버에서 클라이언트에 필요한 객체를 초기화 및 업데이트를 하고 올바른 정보를 갖고 게임룸으로 들어가야 합니다.
분산 서버이기 때문에 이와 같은 과정은 로비에서만 일어나고 게임룸에서는 오직 게임에만 신경쓰도록 해야합니다.
잘 돌아가고 개발이 잘되는 프로젝트는 이같이 뻔한 것들이 잘 지켜지는 프로젝트들입니다.
반도의 흔한 네트워크 게임 프로세스
위의 그림은 간단한 네트워크 게임의 프로세스를 다시 한번 간략히 그려본 것입니다.
이 그림위에 수명 주기를 다시 체크해보죠.
네트워크 역시 다른 곳에서 자주보던 그림이 나왔습니다.
비밀인데 아무 것도 안하면서 일한 척 할려면 그림을 잘그리면 됩니다.
이러한 그림 연습이 코딩하는데 도움이 되냐고 반문할수 있지만 점점 복잡해져가는 네트워크 구성에 큰 도움이 된다고 확신합니다.
이런 설계가 있으면 언제 어디서 클라이언트와 서버에 각각 정보를 채울 것인지 확연해집니다.
물론 호출되는 함수는 send() 함수와 recv() 뿐이겠지요.
이런 식의 그림 연습은 앞으로도 종종 해볼 것입니다.
4년 내내 다른 친구들 장학금 받는데 큰 기여를 한 성적이라 대학 수업은 잘 모르지만,
대학에서 OOP을 배우는 이유는 C++이나 JAVA같은 언어 자체를 배우기 위한 시간이 아니라고 생각됩니다.
하도 공부를 못해 4학년 졸업할 때 너는 프로그래밍을 못하니 일년 더 다녀보라는 말을 들을지라
제 말이 맞는지는 잘 모르겠습니다만, 제 생각은 이렇습니다.
OOP는 현실을 반영한 철학과도 같은 개념이기에 객체간의 관계와 수명주기를 다른 곳에도 많이 응용해서 디자인할수 있습니다.
위의 그림들에서 클라이언트와 각 서버들은 한 인스턴스 속에 들어있는 다섯개의 객체(혹은 클래스)라고 봐도 무방합니다.
Client 객체가 Path Server, Load Balance Server, Lobby Server, Game Server라는 네개의 객체에게 질의를 하는 구조이며
서버인 Lobby Server와 Game Server의 객체는 Database에 의해 전역 데이터, 혹은 공유 데이터를 교환할 것입니다.
각 객체들은 자신의 역활만을 해주고 있고 수명도 존재합니다.
즉, OOP의 고급(?)이라 할수 있는 디자인 패턴 역시도 네트워크에서 사용해볼수 있지 않을까요?
...은 지금은 너무 떡밥이 세니 본론으로 돌아가 지난 시간의 아바타 채팅을 다시 변경시켜봅시다.
2. 로비 서버의 제작, 그러나 할말이 많다.
지난 시간에 서버와 클라이언트 이외의 데이터는 로긴을 위한 사용자 테이블 뿐이었습니다.
위의 채팅서버에서 로비서버로 바뀐다면 변경할 포인트가 뭐가 있을까요?
지난 시간처럼 명세서를 꾸며봅시다.
로비서버 명세서
1) 클라이언트가 로비 서버에 입장하면 자신의 정보(닉네임, 전적)를 받는다.
2) 같은 채널내 다른 유저의 정보를 받는다.
3) 다른 유저와 채팅을 할수 있다.
4) 게임룸 리스트를 볼수 있다.
4-1) 자신의 등급이 맞지 않는 룸에는 입장이 불가능하다.
5) 게임룸을 직접 만들수 있다.
5-1) 자신의 등급이 맞는 않은 룸은 만들 수 없다.
...만들어야 할 항목들이 죄다 나왔습니다.
이중 가장 중요한 것은 클라이언트 접속시 다른 유저들과 게임룸 리스트를 클라이언트에게 보여준다는 것입니다.
결론부터 말하자면 이게 생각만큼 쉽지는 않습니다.
....................................................................그냥 수식이나 포스트 하고 나머지는 직접 짜보세요~ 하면서 인공지능 연재할껄.... .
지금 기분
...그래도 강의 연재 역시 "만들기"라고 본다면 시작했으면 기어이 끝장을 봐야겠죠?
먼저 필요한 것은 클라이언트와 서버에 존재할 CGameUser와 같은 단일 사용자 정의 클래스입니다.
서버는 접속 들어온 사람들만큼 이 CGameUser를 자료구조로 저장하고 있어야 합니다.
이때 속력을 위해 굳히 DBMS에 현재 로비에 접속된 유저를 저장하지는 않습니다.
당연히 로비서버 안에 저장하고 있습니다.
사용자 리스트를 뿌려줄려면 어떻게 해야 할까요?
1) 현재 유저수만큼 send() 함수를 호출해 일일이 CGameUser를 보낸다.
...네 말도 안되죠. 사용자 정보는 UDP가 아닌 TCP로 보낼 중요한 데이터입니다.
줄곧 보낼수도 없거니와 새로 들어온 사용자와 나간 사용자를 다시 결정해야 합니다.
몇명 안되는 게임이라면 이 방법도 가능하겠지만 실제로 코딩해보면 상당히 지저분해 질수밖에 없습니다.
따라서 다른 방법으로,
2) 서버 자료구조의 CGameUser를 통채로 보낸다.
가 있습니다.
엄청 멋있지만 척 들어도 어렵게 느껴지죠? 만약 CGameUser를 STL map에 저장하고 있다면,
send(UserMap, sizeof(UserMap)); 식으로 보낸다는 이야기입니다.
당연히 서버와 클라이언트는 사용자 관리에 같은 콜렉션을 써야 합니다.
그래서 클라이언트 코드라도 이런 부분은 서버쪽에서 만들기도 합니다.
하지만 콜렉션, 컨테이너를 통채로 보내는 것은 결코 쉬운 방법이 아니며 코딩 길이도 상당해집니다.
네, 맞습니다, 각 게임회사에는 이 방법이 자사 서버 엔진의 아주 중요한 요소중 하나입니다.
바로 객체 직렬화(Object Serialization)입니다.
2-1. 직렬화
직렬화는 서버가 아니더라도 한번쯤 들어보셨을 것입니다.
MFC를 공부하면서 "<<"로 객체를 그대로 파일에 저장하는 것이라던가, JAVA에서 ObjectOutputStream() 같은 함수죠.
단순 구조체라면 쉽습니다만 핵심은 역시 자료구조를 통채로 옮기는 것입니다.
1) XML
XML은 텍스트 기반으로 이뤄진 자료구조입니다.
CGameUser 객체 10개라도, 100개라도 XML로 쉽게 표현할 수 있습니다.
게임에서는 네트워크 프로토콜로 XML을 잘 사용하지는 않습니다. 일단 너무 큰게 문제겠지요.
대신 XML은 HTTP에 실려져 SOAP(http://www.w3.org/TR/soap/)을 구현하는데 많이 사용되며
Action Script와 맞물려 플래시 네트워크 게임에서도 많이 사용됩니다.
저는 일단 비추! 합니다.
단, 게임 말고 Facebook이나 Twitter 정보 받아 올때는 JSON보다 XML을 좋아합니다.
JSON은 사람이 읽기에는 너무 헛갈리거든요.
정말이지 XML은 사람을 위한 언어이고 JSON은 기계를 위한 언어입니다.
그러나 시기를 잘못 탔습니다. 구글이 Protocol Buffer를 내놓았을 때는 이미 스마트폰 열기가 시작되었고,
스마트폰에서의 평가는 좋지 못했습니다.
무엇보다 구글에서 나온 멋진 물건(?)이라는 기대와 달리 컨테이너를 자동으로 직렬화해주는 기능이 없었습니다.
SOAP이나 플래시에서 사용하는 XML보다 사실 별로 나은게 없는거죠.
(혹시 Protocol Buffer를 이용해 재미를 본 분이 있으면 반론과 경험담을 부탁드립니다.)
3) JSON
최근 인기를 가장 끌고 있는 것은 역시 JSON(JavaScript Object Notation)입니다.
(http://json.org/)
JSON은 원래 JavaScript용으로 나온 경량 데이터 교환 포맷이나 XML보다 가볍고 파서 역시 가벼워 PC와 스마트 디바이스를 가리지 않고 위엄을 떨치고 있습니다.
트위터, 페이트스북 같은 유명 SNS들은 XML과 JSON을 모두 지원하며 앱스토어 역시도 JSON을 프로토콜로 사용합니다.
게임에서 역시 마찬가지죠, 실시간 게임 뿐만 아니라 특히 SNG들은 대부분 JSON으로 작동된다고 보셔도 됩니다.
어떤 과학의
프 로 토 콜
JSON
...드립 실패했다는 거 알고 있으니 댓글로 지적하진 말아주세요.
4) boost::serialization
XML과 JSON은 그 바탕에 이기종 통신용이라는 탄생 목적을 갖고 있습니다.
윈도우, 유닉스, C++, JAVA 등 서로 다른 OS와 언어끼리 손쉽게 데이터를 교환하는 것이 목적입니다.
그래서 텍스트(UTF-8)형식으로 만들어졌죠.
아이폰 앱이라도 서버까지 Objective-C로 짜지는 않습니다, 안드로이드 앱이라도 서버까지 JAVA로 짤 필요는 없지요.
어쩌면 이런 성격이 스마트 디바이스에서 JSON을 최고의 스타로 만들어준 것인지도 모릅니다.
하지만, 같은 C++끼리라면 어떨까요?
굳히 텍스트 기반을 들고 가야할 필요는 없을 것입니다.
PC 온라인 게임이라면 서버와 클라이언트 모두 C++로 가능하고 C++가 가장 많이 사용되는 환경일 것입니다.
이런 경우에는 boost::serialization 가 깔끔한 솔루션을 제공합니다.
(http://www.boost.org/doc/libs/1_49_0/libs/serialization/doc/index.html)
boost::serialization는 STL 콜렉션들을 그대로 직렬화 시켜주는 정말 멋진 라이브러리입니다.
바로 이 부분이 많은 게임회사 서버팀의 비밀중 하나였지요.
그리고 boost::serialization로 그 C++ STL 직렬화의 비밀을 누구나 사용할 수 있게 되었습니다.
2-2. 패킷 생성기, 혹은 컴파일러 이제까지 적은 내용을 한줄로 요약하면,
실제 온라인/네트워크게임에서는 직렬화를 통해 STL 콜렉션 같이 길이가 정해지지 않은 데이터 덩어리 자체를 그대로 패킷으로 보낸다.
입니다.
하지만 아직 해결해야 할 부분이 있습니다.
지난 시간의 소스를 다시 봅시다.
//
// MFCClientDlg.cpp
// 로긴 데이터 보내는 부분
//
CLOGIN loginPack;
ZeroMemory(&loginPack, sizeof (loginPack));
loginPack.head = MSG_LOGIN;
memcpy((char *)&loginPack.id, m_strID, m_strID.GetLength());
memcpy((char *)&loginPack.pwd, m_strPWD, m_strPWD.GetLength());
이런 식의 파일을 하나 만들어두면 누군가가 이 파일을 헤더 파일과 CPP 파일에 원래 소스를 만들어 주면 어떨까요?
SendLogin()과 SendChat()이라는 이름을 가진 함수까지 만들어서요.
그리고 수신부에도 이 두 패킷을 받아 처리하는 함수 원형을 만들어 줄수도 있겠죠, OnRecvLogin(), OnRecvChat() 같은 식으로 말입니다.
그런 역활을 해주는 것이 흔히 패킷 생성기(Packet Generator)라고 불리우는 외부 컴파일러입니다.
이에 대한 힌트는 네트워크 프로그램에서 나온 것만은 아닙니다.
CORBA, COM 같은 분산 프로그래밍에서 흔히 사용되는 방법이며 멀리서 찾을 필요없이
"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\midl.exe"이 바로 이런 역할을 합니다.
물론 midl.exe은 MS의 IDL 컴파일러로 COM 프로그래밍시 IDL 파일을 빌드시켜주는 컴파일러입니다.
(IDL : Interface Definition Language)
이것을 네트워크 프로그램용으로 만드는 것이 패킷 생성기죠, 네트워크 직렬화에 이어 각 개발사의 핵심 보물 중 하나입니다.
부르는 명칭은 달라도 하는 역활은 비슷합니다, 어느 개발사에서 사용하지는 알수 없지만 ADL.exe이라는 훌륭한 컴파일러도 있죠,^--^
다행히 http://mastercho.tistory.com/9 같은 훌륭한 개발자분을 통해 제작 기법은 많이 알려져 있습니다.
최근에는 스크립트 언어를 이용한 방법도 많이 공개가 되었는데 보다 쉽게 직렬화 + 패킷 노가다 하는 일을 줄일수가 있게 되었습니다.
IDL로 패킷을 정의하면 빌드시 외부 컴파일러(pidl.exe)가 헤더와 CPP를 만들어 줍니다.
Custom Build Tool 옵션은 이럴때 써먹는거죠, MFC나 ATL로 ActiveX 컨트롤을 제작하더라도 IDL에 기본적으로 midl.exe가 Custom Build Tool로 붙어있는 것을 볼수 있습니다.
(참고로 해외에선 DDoS 테스트 클라이언트툴을 패킷 생성기라 부릅니다. 이런 IDL 컴파일러를 패킷 생성기라고 부르는 것이 정확한 명칭인지는 잘 모르겠습니다.)
3. 분량 조절을 실패했습니다. 네, 실제 로비 제작은 다음 시간에 하겠습니다. (-_-);;
너무 세게 떄리진 말아주세요...
이제까지 소개한 것들을 다시 정리해 보죠.
1) 대용량서버는 IOCP, 혹은 epoll 소켓 모델을 이용한다.
2) 서버든 클라이언트든 I/O 관련은 비동기 함수를 이용한다.
3) C/S 모델이나 P2P 모델이나 listen() accept()/connect(), send()/recv(), close()의 배치로 구현할 수 있다.
4) 서버에는 반드시 DBMS가 따라다니며 서버와 DBMS의 통신 시간 역시 네트워크 수행시간에서 C/S의 통신 이상 중요한 요소이다.
5) 분산서버 아키텍쳐는 결국 객체간 통신과 객체 수명주기와 같다.
6) 실제 게임을 만들려면 STL 컨테이너같은 콜렉션을 주고 받아야 하고 이것을 직렬화(serialization)라 부르는데 몇가지 방법이 있다.
7) 보다 뽀대나고 전문적으로 할려면 패킷을 외부 파일에 정의하면 자동으로 이벤트 함수를 만들어 주는 외부 컴파일러가 있으면 참 좋다.
휴우, 여기까지 설명하니까 이제서야 백그라운드로 이해해야할 네트워크의 기초 지식이 끝났습니다.
다음 연재에 실제 로비를 만들겠습니다.
뭘로 만들까요? 과연 IDL 컴파일러를 붙여야 할까요?
...그냥 JSON 정도로 용서해 주시면 안될까요? 멀티플랫폼이 대세니까 용서해주세요.
4. 더 생각해볼꺼리
1. 각자 사용하시는 패킷 생성기 이야기나 하면서 놀아요~ ^-')b
PS) 다시 읽어보니 이미 알고 계신 분들에게는 정리 정도인데,
모르시는 분들에게는 한도 끝도 없는 이야기...로 느껴질수도 있겠습니다.
각 링크는 다 클릭해보시고 모르는 용어는 구글에서 검색해 보시길 바랍니다.
직렬화 + 패킷 생성기를 직접 구현하는 것만 하더라도 서버 엔진의 절반이라 볼수 있습니다.
또한 이 작업을 보다 멋있게 구현하는게 서버 엔진 개발자들의 끝나지 않는 로망이기도 합니다.
경우에 따라서는 내부용(서버간 통신) 패킷과 외부용(클라이언트 연결) 패킷 생성기 두개를 만들 때도 있습니다.
오디오프로그래머 - 사운드연출상필요한것들구현 사운드엔진전문가 (언리얼, 사운드미들웨어(마일즈, FMOD등)) 사운드 QA - 기존 QA보다좀더사운드에전문적인분들이해당. 사운드엔지니어 - QA에서넘어온사운드오류이슈와최종밸런스를조율
위직군들중, 한쪽만잘한다고, 좋은사운드를가지는것도아니고, 모두다잘해야만 환상적인 게임 속 세상을 만들수 있습니다. 요즘은위와같은 인원들과 구성으로제작진행을하는프로젝트들이점차많아지고있고, 그간 해외에서나 이슈가 되었던 내용들이였지만, 국내에서 개발되는 프로젝트들도 위와 같은 흐름을 가지고 각 전문가들과 함께 개발진행이 되고 있습니다.
한국의 게임사운드도 해외와 견주어 결코 뒤처지지 않는 수준으로 올라온것 같아 뿌듯합니다.
지금까지 사운드팀, 사운드 스튜디오에서의 전체적인제작파트와진행라인이 이제눈에들어오시리라생각됩니다.
세부적으로 사운드디렉터가각파트의사람들과조율을해야할점들. 짚고넘어가야할것들이 무척 많이 있는데요
다음회엔,
개발팀에서넘어오는자료들과각파트의담당자들이맞닥뜨리게되는상황극을편하게풀어써볼까합니다.
살려야 할 원칙과 흔들리지 않아야 하는 기본 뼈대가 세워지는 과정도 이에 해당되겠고요,
자주접하게되는눈에보이지않아, 상상력을발휘해서진행해야하는것들 위주로 글을 써볼려고 합니다.
기술적인 내용들도 재미있는데, 앞으로 계속 파고 들어갈 예정이니 기대해주세요~ :)
오늘은 인류가 중력을 기술로 이겨내며 발전한 건축양식 에 대해 글을 풀어보려고 합니다. 게임이나 문화적 발전을 설명하기 쉬운 서양 건축사쪽 위주로 풀었으며
(마야, 잉카, 앙코르와트 등 후계가 끊어진 문화권은 배제 하였습니다)
아무래도 이쪽은 외계기술 또는 신성개입이 아니고는 설명하기 힘든 부분이 있단 말이죠...
마야 사원 돌 조각.
여기에 한가지 미리 말씀드리고 양해를 구하고 싶은 점은, 역사적으로 기술이 초기에 발견된 시점보다는
그 기술이 시스템적이나 일반적으로 널리 사용되게 된 시점을 기준으로 하였습니다.
이런식으로 기술하지 않으면 어떠한 기술들은 연대가 기원전 몇 천년millenia 단위로 넓게 분산되기 때문입니다.
건물의 초기목표.
주거란 기후의 변화 등 외부 환경으로부터 가족의 생명과 재산을 보호하여 안전하게 지켜주는 공간이며,
더 나아가 가족의 건강 유지와 쾌적한 주생활을 영위하기 위한 취사·청소·세탁 등의 생활을 유지하기 위한
가사 노동이 이루어지는 곳입니다. 초기에는 아마 주거가 주목적 이었겠죠.
(지금이야 세받아먹기위한 고층빌딩들이 주류지만...)
듣기만해도 가슴떨리는 마이홈. 가지기 힘든너... 크흑
태초에 사람이 지상에서 활동할 즈음. 나무 밑에서 비바람을 피하는 것 정도가 첫번째 목표였겠지요.
체온 유지, 여러가지 위협 들에서의 방어 등 최초, 최고의 주거의 형태란 아마도- 동굴이었을 것입니다.
아저씨 3동 407호인데요 저 없으면 택배는 문앞에 놔두고 가주세요.
날씨 안좋은 날에는 틀어박혀 그림도 좀 그리셨지요. 화려한 필력.
무릇 천재는 엄한 교육과 반복으로 만들어지는법입니다.
점차 인구가 늘어나고 농경생활이 퍼지면서 수용이 한정된 자연동굴을 떠나 일반 평지에서 살아가는 연구를 하게 됩니다.
여기에는 막집과 움집이 있는데 막집dwelling 은 그대로 텐트처럼 평지에 지은 집,
움집pit-house는 반지하처럼 땅을 약간 파고 그 위에 지붕을 올린 형태입니다.
벽을 만들 수 없었으므로, 아래로 파들어가면 땅이 벽 역할을 해 준다는 역발상의 발로랄까요.
우리가 무식해서 벽이 없다고? 불가능. 그것은 아무것도 아니제.
실제 움집-피트하우스 유적. 생각보다 깊습니다.
단지 겉모습 만으로는 막집과 딱히 구분이 가지 않습니다.
눈썰미 좋으신분은 요거 발더스게이트에서
사람 가둬놓는 감옥 용도로 써먹은거 아실거에요 사다리만 치우면 되니까...
사람들이 모이면서 부족장/신관 등의 계급이 생깁니다.
이런 중요한 사람들의 장례를 치르는 부족장의 묘지는 샤머니즘과 결합해 기념 및 의식의 의미가 들어가게 되고
주변부족에게 세력을 자랑하려는 용도도 있었지요 ‘나는 이정도의 노동력을 부릴 수 있어’ 라는 패기로 고인돌dolmen이 등장하게 됩니다.
인구도 부족하던 시대에 어떻게 이런 돌을 올릴 생각을 했는지 아직도 미스테리입니다.
우리 누가 더 큰돌 얹는지 좀 시합좀 해볼까.
늬들 이정도 올릴수 있어? 쫄리면... 돌아가라.
너무나 유명한 스톤헨지. 늬들이 피똥싸면서 무덤올릴때
우리 동네는 가볍게 놀면서 달력을 만들었단다 아가야...
사람들은 이제 최초로 거대한 공간에 대한 욕구를 알아차리게 됩니다.
네 그렇습니다 -아파트 평수 늘려가듯이... 한번 올라간 눈높이는 돌이킬 수 없지요.
농담이 아니라 저 돌짝들이 이렇게 보였을 거라고요 진짜.
강과 건축
유프라테스 문명 - 수메르 (기원전 3300년경)
인류문명의 가장 오랜 발상지중 하나인 유프라테스 강 유역- 수메르지역은
상류에서 밀려와 풍부한 진흙으로 가득차 있을뿐 근처에는 돌산이 없어 석재조차 귀했습니다.
그들은 그나마 풍부한 진흙을 형틀에 넣고 구워내어 벽돌을 쌓는 조적구조 Masonry Construction를 집중적으로 발전 시킵니다.
기껏해야 점토판에나 새겨야 했던 수메르와 파피루스를 사용하여 책을 만들던 이집트의 문명도는
이미 궤를 달리하는 것이었습니다.
파피루스 종이.
파피루스Cyperus papyrus. 나일강에 많은 이 식물로 종이를 만들었죠.
그리스, 초기 로마까지도 사람들은 판위에 왁스를 발라 거기 글자를 긁어 새겼습니다...
(참고용 2500년쯤 후의 로마의 타블렛 세트.
왁스를 담고 굳혀 뾰족한 스타일러스로 쓴 후 닫고 오른쪽 반지로 봉인용 왁스에 인장을 새겼습니다.
위쪽은 아주 얇은 나무판에 잉크로 쓴 쪽지?지만 쪼개지거나 부서지기 쉬워서 보존용으로는 적합하지 못했습니다.
(30대분들 어렸을때 만두 포장해주던 나무박스 기억하세요 노란 고무줄로 감아줬지요)
뭐 일단 여기에서부터 시작합니다.
슥 보니 UV 밑에 U와 V가 떨어져 있는게 보이는군요.
파랑색 공 아이콘이 U와 V의 옆에 각각 보이니까 당연히 float 으로 출력되는 거겠고..
U와 V가 각각 떨어져 준비가 되어 있는걸 볼 수 있습니다. 하긴 저게 미리 없으면 방법이 없겠지..
그럼 떨어뜨리는 것은 할 필요 없이 저걸 합쳐주는 것만 준비하면 되겠군요.
그럼 좀 귀찮지만, 합쳐 주는 뭔가가 추가로 필요하다는 것을 알 수 있습니다.
빈 화면에서 오른클릭해서 , Math를 찾아서 VectorConstruction 을 만듭시다.
즉, '준비된 빈자리의 float4 벡터' 입니다.
근데 재미있는 것은, 4자리가 준비되어 있긴 하지만 이 VectorConstruction에 몇 개의 수를 넣는냐에 따라 float 숫자가 달라진다는 거지요.
즉 X한테만 숫자를 넣으면 float 을 출력하고,
X,Y 에다가 숫자를 넣으면 float2를 토해내고
X, Y, Z 에다가 넣으면 float3을 토해내고
X, Y, Z, W 에다가 넣으면 자동으로 float4를 토해내는 신통방통한 놈이란 말입니다.
그러므로 우리는 여기다가 U와 V 를 넣겠습니다. 두 개 넣었으니 float2가 출력되겠죠.
이전에도 말했지만, U와 V 는 X와 Y 랑 똑같은데 그냥 이름만 다른거라고 말씀드렸었지요
자, 기존에 연결되어 있던 UV 라인을 삭제하고,
U와 V 를 각각 X와 Y에 넣어서 합쳐줬습니다.
그리고 나온 Vector를 UV에 연결해 줬지요. [각주:4]
이렇게 하면 기존에 작업한 것과 똑같습니다. 그럼 성공한겁니다.
그렇지만, 전과 다른것은 이제 드디어 U와 V 값을 따로 접근할 수 있게 되었다는 것입니다.
이제 벌써 3달을 넘게 하셨으니, 너무 쉬운건 살짝 점프하고 싶은데요.
아니, 그 전에 한 번 스스로 생각해 보세요.
V 한테 0.5 값을 더하려면 이제 어떻게 해야 하지요?
......
..
설마 알겠지
.. 어서 안다고 말해...
설마 여기까지 배워놓고 모를까...
네, 정답공개합니다.
네에. 이렇게 하면 되겠죠?
멀쩡히 잘 가고 있던 V 값을 끊고, 그 사이에 MathOperator를 끼워 넣은 다음에, Constant(상수)를 0.5만 더해주면 되는 거지요. 그림을 보니 위아래로만 움직였습니다!!!!
-0.5 를 하면 반대로도 움직이겠지요!
다양한 숫자를 넣어보시고 테스트 해 보십시오.
자아 ..... 요걸 이용하면 뭘 할 수 있을까요?
바로
폭포나 흘러가는 강을 만들 수 있습니다
폭포나 강은 보통 물 텍스쳐가 일정 방향으로 흘러가는 방식으로 만들지요.
이럴때 사용할 수 있는게 이 쉐이더입니다.
UV를 어떻게 펴냐에 따라 , 곡선으로 흘러가게 할 수도 있다는 말씀. Ndoors Co. 삼국지를 품다.
쉐이더에서 V 값만 무한히 증가하게 애니메이션을 준다면, 폭포나 흘러가는 강을 자연스럽게 만들 수 있습니다.
요것도 알아서 흘러가게 할 수 있는데, 이건 좀 있다가 해 보도록 합시다. 아직 개념설명이 끝나지 않았어요.
4. UV를 눈으로 봅시다.
네, 위에서는 이제 Vector Construction을 통해, 조각조각 나눠져 있던 float를 합쳐서 float2 등으로 만드는 것을 알아봤습니다.
자... 여기서 ... 뭔가 할 수 있을 것 같지 않나요...?
바로... UV를 눈으로 보는 것 말입니다!!!!
워워.. 긴장하지 마세요. 별 거 아닙니다.
그전에는 분명 뭐야 이게? 했던 것이겠지만, 이제 여러분들의 수준에서는 '아 .. 그거!' 라고 알 수 있는 수준인 단원입니다.
게다가 UV를 눈으로 보게 되면, 그동안 개념으로만 알고 있었던 UV라는 것이
확실하게 이해되게 됩니다! 그래픽 디자이너는 눈으로 봐야만 이해하곤 하거든요.
자 , 이번에 필요한 것은 아까 배운 VectorConstuction 과 UV 뿐입니다. 다른 것은 지워버리셔도 좋습니다.
여기서 우리가 알고 있는 몇 가지 사실을 나열해 보겠습니다. 무엇이 상상되는지 한 번 생각해 보시죠.
- UV 는 0과 1 사이의 값으로 표현된다.
- 칼라도 0과 1사이의 채널값의 모임으로 표현된다.
- 칼라는 0과 1사이의 채널이 R,G,B 세 군데에 들어가면 칼라가 된다.
- VectorConstruction 은 한 채널 (float) 을 합쳐서 최대 4개의 채널 (float4) 을 가진 벡터로 만들어 준다.
자 상상이 끝나셨는지? 뭘 하려는지?
잘 모르시겠다고요?
그럼 아래 그림을 보세요
짠
어라... U 값을 X, Y, Z 에 넣어서 float3로 만들었습니다. 그리고 그걸 다시 AmbientColor로 만들었습니다 :)
그럼 그림은 어떻게 보일까요?
이렇게 보입니다 :) UV의 U 값이 흑백으로 보입니다!! 그도 그럴 것이, X,Y,Z 모두에 U 값을 넣었으므로, float3(0,0,0) 부터 float3(1,1,1) 까지의 색상이 되었지요? UV의 U가 눈으로 보입니다 >_<
물론 U가 아니라 V도 볼 수 있습니다.
우리 그래픽 디자이너들은, 눈으로 봐야 이해하기가 쉽잖아요!
어디가 V 값이 0인줄 알겠고 어디가 1인줄 알 것 같애!!!
프로그래머들은 자기네들만 이런거 보고!!! 우린 보여주지도 않고!!! 흐규흐규!!!!
"Vertex가 UV값을 가진다" 라고 설명하면, "그럼 그 Vertex 사이는 어떻게 되어 있는거야?" 라고 생각할 수 있겠지요. 이제 그림을 보면 명백해 지지요.
"두 개의 다른 Vertex 값의 사이는 두 값을 블랜딩 해 줍니다" [각주:5]
어때요? UV를 눈으로 보게 되니까 뭔가 기쁘지 않아요?
아직 끝나지 않았어요!
끝나지 않았어 끝나지 않았어
이번엔 UV를 동시에 보기로 하죠. U는 Red 채널에 넣고, V는 Green 채널에 넣는 거예요. B가 남으니까....B는 그냥 상수 0 을 넣어서 색을 없애 보기로 하죠!! 파랑색은 업ㅋ엉ㅋ
우왕 UV가 칼라로 한 번에 보여요!!! UV가 0,0 인 부분은 Z값도 0을 넣었으니까 (0,0,0)이 되어서 검은색이 나왔구요!
UV가 (1,1)인 부분은 RGB로 하면 (1,1,0) 이 되니까 노란색이 되었어요!!!
어때요, UV를 눈으로 볼 수 있지요?????!!!!??
이렇게 UV를 눈으로 보게 되었습니다. 그동안 '니시카와 젠지' 씨의 글이나 기타 그래픽스 이론 글을 읽다가 저런 뭔가 무지개색의 그림이 나오면 저게 뭘까.. 라고 더이상 생각하지 않아도 좋습니다!! 이젠 저 색깔이 숫자로 보여야 해요!!!
이전에도 말씀드렸지만, 숫자를 색으로, 색을 숫자로 변환해 가면서 볼 수 있는 능력!
쉐이더를 공부할때는 꼭 필요한 능력입니다.
5. 실습 : UV를 에니메이션 합시다.
원래 4까지 하고 끝내려 했는데, 진짜 이것만 하면 이제 더는 UV를 안건드려도 될 것 같네요.
요것까지만 해 보지요. 실습입니다.
자 이번엔 흘러가는 강을 만들 거예요. 폭포라고 해도 괜찮겠죠.
우선 준비할 것은 이것입니다.
텍스쳐는 일단 귀찮으니까 있는거 쓰도록 합시다.
DClouds_32bit.dds 가 괜찮아 보이네요. Texture를 생성해서 이 텍스쳐를 입혀 보세요 [각주:6]
세로로 길죽하게 입혀졌군요. 뭐 이대로도 좋다면 할 말 없지만... 저는 좀 조절하고 싶네요
조절이 가능하게 하기 위해서 , Vector Construntion 을 이용해서 UV를 나눠 놓읍시다.
이렇게요. 뭐, 당연하게도 변한건 없지요.
근데 이번엔 U 값 (X 축)이 좀 늘어난 것을 완화시켜 보도록 하겠습니다.
생각해보세요... 귀찮겠지만... 어떻게 하면 되나요?
U값(X축) 을 타일링 시키면 되겠지요? 세로 타일링 수치를 늘이면 늘어난게 좀 완화되지 않겠어요?
타일링을 만드는건? 곱하기죠?
그러니까 아래처럼 되는거죠.
이해 안되시면 차근차근 잘 보시면서 기억을 되짚어 보세요 :)
네, 이렇게 U 값에 타일링 (곱하기) 를 추가해 놨습니다. 상수 (Constant)의 숫자를 좀 올려보세요.
저는 2 정도로 하니까 그런대로 괜찮게 되었네요.
흑백인게 마음에 안 드시면, 마지막에 칼라값을 곱해주세요.
푸른 계열 색을 곱하면 괜찮겠지요 .
..촌스럽네요.
그냥 이게 무료강의의 폐해라고 생각하고 넘어가도록 합시다.
자 이젠 물이 흘러가게 해야죠.
물이 흘러가는건? UV의 이동입니다. 이동은 어느쪽으로? 역시 아까 했던 것처럼 위아래로 흘러가야 하니까.. 간단합니다. U 에다가 '덧셈' 을 해주면 되겠군요.
자 , 잘 보세요. 여기입니다. 흐름을 눈으로 잘 느껴보세요.
노드로 하면 오히려 조금만 복잡해져도 흐름을 놓치는 경우가 많거든요. 오히려 코드가 보기가 쉽다는... 쿨럭.
요령은, 오른쪽 부터 보는겁니다. 흐름을 느껴보세요. 오른쪽 아래 UV부터 봅니다. 좌측으로 흘러갑니다...
- UV의 U 값이 ... [각주:7]
- Input B 로 들어가서
- 상수(Constant) 랑 곱해졌습니다.
- 거기서 곱셈이 끝이죠.
- 그리고 그걸 Vector Construction의 X 에다 집어 넣는 것입니다.
두 자리 넣었으니 float2를 뱉겠다고 Vector 의 공 아이콘이 보라색으로 변한 꼼꼼한 디테일 보세요. [본문으로]
블렌딩. 사실 블렌딩이라고 하면 맞지 않습니다. 그래픽 디자이너분들의 용어로는 "보까시" 해준다 라던가"그라디에이션" 해준다 정도가 통용되는 말이겠지요. 그렇지만 프로그래머의 용어로 이걸 말하려면 "인터폴레이션 해준다" 또는 "보간해준다" 라고 하는 것이 좋습니다. 구체적으로 말하면 리니어 인터폴레이션 (Liniar Interpolation) 이지요. 혹은 이걸 번역해서 '선형 보간' 이라고도 합니다. 참 다르고도 신기한 그래픽 디자이너들과 프로그래머들의 용어의 세계입니다. :) [본문으로]
설마 이젠 이런 것 정도는 설명 안해도 아시겠죠??? 이 텍스쳐는 ShaderFX를 설치하면 기본으로 들어 있는 것이 또한 마음에 드는 점입니다. [본문으로]
MathOperator를 선택하고 오른쪽 메뉴에 보면 덧셈으로 바꿀 수 있지요..? [본문으로]
재미있는 것 하나 알려 드리지요. 이렇게 만들어 놓은 물 오브젝트를, 1. 맥스에 가서 메터리얼 에디터를 열고, 2. 슬롯을 하나 빈 것 선택한 다음에, 3. 메터리얼 에디터에 있는 스포이드 아이콘을 찍어서 지금 만든 물 오브젝트를 찍어보세요!!! 신기한 일이 벌어질겁니다!!! 뭔지는 안가르쳐 드려요!!! [본문으로]
참 지루하고 재미없던 4회짜리 연재가 드디어 끝나간다!! 다시한번 재미없는 중년남이라는 사실이 여실히 드러난 것에 조금 자괴감도 들긴 하지만, 애초부터 이 글을 쓰기 시작한 것이 잘못된 만남이였을지도 모르겠.. 게다가 쓰다보니 전공 분야도 아닌;; 프로듀싱과 얽히는 내용까지 끄적이는 바람에 내용이 지루하게 길어져서;; 너무 길어지면 아무도 안읽을까봐 핑계삼아 프로토타이핑은 2번에 나눠 업데이트를 할 예정이다.
어쨌든 프로토타입. 게임으로도 동명의 게임이 출시된 바 있지만, 어떻게 보자면 참 공대스러운 단어일수도 있는데 우리가 참 여기저기서 많이 듣는 단어이기도 하다. 뭔가 만들때 실험삼아 먼저 만들어 본 목업(Mock-up)도 프로토타입이라고 하고, 테스트를 위해 제작된 여러가지 구동되는 샘플들도 프로토타입이라고 하고.. 사전을 뒤져보면 '원형(原型)'이라고 뜻이 뜨는데, 이걸 또 굳이 해석하자면 '본래의 모습' 정도이려나;; 어쨌든, 최종 단계에 이전에 어떤 목적을 갖고 구현된 구체적인 모습 정도로 생각해 볼 수 있을 것 같다.
풍동실험을 위해 만들어진 2009 Tesla Roadster Sport의 프로토타입 목업. 갖고싶..
게임 개발에 있어 프로토타입이라는 것도 사실 크게 다르지 않겠지만, 프리-프로덕션 단계에 한정해 프로토타이핑에 대해 이야기 하자면 앞에서 다룬 의미와는 조금 차이가 있을 것 같다. 왜냐하면 그 목적이나 만들어진 프로토타입의 수준이 최종 단계 이전의 구현된 구체적인 모습보다는 상상해보았던 기술적인 혹은 기능적인 메커니즘을 실제로 구현해 게임으로써의 가능성을 검증하거나 보완해내기 위한 정도이거나, 실제로 어떻게 플레이 될지 혹은 어떻게 보여질지를 스케치나 영상, 혹은 시뮬레이션으로 구체화 함으로써 구현 이전에 방향성을 확인하고 더 재미있는 쪽으로 정리하고 확장해내기 위한 정도로 하나의 완성 직전의 모습보다는 굉장히 '부분적'으로 나뉘어있는 특정 단위로 만들어질 경우가 더 많기 때문이다.
그렇다면 게임의 프로토타이핑을 유저경험의 시뮬레이션이라는 전제하에 진행한다고 가정했을 때, 그 프로토타입을 만드는 방법에는 어떤 것들이 있을까?
수많은 개발사나 프로젝트가 존재하는만큼, 정말로 다양한 방법이 있을 수 있겠지만 여기서는 그 중 개인적인 경험을 통해 체험했던 큰 두가지 정도만 다뤄보고자 한다. 하나는 최종 단계에서 사용될 각 기능과 규칙 요소들을 순차적으로 실제 구현해가며 게임의 뼈대부터 차근차근 올려나가는 'Low Level Game Design'의 방법이고, 다른 하나는 최종 단계에서 플레이 될 유저경험을 예상하고 이를 우선적으로 각각 동시에 시뮬레이션 해본 후 그 중 가능성이 있어 보이는 방법만을 선별 구현해 추후 하나의 형태로 합쳐나가는 'High Level Game Design'의 방법이다. (각 용어에 대한 사전적 정의는 위키피디아 http://en.wikipedia.org/wiki/High-_and_low-level 참고)
전자의 경우는 의도하는 게임 플레이나 각 기능(우측 그림에서 수평적으로 배치된 각각의 Component)이 실제로 하나씩 완성되어가면서 개발되기에 시스템을 쌓아가며 비교적 일정을 준수하기 용이하다는 장점이 있지만, 그 시스템 완료 후 정상적으로 동작하는지 QA와 그에 컨텐츠를 대입한 게임 플레이를 만들어 적용한 후에나 유저경험의 감성적 품질을 확인할 수 있다는 단점을 가지고 있다.
후자의 경우는 영상데모나 로직데모 등 작은 단위의 컨텐츠를 시스템 구현과 별개로 쪼개서 만든 목업(우측 그림에서 수직적으로 도려낸 The Slice)을 통해 유저경험의 감성적 품질을 예측해본 후 좋은 것만 선별적으로 개발할 수 있는 장점이 있지만, 목업에 있어 개발 일정이 지연되기 쉽고 이러한 각각의 조각난 목업들에 포함된 각 기능 단위의 완성된 시스템을 만들어 통합할 때 부하가 커지는 단점이 있다.
일부는 스크럼을 비롯한 애자일 개발도 프로토타이핑 방법 중 하나 아니냐고 불만을 제기할 수도 있겠지만, 그는 위의 각 방법을 어떻게 진행하느냐의 과정에 대한 방법이 될 순 있어도 독립적인 하나의 전혀 다른 프로토타이핑 방법은 아니라 생각되어 여기서는 제외하였다.
In Japan, assets for a game are developed in parallel; in the U.S. "game development is typically a vertical slice." Thus the early build, "the team tried to create a small piece of the experience that resembles the final product."
일본에서는 게임의 요소들이 병렬로 개발된다. (반면) 북미에서의 게임 개발은 전형적으로 수직형 조각의 형태가 된다. 그러므로 (북미 개발의) 초기 빌드에서 개발팀은 최종 제품과 닮은 (유저)경험의 작은 일부를 만들어내려고 한다.
Demon's Soul ⓒ From software
설명이 충분하진 못한 것 같지만.. 앞의 정의나 kotaku 기사에서의 요점은 일본을 위시한 Low Level 접근에서는 각각의 기능을 완성해가며 게임이 조금씩 형태를 갖추기 때문에 최종 모습의 구체적 확인에 시간이 걸리고 그조차 제공되는 순서대로 볼 수 밖에 없는 반면, 북미를 위시한 High Level 접근에서는 각 기능 단위가 아닌 어떤 유저경험의 특징(?) 단위로 그 모습을 먼저 시뮬레이션 해보고 들어가기 때문에 좀더 최종 모습을 먼저 확인할 수 있다는 점이다.
하지만 프로젝트의 특징이나 장르 혹은 팀의 상황 등을 고려해본다면, 두 방법 중 어느 것이 더 좋고 나쁘다로 단정하기는 어렵다. 최초에 제시된 비전 자체가 감성적인 유저경험보다는 어떤 로직적인 측면에서의 재미에 집중해야 하는 퍼즐 게임이나 아케이드 게임에서는 Low Level의 프로토타이핑이 더 효율적이고 유용하다. 반면, 다양한 행동을 통해 진행되는 어드벤처나 RPG 같은 게임들에서는 어떤 행동들로 어떤 플레이를 만들 것인가에 대한 High Level 접근이 좀더 개성있고 차별화되는 프로토타이핑을 도와줄 것이다. 물론 이런 RPG류의 게임이라도 논타게팅, 던전메이킹, 소셜네트워크 연동 같은 기능적 요소에 치중한 비전을 갖고 있다면 그 또한 기술적 검증과 그로부터 파생될 재미와 가능성을 먼저 확인해 볼 수 있도록 Low Level의 접근이 더 좋을 수도 있을 것이다.
국내의 일반적인 게임 개발에 있어서도 대부분 프레임워크를 만들고 렌더링, 컨트롤러, 로직 등 실제 구현에 필요한 요소들을 하나씩 쌓아올려가며 프로토타입을 만드는 Low Level 기반의 개발이 더 많은 것 같다. 아마도 최초의 프로토타입은 이동과 기본 전투, 두번째 프로토타입은 레벨 구성과 스킬 전투 등등으로 각 기능을 순차적으로 개발하며 쉐이더와 라이팅도 적용해보고, 엑셀 연동 데이터 구조도 만들고 하는 식으로 개발해 나갔을 것이다. 이런 방식은 처음 몇 번의 프로토타이핑은 매우 빠른 반복개발 속에서 점차 확확 달라지는 모습의 플레이 가능한 결과물을 도출해 몇 차례의 까다로운 초반 허들을 통과할 수 있게 도와줄 것이다. 하지만 이 방법의 맹점은 개발을 하면 할수록 기존에 완성된 기능에 새로운 기능을 추가해 나가는데 요구되는 시간과 자원이 계속적으로 늘어난다는 점이다. 각자가 어떤 요소에 대해서 같은 상상과 느낌을 갖고 개발하지 못하는 경우도 많아지고, 그럴 때마다 이미 프로그래밍되어 구현된 결과물이 기획에 맞네 다르네, 어쨌든 난 만들었으니 쓰는 사람이 값을 넣어서 수정해보던지 말던지 등등으로 사후 확인을 하는데 자원이 소모된다.
구현된 결과물을 함께 보고 기획자, 프로그래머, 그래픽디자이너 각각의 입장이 확연하게 갈리는 순간!!
또, 기획이 변경되거나 피드백의 벽에 부딪히게 될 때마다 요청되는 요소들이 구현된 기능 기반의 환경에서 추가할 수 있는 것인지, 예외처리를 해야하는 것인지 등등까지 따지고 들어가다보면 프로토타이핑을 통해 검증하는데까지 소요되는 시간이 예측 불가능한 수준으로까지 달라질 수 있다. 이렇게 마일스톤의 일정이 지연되다보면 허들을 통과하기 위해 보여줘야 할 부담이 누적되어, 리더의 입장에서는 전에 없던 어떤 것, 더 많은 기능 등에 집착하게 만들기 쉽다. 프리-프로덕션 단계에서의 이런 변화는 사실 당연한 것일 수 있지만, 이미 구현된 시스템과 로직이 있는 상태에서는 허들의 피드백이나 팀이 당면한 상황에 맞춰 변경하고 빼버리고 전혀 다른 것을 추가하려는 시도의 반복 자체가 팀에 큰 부담을 안기게 된다. 시간이 충분하다면 프리-프로덕션에서도 플레이 데모 형태의 프로토타입을 만드는 것이 나쁠 것이야 없겠지만, 그렇지 못하다면 굳이 어떤 게임 플레이로 유저경험의 재미를 살릴 것인지를 찾기도 이전에 프로덕션과 다른 없는 단계로 개발을 하면서 부담을 키워나갈 필요는 없지 않을까..
프리-프로덕션 단계에서는 게임의 최종 버전을 예상하여, 어떤 플레이들이 유저경험으로 전달될 것인지를 먼저 쌓아두는 것이 낫지 않을까 하는 (지극히 개인적인) 생각이 든다. 팀이나 프로젝트의 규모가 충분한 기간과 버짓, 인력을 통해 순발력 있게 프로토타입을 뽑아낼 수 있는 형편이 되는 것이 아니라면 프리-프로덕션 단계에서 최소의 자원으로 최대의 준비를 먼저 해둘 필요가 있을 것이고, 그 과정에서 '사용자에게 직접적으로 어떻게 플레이될 수 있겠다'에 대한 감성적 경험을 시각화된 형태로 바라볼 수 있게 만드는 것이 이 지루한 연재에서 의미한 '비전'이라고 한다면, 마이크로소프트가 제시했던 프로덕티비티 퓨처 비전 같은 영상이 그 개념에 대한 감을 잡게 해줄 것이다.
원래 이번에 다루려했지만 괜히 잘 알지도 못하는 프로듀싱 얘기랑 엮느라 빼먹은;;;; 게임에서의 사전영상화(Pre-visualization)에 대한 얘기를 진짜로 다음에 꼭 좀 해보자.