3. Custom Scene Node
Posted 2007/09/15 19:18 by 수달--------------------------------------------------------------------------
튜토리얼 3 : 일반적인 씬 노드
---------------------------------------------------------
이번 튜토리얼은 조금 심화된 내용이다. 만약 IRRLICHT 엔진으로 무언가를 바로 돌려보고 싶다면, 먼저 다른 예제들부터 찾아 보는게 낫다. 튜토리얼은 일반적인 씬 노드를 어떻게 만들고, 어떻게 엔진 내에서 사용하는지를 보여준다. 일반적인 씬 노드는 IRRLICHT 엔진이 일반적으로 지원하지 않는 특수한 렌더링 기술을 사용해야 할 때 필요하다. 예를 들자면, indoor portal-based renderer나 advanced terrain scene node를 구현할 수 있다. 일반적인 씬 노드를 통해 쉽게 IRRLICHT 엔진을 확장할 수 있으며, 필요에 의해 적용할 수 있는 것이다.
예제는 짧고 간단하게 보여줄 것이다. 이 튜토리얼의 최종 결과는 아래의 그림과 같다. 별로 신통찮게 보이지만 일반적인 씬 노드의 모든 것이며, 사용자가 만드는 씬 노드의 좋은 출발점이다.
(역자 주 : 튜토리얼에 대한 나의 생각은 최하단에 있다.)
--------------------------------------------------------------------------
시작
----
먼저 헤더 파일과 네임 스페이스, 라이브 파일을 코드에 넣자.
#include <irrlicht.h>
using namespace irr;
#pragma comment(lib, "Irrlicht.lib")
이 부분이 이번 튜토리얼에서 가장 까다로운 부분이다. 임의의 씬 노드를 정하는 곳으로, 단순하게 하기 위해 indoor portal renderer나 terrain scene node는 사용하지 않고, 4개의 점으로 이뤄진 3D 객체를 만들도록 하겠다. 씬 노드를 IRRLICHT 엔진에서 사용할 수 있도록 클래스는 ISceneNode에서 상속 받고, 몇가지 함수를 재정의(overriding) 한다.
class CSampleSceneNode : public scene:ISceneNode
{
일단 몇가지 멤버 변수를 선언해, 이제부터 만들 tetraeder(지형의 한 사각 면을 이루기 위한 네 개의 점)를 위한 메모리를 정한다. 바운딩 박스, 4 정점, 그리고 tetraeder의 재질 정보를 확보하면 된다.
core::aabbox3d<f32> box;
video::S3DVertex Vertices[4];
video::SMaterial Material;
클래스 생성자는 씬 노드의 부모, 씬 매니저 포인터, 씬 노드의 아이디를 인자로 갖게 한다. 이 생성자는 내부적으로 부모 클래스 생성자를 호출하여 이후에 그려낼 4 정점과 씬 노드의 매터리얼 사양 등을 설정하게 된다.
public:
CSampleSceneNode(scene::ISceneNode * parent,
scene::ISceneManager * mgr,
s32 id)
: scene::ISceneNode(parent, mgr, id)
{
Material.Wireframe = false; Material.Lighting = false;
Vertices[0] =
video::S3DVertex(0,0,10,1,1,0,video::SColor(255,0,255,255),0,1);
Vertices[1] =
video::S3DVertex(10,0,-10,1,0,0,video::SColor(255,255,0,255),1,1);
Vertices[2] =
video::S3DVertex(0,20,0,0,1,1,video::SColor(255,255,255,0),1,0);
Vertices[3] =
video::S3DVertex(-10,0,-10,0,0,1,video::SColor(255,0,255,0),0,0);
IRRLICHT 엔진은 이런 방식으로 만들어지는 씬 노드의 바운딩 박스를 알아야 한다. 그것은 자동 컬링(안보이는 면 제거:은면 제거) 등 여러 부분에 쓰인다. 그렇기에 사용할 4 정점으로부터 바운딩 박스를 만들겠다. 만약 엔진에서 자동 컬링을 원치 않거나 할 경우에는 그냥 AutomaticCullingEnabled = false; 를 사용하면 된다.
Box.reset(Vertices[0].Pos);
for(s32 i = 1; i < 4; ++i)
Box.addInternalPoint(Vertices[i].Pos);
}
이들이 그려지기 전에 매 씬 노드의 OnPreRender()함수가 씬 매니저에 의해 호출된다. 이때 씬 노드는 자신이 그려져야 한다면, 자신을 씬 매니저에 등록한다. (역자 주 : 최적화를 통해 그려질 지형 면만 그려지게 한다. 즉 너무 먼 곳, 카메라 뒤, 앞선 물체에 가려 그릴 필요가 없는 부분 등을 OnPreRender()가 확인해 해당 씬 노드가 그려질지 안 그려질지 판단해 씬 매니저에 등록하거나 안 하거나 한다는 의미)
::render() 함수가 호출될 때 씬 매니저에게 반드시 알려주어야 한다. 왜냐하면 스텐실 버퍼 그림자는 다른 모든 씬 노드가 모두 그려진 다음에 그려지는 반면, 맞춤형 씬 노드는 처음부터 차례대로 자신의 내용을 그릴 것이기 때문이다. 게다가 카메라와 광원은 다른 씬 노드가 그려지기 전에 그려져야 할 필요가 있다. (역자 주 : 그래야 최적화 계산을 할 테니.)
자, 그럼 씬 노드를 등록해 보자. 카메라나 광원을 적용하고자 한다면, SceneManager->registerNodeForRendering(this, SNRT_LIGHT_AND_CAMERA);를 호출한다. 이제 기반 클래스인 ISceneNode의 OnPreRender()함수를 호출하고, 모든 자식 노드들을 등록하도록 하자.
virtual void OnPreRender()
{
if(IsVisible)
SceneManager->registerNodeForRendering(this);
ISceneNode::OnPreRender();
}
render() 함수에서 자질구레한 일이 일어난다. 함수에선 씬 노드가 자기 자신을 그리는데, 우리는 이 함수를 재정의해 tetraeder를그리도록 하자.
virtual void render()
{
u16 indices[] = { 0, 2, 3, 2, 1, 3, 1, 0, 3, 2, 0, 1 };
video::IVideoDriver * driver = SceneManager->getVideoDriver();
driver->setMaterial(Material);
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
driver->drawIndexedTriangleList(&Vertices[0], 4, &indices[0], 4);
}
적어도 세개의 추가적인 함수 호출이 필요하다. GetBoundingBox()는 이 씬 노드의 바운딩 박스를 리턴해줄 것이며, GetMaterialCount()는 이 씬 노드의 재질들 수를 리턴할 것이고(이번 예제에선 재질이 하나다.), getMaterial()은 해당 인덱스(차례)의 재질을 리턴할 것이다. 여기서는 단지 하나의 재질만 있기 때문에 0보다 큰 인덱스의 재질은 없다고 가정한다. (역자 주 : 그렇기에 한번만 호출했고 1을 리턴했다. 아니라면 매터리얼 수 만큼 반복해야 할 것.)
vitrual const core::aabbox3d<f32> & getBoundingBox() const
{
return Box;
}
virtual s32 getMaterialCount() { return 1; }
virtual video::SMaterial & getMaterial(s32 i) { return Material; }
}; //class CSampleSceneNode
씬 노드 클래스를 만들었다. 자, 이제 가뿐하게 엔진을 시작하고, 씬 노드를 만들며, 카메라를 배치해 결과를 살펴보도록 하자.
int main()
{
IrrlichtDevice * device =
createDevice(video::EDT_OPENGL,coredimension<s32>(640,480),16,false);
device->setWindowCaption(L"Custom Scene Node - Irrlicht Engine Demo");
video::IVideoDriver * driver = device->getVideoDriver();
scene::ISceneManager * smgr = device->getSceneManager();
smgr->addCameraSceneNode(0,core::vector3df(0,-40,0),
core::vector3df(0,0, 0));
씬 노드를 만들어보자. 만들고 나서 즉시 ->drop() 해줘야 한다는 것을 주목하라. 이게 가능한 이유는 일단 한번 만들면 씬 매니저가 그것을 관리 하기 때문이다. 그러나 프로그램이 끝날 때 해도 가능하긴 하다. (역자 주 : 아마 이 부분 때문에 IRRLICHT 엔진을 분석한 다른 분들이 '메모리 단편화'를 걱정하는 모양이다.)
CSampleSceneNode * myNode =
new CSampleSceneNode(smgr->getRootSceneNode(), smgr, 666);
myNode->drop();
단지 하나의 지형면으로만 구성된면 재미없으니, 씬 노드에 약간의 회전을 넣어 보자. 이런 방법은 다른 씬 노드에서도 할 수 있다.
scene::ISceneNodeAnimator * anim =
smgr->createRotationAnimator(core::vector3df(0.8f, 0, 0.8f));
myNode->addAnimator(anim);
anim->drop();
모든 것을 그린 후 마치자.
while(device->run())
{
driver->beginScene(true, true, video::SColor(0, 100, 100, 100));
smgr->drawAll();
driver->endScene();
}
device->drop();
return 0;
}
굿! 컴파일 후 프로그램을 돌려보자.
--------------------------------------------------------------------------
이번 엔진 튜토리얼에 대한 나의 생각.
처음 해석할 때 제목부터 좀 이해가 안되었는데, 해석을 마친 후, 튜토리얼 1. 2. 와 연계해 생각해 보니 어느 정도 윤곽이 잡힌다. 즉 튜토리얼 1. 2.에서 각각 캐릭터 모델링과 월드 맵핑(용어는 넓은 의미로 생각하라.)을 했다. 하지만 화면에 나타나는 모든 것을 이렇게 거대하고 폴리곤이 많은(?) 외부 모델로만 만들 수는 없는 것이다. 어떤 경우는 프로그래머가 직접 점 단위, 면 단위의 조정을 해야한다. 그것을 여기서 배워본 것이다.
이렇다고 한다면 Scene Node의 의미가 뚜렷해 진다. 각 노드는 각각 그리고자 하는 하나의 '무엇'이다. 그 '무엇'이 튜토리얼 1. 2.의 캐릭터나 월드일 수도 있고, 여기서처럼 직접 만든 점 혹은 면일 수 있다는 것이다.
이는 엔진 튜토리얼이 DirectX의 예제 순서와 역순임을 알 수 있다. DriectX의 예제는 먼저, 점, 선, 면을 이야기 하고, 카메라, 광원을 말한 후, 메시를 보이고, 애니메이션을 구현한다. 즉 작은데서부터 큰데로 나가는 것이다. 물론 이 방법은 기초를 충실히하며 천천히 단계를 밟을 수 있다는 이점이 있다. 하지만 기초 공부가 끝난 개발자 입장에서 당장 중요한 것은 큰 덩어리를 어떻게 보일 것인가이다. 게임을 만드는 것은 먼저 캐릭, 월드를 시작으로 인터페이스나 세세한 효과나 표현을 해내는 것이다. 그렇기에 엔진 튜토리얼의 구성이 Custome Scene Node부터가 아닌 캐릭터 씬 노드, 월드 씬 노드부터 시작한 것이다.
향후 엔진 튜토리얼의 구성도 직접적으로 게임을 만드는데 적용되는 것들을 순서로 되어 있다. 그렇기에 이 튜토리얼 서문에 '당장의 것이 필요하면 다른 튜토리얼부터 보라.'는 말이 담겨 있다. 이를 유의하며 계속해 나가도록 하겠다.
음......
여전히 한글화 한 제목 - '일반적인 씬 노드'는 어색하다. 그렇다고 '일반형'이라고 하면 모호해지고, '직접 찍은'이라고 하면 문장화된 제목이 될 것이다. 여기에 귀찮음까지 더해 그냥 두도록 하겠다.
'기본 카테고리' 카테고리의 다른 글
Irricht엔진튜토리얼 05. User Interface (0) | 2009.03.19 |
---|---|
Irricht엔진튜토리얼 04. Movement (0) | 2009.03.19 |
Irricht엔진튜토리얼 02. Quake 3 Map (0) | 2009.03.19 |
Irricht엔진튜토리얼 01. Hello World (0) | 2009.03.19 |
Equipment Damage Curves Cables , 단시간 허용전류2 (0) | 2009.03.19 |