Tutorial6- 메쉬

3D 파일 포멧 기초

 

.X File Format은 DirectX에서 지원하는 기본적인 3차원 메시파일 포맷이다.
지금까지는 모든 메시데이터는 3차원 좌표를 직접 지정하여 생성했지만 실제 게임을 제작한다면 전문 3D 디자이너들에 의해서 만들어진 메시 파일을 사용하여야만 한다.

 

맥스나 마야에서 X 파일 포맷으로 Export하려면 DX9 SDK가 아닌 추가 SDK(Extras SDK)를 다운 받아서 추가해야 한다. 추가 SDK를 설치하면 맥스와 마야에서 사용되는 X 파일 Exporter의 빌드 되지 않은 상태의 소스코드가 있다. 이 소스들 중에 사용하려는 버전에 맞는 플러그인을 빌드해서 사용하면 된다. 하지만 이 코드를 빌드하려면 DX9 외에 MAX나 MAYA에서 제공하는 SDK도 있어야 한다. 이 SDK들은 각 소프트웨어를 설치하면서 옵션으로 설치가 가능하다.

 

이렇게 추출된 X 파일은 IDirect3DXMesh를 통해서 완벽하게 제어가 가능하다.

[출처] Mesh - 기초|작성자 누리블루




<사진출저: 한국콘텐츠 진흥원>

//메시와 X파일을 이용하는 방법에 대해서 알아보자

 

// 소스분석

 

LPDIRECT3D9                g_pD3D       = NULL;       //D3D 디바이스를 생성할 D3D객체변수
LPDIRECT3DDEVICE9      g_pd3dDevice = NULL;      //렌더링에 사용될 D3D디바이스
 

LPD3DXMESH                g_pMesh          = NULL;    //메시 객체
D3DMATERIAL9*             g_pMeshMaterials = NULL;   //메시에서 사용할 재질
LPDIRECT3DTEXTURE9*   g_pMeshTextures  = NULL;   //메시에서 사용할 텍스쳐
DWORD                         g_dwNumMaterials = 0L;   //메시에서 사용중인 재질의 개수

 

//위에서 처럼 메시를 사용하기 위해서는 많은 정보에 대한 선언을 해 두어야 한다.

 

HRESULT InitGeometry()
{

   
// 재질을 임시로 보관할 버퍼선언
    LPD3DXBUFFER   pD3DXMtrlBuffer;
 

    // Tiger.x파일을 메시로 읽어들인다. 이때 재질정보도 함께 읽는다.
    if( FAILED( D3DXLoadMeshFromX( "Tiger.x", D3DXMESH_SYSTEMMEM, 
                                   g_pd3dDevice, NULL, 
                                   &pD3DXMtrlBuffer, NULL, &g_dwNumMaterials, 
                                   &g_pMesh ) ) )
    {

           // 현재 폴더에 파일이 없으면 상위폴더 검색
        if( FAILED( D3DXLoadMeshFromX( "..\\Tiger.x",

                                    D3DXMESH_SYSTEMMEM, 
                                    g_pd3dDevice, NULL, 
                                    &pD3DXMtrlBuffer, NULL, &g_dwNumMaterials, 
                                    &g_pMesh ) ) )
        {
            MessageBox(NULL, "Could not find tiger.x", "Meshes.exe", MB_OK);
            return E_FAIL;
        }
    }
 

     // 재질정보와 텍스쳐 정보를 따로 뽑아낸다. 
    D3DXMATERIAL*  d3dxMaterials =  (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
 

    // 재질개수만큼 재질구조체 배열 생성
    g_pMeshMaterials = new D3DMATERIAL9[g_dwNumMaterials];   
 

     // 재질개수만큼 텍스쳐 배열 생성
    g_pMeshTextures  = new LPDIRECT3DTEXTURE9[g_dwNumMaterials]; 
 

    for( DWORD i=0; i<g_dwNumMaterials; i++ )
    {

          // 재질정보를 복사

        g_pMeshMaterials[i] = d3dxMaterials[i].MatD3D;
 

          // 주변광원정보를 Diffuse정보로
        g_pMeshMaterials[i].Ambient = g_pMeshMaterials[i].Diffuse;
 

        g_pMeshTextures[i] = NULL;

        if( d3dxMaterials[i].pTextureFilename != NULL && 
            lstrlen(d3dxMaterials[i].pTextureFilename) > 0 )
        {

               // 텍스쳐를 파일에서 로드한다

            if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, 
                                                d3dxMaterials[i].pTextureFilename, 
                                                &g_pMeshTextures[i] ) ) )
            {

                     // 텍스쳐가 현재 폴더에 없으면 상위폴더 검색

                const TCHAR* strPrefix = TEXT("..\\");
                const int lenPrefix = lstrlen( strPrefix );
                TCHAR strTexture[MAX_PATH];
                lstrcpyn( strTexture, strPrefix, MAX_PATH );
                lstrcpyn( strTexture + lenPrefix,

                         d3dxMaterials[i].pTextureFilename, MAX_PATH - lenPrefix );

                if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, 
                                                    strTexture, 
                                                    &g_pMeshTextures[i] ) ) )
                {
                    MessageBox(NULL, "Could not find texture map",

                                                                         "Meshes.exe", MB_OK);
                }

            }
        }
    }
 

    /// 임시로 생성한 재질버퍼 소거
    pD3DXMtrlBuffer->Release();

    return S_OK;
}

 

중요:
여기서 내가 잠시 몰랐던것이 있는데 X 파일은 텍스처파일 및 기타 정보들을 가지고 있다.
그래서 구조체 포인터만으로 텍스쳐파일을 불러올수있는것이다. 또한 X 파일을 읽어들일 때 주의해야 할 것은 모든 메시 파일은 여러 개의 폴리곤으로 구성되어 있고, 폴리곤은 각각의 재질을 가질 수 있다는 것이다. 따라서 대부분은 재질이 여러 개일경우 메시를 재질별로 부분 메시로 분할한다. 이렇게 분할된 부분 메시는 부분 메시별로 따로 그려야 하는데, D3D에서는 DrawSubset()함수가 그 역할을 한다.

 

VOID Render()
{

     // 후면버퍼와 Z버퍼를 지운다.

    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 
                         D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );

    
     // 렌더링 시작
    if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
    {

          // 월드,뷰,프로젝션 행렬을 설정한다.
        SetupMatrices();
 

          // 메시는 재질이 다른 메시별로 부분집합을 이루고 있다.
          // 이들을 루프를 수행해서 모두 그려준다.

        for( DWORD i=0; i<g_dwNumMaterials; i++ )
        {

               // 부분집합 메시의 재질과 텍스쳐 설정

            g_pd3dDevice->SetMaterial( &g_pMeshMaterials[i] );
            g_pd3dDevice->SetTexture( 0, g_pMeshTextures[i] );

        
                // 부분집합 메시 출력

            g_pMesh->DrawSubset( i );
        }

          // 렌더링 종료
        g_pd3dDevice->EndScene();
    }

     // 후면버퍼를 보이는 화면으로!
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
 

메시를 그리기 직전에 그 메시에 해당하는 텍스쳐와 그 재질을 적용한다는 것을 잘 기억해 두자.
이렇게 여러 개의 재질은 여러 번의 SetTexture()+SetMaterial()+DrawSubset()으로 구성된다.
만약 텍스쳐 없이 재질만 있다면 SetTexture()과정을 생략할 수 있다.







 

이 글을 공유하기

댓글

Designed by JB FACTORY