.sdkmesh を描画

SDK Mesh(Teapot.sdkmesh)を描画します。
sdkmesh に関して気になるページを見つけました。
SDK メッシュ ファイル形式の概要
DXUT メッシュ形式 (.sdkmesh) は製品版のタイトルに推奨されるファイル形式ではありません。
この形式は、SDK サンプルの特定の要求に合わせて設計されています。
実際のアプリケーションでは、アプリケーションの特定の要求を満たす形式を優先し、このファイル形式の使用は避けてください。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プログラムの説明

  1. X-FILE に代わる物として DirectX10 から登場したの DXUT メッシュ形式(.sdkmesh)です。
    sdkmesh に関して気になるページがあるのですが、それはそれとして、取りあえず描画してみましょう。
    DirectX Sample Browser にはメッシュを描画するプロジェクトが沢山あるのですが、初心者には難しすぎます。
    そこで Teapot.sdkmesh を例にして、極力シンプルなプログラムを作成します。
    sdkmesh のモデルは DirectX SDK (June 2010) の下記のフォルダーに格納されています。
    C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Samples\Media\
    また meshconvert を使って X-FILE を DXUT メッシュ形式に変換することが出来ます。
    meshconvert の説明は X-FILE を sdkmesh にコンバートして描画 を参照して下さい。
  2. DirectX10 のプロジェクトなので MultiMon10 を使うことにします。
    DirectX Sample Browser で MultiMon10 のプロジェクトを作成して下さい。
    今回は Camera を使ってティーポットを操作します。
    ソースプログラムを圧縮形式で提供します。
    Shader は ティーポットを ArcBall で操作 から取得して下さい。
    ファイル名 説明
    sdkmesh.zip MultiMon10.cpp 圧縮ファイル
  3. #include と領域の宣言です。
    CModelViewerCamera を使うので "DXUTcamera.h" を include して下さい。
    g_Mesh がティーポットのメッシュです。
    DXUTCreateTeapot() で生成したときは ID3DX10Mesh* でしたが .sdkmesh では CDXUTSDKMesh を使っています。
    CDXUTSDKMesh は SDK Mesh の API をラップした便利なクラスです。
    g_Camera がモデルを回転する CModelViewerCamera です。
    #include "DXUT.h"
    #include "DXUTmisc.h"
    #include "SDKmisc.h"
    #include "SDKmesh.h"
    #include "DXUTcamera.h"
    
    ID3D10Effect*                   g_pEffect = NULL;
    ID3D10InputLayout*              g_pLayout = NULL;
    ID3D10EffectTechnique*          g_pRender = NULL;
    CDXUTSDKMesh                    g_Mesh;
    ID3D10EffectMatrixVariable*     g_pWorldVariable = NULL;
    ID3D10EffectMatrixVariable*     g_pViewVariable = NULL;
    ID3D10EffectMatrixVariable*     g_pProjectionVariable = NULL;
    ID3D10EffectVectorVariable*     g_pColorVariable = NULL;
    CModelViewerCamera              g_Camera;
    D3DXVECTOR4 g_Colors[2] = 
    {
        D3DXVECTOR4( 1.0f, 1.0f, 0.2f, 1.0f ),
        D3DXVECTOR4( 1.0f, 0.3f, 0.3f, 1.0f ),
    };
    
  4. OnD3D10FrameRender() ではタイマーで World を自動的に回転します。
    g_Camera の領域から g_World, g_View, g_Projection を Shader に設定して描画します。
    g_Camera で回転すると g_Camera 中の World 座標と View 座標が回転します。
    次の行で warning C4239: が出るかも知れません。
    g_Camera.SetWorldMatrix( *g_Camera.GetWorldMatrix() * World );
    気になるときは、次のように書き換えて下さい。
    D3DXMatrixMultiply( &World, &(*g_Camera.GetWorldMatrix()), &World );
    g_Camera.SetWorldMatrix( World );
    CDXUTSDKMesh を使うと描画は簡単で g_Mesh.Render() の一行だけです。
    void CALLBACK OnD3D10FrameRender( ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
    {
        // Rotate cube around the origin
        D3DXMATRIX  World;
        D3DXMatrixRotationY( &World, 60.0f * DEG2RAD((float)fTime) );
        g_Camera.SetWorldMatrix( *g_Camera.GetWorldMatrix() * World );
    
        // Clear the back buffer
        float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; // red, green, blue, alpha
        ID3D10RenderTargetView* pRTV = DXUTGetD3D10RenderTargetView();
        pd3dDevice->ClearRenderTargetView( pRTV, ClearColor );
    
        // Clear the depth stencil
        ID3D10DepthStencilView* pDSV = DXUTGetD3D10DepthStencilView();
        pd3dDevice->ClearDepthStencilView( pDSV, D3D10_CLEAR_DEPTH, 1.0, 0 );
    
        // Update variables that change once per frame
        g_pWorldVariable->SetMatrix((float*)&(*g_Camera.GetWorldMatrix()));
        g_pViewVariable->SetMatrix((float*)&(*g_Camera.GetViewMatrix()));
        g_pProjectionVariable->SetMatrix((float*)&(*g_Camera.GetProjMatrix()));
        g_pColorVariable->SetFloatVector( (float*)&g_Colors[0] );
    
        g_Mesh.Render( pd3dDevice, g_pRender, NULL );
    }
    
  5. OnD3D10CreateDevice() はデバイスを生成するときに呼ばれます。
    Shader は頂点座標と法線ベクトルで構成されるモデルに色を設定して描画するものを使用します。
    g_Mesh.Create() で .sdkmesh をロードします。
    CDXUTSDKMesh を使うとロードも簡単で g_Mesh.Create() の一行で、マテリアルからテクスチャまで全て面倒を見てくれます。
    このプログラムでは "C:\\DATA\\Sdkmesh" のフォルダーに格納されている "teapot.sdkmesh" をロードしています。
    &Eye, &At をパラメータとして g_Camera.SetViewParams() を設定します。
    HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice,
                     const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
    {
            :
            :
        // Find the D3DX effect file
        WCHAR str[MAX_PATH];
        V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"Normal.fx" ) );
        DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS;
            :
            :
        // Load the mesh
        SetCurrentDirectory(L"C:\\DATA\\Sdkmesh");
        V_RETURN( g_Mesh.Create( pd3dDevice, L"teapot.sdkmesh", true ) );
    
        // Initialize the view matrix
        D3DXVECTOR3 Eye( 0.0f, 3.0f, -7.0f );
        D3DXVECTOR3 At( 0.0f, 0.0f, 0.0f );
        g_Camera.SetViewParams( &Eye, &At );
    
  6. OnD3D10ResizedSwapChain() では、縦横比を計算して g_Camera.SetProjParams() を設定します。
    次に g_Camera を使ってティーポットをマウスで回転します。
    マウスで回転するプログラムは結構面倒なのですが、g_Camera を使うと g_Camera.SetWindow() を呼び出すだけです。
    マウスの左ドラッグでモデルが回転し、右ドラッグでカメラが回転します。
    HRESULT CALLBACK OnD3D10ResizedSwapChain( ID3D10Device* pd3dDevice, IDXGISwapChain* pSwapChain,
            const DXGI_SURFACE_DESC* pBufferSurfaceDesc, void* pUserContext )
    {
        // Setup the projection parameters again
        float fAspect = static_cast( pBufferSurfaceDesc->Width ) / static_cast( pBufferSurfaceDesc->Height );
        g_Camera.SetProjParams( D3DX_PI/4, fAspect, 0.5f, 1000.0f );
        g_Camera.SetWindow( pBufferSurfaceDesc->Width, pBufferSurfaceDesc->Height );
    
        return S_OK;
    }
    
  7. OnFrameMove() で g_Camera.FrameMove() を呼び出します。
    void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext )
    {
        g_Camera.FrameMove( fElapsedTime );
    }
    
  8. MsgProc() で g_Camera.HandleMessages() を呼び出します。
    LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, 
                              bool* pbNoFurtherProcessing, void* pUserContext )
    {
        g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );
        return 0;
    }
    

超初心者のプログラム入門(DirectX10 game program)