2. Quake 3 Map

Posted 2007/09/15 19:16 by 수달

--------------------------------------------------------------------------

튜토리얼 2 : 퀘이크3 맵

이번 튜토리얼에서는 어떻게 하면 (1) 엔진 속으로 퀘이크3 맵을 읽어들이고, (2) 최적화된 렌더링을 위해 씬노드를 만들며, (3)유저가 움직이는 카메라를 배치할 수 있는지 보여준다. 이번 튜토리얼을 시작하기에 앞서 엔진 기초를 숙지할 것을 권한다. 아직 잘 모르더라도 튜토리얼 1. Hello World를 봤다면 무난할 것이다.

<예제 그림>


--------------------------------------------------------------------------

시작

----

Hello World 예제같이 시작해 보자. IRRLICHT 헤더 파일을 인클루드하고 콘솔 사용을 위한 드라이버 타입을 요청하자.


#include <irrlicht.h>

#include <iostream>


앞서 말한 바와 같이 IRRLICHT 엔진에서는 모든 것을 'irr' 네임 스페이스에서 찾을 수 있다. 매번 클래스 앞에 irr::를 사용하지 않으려면, 컴파일러에게 사용할 네임 스페이스를 미리 알려주어야 한다.

IRRLICHT엔진에는 서브 네임 스페이스로 'core', 'scene', 'video', 'io', 'gui'가 있다. Hello world 예제와는 다르게 이 다섯개를 'using namespace' 하지 않을 것이다. 이것들은 필요할 때마다 사용해야 한다. 물론 원한다면 다 써도 좋지만, 여기서는 단순하게 하겠다.


using namespace irr;


Irrlicht.DLL을 사용하기 위해 컴파일러 프로젝트 세팅을 추가하거나, 쉽게 #pragma 구문을 사용하자.


#pragma comment(lib, "Irrlicht.lib")


자, 시작이다. main()을 사용할 것이다. 왜냐하면 WinMain()을 치는 것보다 짧기 때문에.


int main()

{


Hello World 예제와 같이, createDevice()로 IrrlichtDevice를 생성한다. 다른 점이 있다면 하드웨어 가속을 할지 안 할지 사용자에게 물어본다는 것다. 소프트웨어 가속은 거대한 퀘이크 3 맵을 그리는데 너무 느리다. 하지만 원한다면 재미 삼아 해보는 것도 좋다.


//ask user for driver

video::E_DRIVER_TYPE driverType = video::EDT_DIRECTX9;

printf("Please select the driver you want dor this example:\n"\

" (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGl 1.2\n"\

" (d) Software Renderer\n (e) NullDevice\n (otherKey) exit\n\n");


char il

std::cin >> i;

switch(i)

{

case 'a': driverType = video::EDT_DIRECTX9; break;

case 'b': driverType = video::EDT_DIRECTX8; break;

case 'c': driverType = video::EDT_OPENGL; break;

case 'd': driverType = video::EDT_SOFTWARE; break;

case 'e': driverType = video::EDT_NULL; break;

default: return 1;
}


//create device anf exit if creation failed

IrrlichtDevice * device =

createDevice(driverType, core::dimension2d<s32>(640, 480));

if(device == 0)

return 1;


device->getVideoDriver()와 device->getSceneManager()를 매번 사용하지 말고, 비디오 드라이버와 씬매니저 접근 포인터를 얻어놓자.


video::IVideoDriver * driver = device->getVideoDriver();

scene::ISceneManager * smgr = device->getSceneManager();


퀘이크 3 맵을 보이기 위해 먼저 그것을 읽어야 한다. 퀘이크 3 맵은 .zip과 다를 바 없는 .pk3파일에 들어 있다. 그렇기에 일단 파일 시스템에 .pk3 파일을 추가 한 후에야, 그 파일에 접근해 읽을 수가 있다.


device->getFileSystem()->addZipFileArchive("../../media/map-20kdm2.pk3");


이제 getMesh()를 통해 메시를 읽을 수 있다. IAnimatedMesh 포인터 하나를 얻자. 알다시피 퀘이크 3 맵은 실제로는 애니메이션이 안된다. 그것은 그저 몇가지 매터리얼이 적용된 정적인 기하물들의 거대 집합체다. 즉, IAnimated Mesh는 1 프레임으로 구성되기에, 애니메이션의 첫번째 프레임을 얻어 addOctTreeSceneNode()를 이용해 OctTree Scene을 만들어야 한다. OctTree는 현재 보이는 영역만을 보이게해 씬을 최적화 한다. (역자주:거대 지형은 쿼드트리나 옥트트리로 성능 최적화를 한다.) 최적화가 안된 완전한 메시를 출력하고자 한다면, OctTree대신에 AnimatedMeshSceneNode를 사용할 수 있다. 한번 해보는 것도 좋다. addOctTreeSceneNode 대신에 addAnimatedMeshSceneNode를 사용한 후 비디오 드라이버에 의해 그려지는 정점을 비교해 보기 바란다. (이는 IVideoDriver 클래스의 getPrimitiveCountDrawed() 함수를 통해 확인 할 수 있다.) OctTree를 이용한 최적화는 대량의 기하 정보를 가진 거대 메시를 그리는데 유용하다.


scene::IAnimatedMesh * mesh = smgr->getMesh("20kdm2.bsp");

scene::ISceneNode * node = 0;

if(mesh)

node = smgr->addOctTreeSceneNode(mesh->getMesh(0));


맵 레벨이 원점(0, 0, 0)에서 모델링 된 것이 아니기에, 약간의 이동이 필요하다.


if(node)

node->setPosition(core::vector3df(-1300, -144, 1249));


남은 것은 퀘이크 3 맵을 보기 위한 카메라 설정뿐이다. 또한 이 카메라는 사용자에 의해 다뤄져야 한다. IRRLICHT 엔진에선 몇가지 다른 형태의 카메라가 가능하다. 예를 들어 마야에서 쓰이는 카메라는 왼쪽 버튼을 누르면 회전하고, 양 버튼을 누르면 줌이 되며, 오른쪽 버튼을 누르면 이동한다. 이것은 addCameraSceneNodeMaya()를 통해 만들 수 있다. 하지만 이번 예에서는 FPS(일인칭 슈팅 게임)과 같은 카메라를 사용하겠다.


smgr->addCameraSceneNodeFPS();


마우스 커서는 필요 없으므로 안 보이게 한다.


device->getCursorControl()->setVisible(false);


모든 준비가 끝났으니 그리기만 하면 된다. 이번에는 윈도 캡션에 매 초당 프레임 수와 그려지는 정점의 수를 표시하자. 'if(device->isWindowActive())' 구문은 선택 사항이다. 하지만 다른 프로그램이 활성화 상태일 때, 마우스 커서의 위치가 교란되 엔진 렌더링에 방해되는 것을 막기 위해 사용하도록 하자.


int lastFPS = -1;


while(device->run())

{

driver->beginScene(true, true, video::SColor(0, 200, 200, 200));

smgr->drawAll();

driver->endScene();


int fps = driver->getFPS();


if(lastFPS != fps)

{

core::stringw str = L"Irrlicht Engine - Quake 3 map example [";

str += driver->getName();

str += "] FPS : ";

str += fps;

device->setWindowCaption(str.c_str());

lastFPS = fps;
}

}


마지막으로 IRRLICHT 디바이스를 해제한다.


device->drop();

return 0;

}


모두 됐다. 컴파일 하고 프로그램을 돌려라!


+ Recent posts