Anatomy of Nebula3 - Loading Custom Model

개요


Nebula3에서는 현재 .n2의 Nebula2 리소스 파일 형태만을 지원하고 있는데, 이 글에서는 Nebula3를 확장하기 위해서 새로운사용자 정의 리소스 파일(메쉬, 애니메이션, 등을 위한 모델 파일)을 추가하는 방법에 대해서 간단하게 살펴 본다.

StreamModelLoader


StreamReader는 ResourceLoader 클래스의 서브 클래스이며 리소스 파일을 스트리밍을 통해서 읽어 들이는 처리를 한다. 읽어 들일때에는 비동기적인 방법으로 읽어 들인다. 아래 소스에서 보듯이StreamModelLoader::SetupModelFromStream 함수에서 리소스 파일의 확장자에 따라 적절한ModelReader를 생성하고 생성한 ModelReader에서는 리소스 파일을 파싱해서 실제로 읽어 들이는 처리를 한다.


bool
StreamModelLoader::SetupModelFromStream(const Ptr<Stream>& stream)
{
    n_assert(stream.isvalid());
    n_assert(stream->CanBeMapped());

    // first decide what ModelReader to use
    bool isLegacyFile = false;
    String fileExt = this->resource->GetResourceId().Value().GetFileExtension();
    Ptr<ModelReader> modelReader;
    if (fileExt == "n3")
    {
        // Nebula3 binary format
        modelReader = (ModelReader*) BinaryModelReader::Create();
    }
    else if (fileExt == "xml")
    {
        // Nebula3 XML format
        modelReader = (ModelReader*) XmlModelReader::Create();
    }
    else if (fileExt == "n2")
    {
        // legacy Nebula2 binary format
        modelReader = (ModelReader*) N2ModelReader::Create();
        modelReader->SetModelResId(this->resource->GetResourceId());
        isLegacyFile = true;
    }
    else
    {
        n_error("StreamModelLoader: unrecognized file extension '%s' in '%s'!",
            fileExt.AsCharPtr(), this->resource->GetResourceId().Value().AsCharPtr());
        return false;
    }


메쉬 데이터


Direct3D9::D3D9StreamMeshLoader를 상속하는 CoreGraphics::StreamMeshLoader 클래스에서는 메쉬 데이터 메쉬 데이터를 읽어 들여 정점버퍼와 인덱스 버퍼를 생성하는 일을 담당한다.D3D9StreamMeshLoader::SetupResourceFromStream() 에서는 리소스의 리소스 아이디의 파일확장자를 검사해서 해당하는 메쉬 데이터 포맷을 읽어 들이는 함수를 호출한다. 리소스 파일의 확장자가 '.nvx2'인 경우에SetupMeshFromNvx2() 함수를 호출한다.

bool
D3D9StreamMeshLoader::SetupResourceFromStream(const Ptr<Stream>& stream)
{
    n_assert(stream.isvalid());
    n_assert(this->resource.isvalid());
    #if NEBULA3_LEGACY_SUPPORT
    if (this->resource->GetResourceId().Value().GetFileExtension() == "nvx2")
    {
        return this->SetupMeshFromNvx2(stream);
    }
    else
    #endif
    if (this->resource->GetResourceId().Value().GetFileExtension() == "nvx3")
    {
        return this->SetupMeshFromNvx3(stream);
    }
    else if (this->resource->GetResourceId().Value().GetFileExtension() == "n3d3")
    {
        return this->SetupMeshFromN3d3(stream);
    }
    else
    {
       n_error("D3D9StreamMeshLoader::SetupMeshFromStream(): unrecognized fileextension in '%s'\n",this->resource->GetResourceId().Value().AsCharPtr());
        return false;
    }
}


SetupMeshFromNvx2에서는 Legacy::Nvx2StreamReader를 통해서 .nvx2 파일을 읽어 들이고 이것을 정점 버퍼와 인덱스 버퍼에 연결한다.


bool
D3D9StreamMeshLoader::SetupMeshFromNvx2(const Ptr<Stream>& stream)
{
    n_assert(stream.isvalid());    
    Ptr<Legacy::Nvx2StreamReader> nvx2Reader = Legacy::Nvx2StreamReader::Create();
    nvx2Reader->SetStream(stream);
    if (nvx2Reader->Open())
    {
        const Ptr<Mesh>& res = this->resource.downcast<Mesh>();
        n_assert(!res->IsLoaded());
        res->SetVertexBuffer(nvx2Reader->GetVertexBuffer().downcast<CoreGraphics::VertexBuffer>());
        res->SetIndexBuffer(nvx2Reader->GetIndexBuffer().downcast<CoreGraphics::IndexBuffer>());
        res->SetPrimitiveGroups(nvx2Reader->GetPrimitiveGroups());
        nvx2Reader->Close();
        return true;
    }
    return false;
}


애니메이션 데이터


애니메이션 데이터도 메쉬 데이터와 크게 다르지 않다. 차이점이라고 하면 메쉬 데이터는 하드웨어쪽의 그래픽 디바이스드라이버(win32에서는 D3D)와 연결되어야 하지만 애니메이션 데이터는 그렇지 않다는 것과 최근의 애니메이션 처리와 관련한가장 중요한 이슈는 스트리밍이라는 점이다. 다시 말하면 애니메이션 데이터의 처리는 스트리밍에 훨씬 더 민감하다는 것이다.

현재(2009.03) 이 글을 쓰는 시점에서 Nebula3의 최신 버전은 2008년. Sep. 버전(9월 버전)인데 이 버전에서는이전 Nebula2의 애니메이션 데이터 파일인 .nax2 파일 포맷 지원이 생략되어 있다. 이는 이 후 버전에서CoreAnimation 모듈에서 기능이 강화된 애니메이션 모듈을 지원하기 위해서라고 한다. 대신에 2008. Feb. (2월)버전에서는 .nax2를 지원하는 코드를 살펴 볼 수 있다. 애니메이션 데이터의 처리 부분이 궁금하면 2008. Feb. 버전을보기 바란다.

결론


이상에서 살펴 본 클래스와 이들의 멤버 함수를 이해하면 원하는 사용자 정의 파일 포맷을 Nebula3에 쉽게 포팅해서 확장할 수 있다.

한가지 팁을 덧붙이자면 Nebula3에서는 모든 리소스를 읽어 들이는 처리가 기본적으로 비동기 방식으로 처리된다. 개발 단계에서는 이 방식이 디버깅 등에 불편한 경우가 있는데 이 때에는 Resource::ResourceMapper::SetAsyncEnabled() 함수로 비동기 처리를 비활성화할 수 있다.

by kimsama | 2009/03/28 09:37 | Nebula3 | 트랙백 | 덧글(0)

트랙백 주소 : http://kimsama.egloos.com/tb/1887608
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]

:         :

:

비공개 덧글

◀ 이전 페이지다음 페이지 ▶