C#으로 일리히트 엔진 다루기

|
많은 게임관련 교육기관에서 닷넷환경에서는 XNA를 사용하려고 합니다만 배우기쉽고 퍼포먼스가 좋을지는 몰라도
XNA는 기능 확장성 관련해서 너무 취약합니다.(확장이 불가능하다 정도로 표현하는게 맞을 수도있습니다.)
예를들어 픽셀단위로 접근을 하려해도 쉽지않습니다.
픽셀쉐이더를 쓰면 되지않나요? 이렇게 반문 하실수도있지만 그 정도 아시는 분이 XNA를 왜? 배우려 하겠습니다^^; 그리고 어린학생이 픽셀쉐이더를 제데로 쓰는 학생이 몇이나될까요?

저는 교육현장에서 6년정도 일을 하고있습니다만 의외로 학생들의 요수사항은 쉽지않습니다.
왜냐하면 어린학생들은 어른들이 생각하지도 못한 정말 기발한 발상을 합니다. 그렇기 때문에 빠르게 개발할수 있다는 장점만을 내세운 XNA는 전혀 도움이 되지 않습니다. 차라리 스타2에디터를 가르치는게 더나을수도 있습니다.
게임은 창의적이여야 합니다. 그러나 범용성과 대중성을 내세워 게임제작에서 반드시 필요한 창의성을 제데로 표현하지 못하게 한다면 그것은 잘못된 정책 이라고 생각합니다.

한마디로 XNA를 정리하자면 '코드배이스이나 툴배이스보다 유연성이 더떨어진다.' 는 결론입니다. 누가 이런걸써야 하나요^^? 정말 생각 해보면 개그스러운 발상입니다.

그래서 닷넷기반위에서 게임프로그래밍을 하기 위해서 기존네이티브코드로된 엔진을 매나지드방식으로 불러오는 방법을 생각해볼수있습니다. 
저는 오거,일리히트,네뷸러,판다3D등의 공개엔진중에서 일리히트엔진을 선택했는데요.
몇가지이유가있습니다.
첫째로 유연성을 뽑을수있습니다. 유연성에있어서는 오거도 멀티 플랫폼이지않느냐 반문하실수도있겠는데요. 제가 말하는건 멀티 플랫폼뿐만아닙니다. 언어적으로도 유연해야된다고봅니다. 예를들면 성경책을보면 주님의 말씀은 여러개의 언어로 표현되지만 의미는 하나를 가지고있습니다. 이처럼 일리히트는 객체지향이라는 복음으로  설계가 되었습니다. 문제는 그순수성에 있습니다. 타엔진은 효율성을 내세워 c++종속적인 면을 일부가지게됩니다만 일리히트는 객체지향이라는 유일신하나만으로 순수하게 설계된 철학을 가지고있습니다. 결론적으로 일리히트는 언어에도 무관한구조를 가지게되었습니다. 일리히트를 표현 하는데 언어는 중요치 않습니다. c++로 구현된 예가 있을뿐 c++기반은 아니기 때문입니다.(영어로 쓰여진 성서책이있을뿐 성서가 영어는 아니죠.)

이런 철학은 닷넷과 궁합이 잘맞아떨어집니다.


일리히트엔진 공식 프로잭트 싸이트는 http://irrlicht.sourceforge.net 입니다. 여기서 정식 버전(1.7.1)을 릴리즈하고있으며 현제는 1.8버전을 준비중에 있습니다. 여러 언어와 바인딩한 예가있는데요. 그중에서 닷넷기반 으로 바인딩하는 방법에 대해서는 일리히트 포럼에 가셔셔 먼저 irrlicht lime을 검색하시면 관련 정보를 얻으실수있습니다.

소스포지 프로잭트가 위와같이 진행되고있으며 현재(2010.7) 버전 0.5가 나온상태입니다.

접근방식은 네이티브코드쪽 irrlicht.dll을 중간단계의 매나지드코드dll인 irrlichtlime.dll을 사용해서 닷넷기반의 매나지드코드로 접근 하는 방식을 사용했습니다.
이 방법의 최대장점은 이해하기 쉽고 단순하다는것입니다. 또한 그다지 큰단점도 없는듯합니다.




위의 소스 코드는 네이티브 일리히트코드중에 createDevice함수를 랩핑한 예를 보여줍니다. 


매나지드코드용 랩퍼 dll프로잭트를 만들때는 위와같이 CLR을 사용한다는 옵션을 줍니다.




라임솔루션 디랙토리 모양입니다. irrlichtLime프로 잭트가 랩퍼 입니다. 결과물은 irrlichtLime.dll이 나옵니다.

연습으로 간단하게 화면에 큐브를 돌려보는 예제를 만들어 보겠습니다.
먼저 프로잭트를 추가합니다.


콘솔 어플로 만듭니다.





라임을 컴파일하면 매나지드 랩퍼(irrlichtLime.dll)가 /bin 디랙토리상에 존재하므로 실행파일이 같은 곳에 있도록 지정해줍니다.

리퍼런스를 추가 합니다.


브라우져 탭으로 가셔셔 /bin 디랙토리에 있는 irrlichtLime.dll을 선택합니다.



그리고 소스를 다음과 같이 편집해 줍니다.(program.cs)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            IrrlichtLime.IrrlichtDevice device = IrrlichtLime.IrrlichtDevice.CreateDevice(IrrlichtLime.Video.DriverType.Direct3D9, new IrrlichtLime.Core.Dimension2Di(640, 480));

            IrrlichtLime.Video.VideoDriver driver = device.VideoDriver;
            IrrlichtLime.Scene.SceneManager smgr = device.SceneManager;

            IrrlichtLime.Scene.SceneNode node = smgr.AddCubeSceneNode();

            node.SetMaterialFlag(IrrlichtLime.Video.MaterialFlag.Wireframe, true);
            node.SetMaterialFlag(IrrlichtLime.Video.MaterialFlag.Lighting, false);

            IrrlichtLime.Scene.SceneNodeAnimator anim = smgr.CreateRotationAnimator(new IrrlichtLime.Core.Vector3Df(0, (float)3.14/4, 0));
            node.AddAnimator(anim);
            anim.Drop();

            smgr.AddCameraSceneNode(null, new IrrlichtLime.Core.Vector3Df(0, 10, -50), new IrrlichtLime.Core.Vector3Df(0, 0, 0));

            while (device.Run())
            {
                driver.BeginScene(true, true, new IrrlichtLime.Video.Color(100, 101, 140));

                smgr.DrawAll();

                driver.EndScene();
            }

            device.Drop();
        }
    }
}

실행 결과입니다.











And