Crt Teapot

Create Teapot

DXUT を使わずに CreateTeapot() でティーポットを生成して描画します。

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

プロジェクトの説明

  1. 今回は Tutorial01 をベースにして、ティーポットを描画するスマートなプロジェクトを作成します。
    2014/09/15 次の環境で開発します。
        Windows8.1
        Visual Studio 2005
        November 2008
    
    メッシュを生成する関数は DXUTShapes.h(.cpp) で定義されています。
    所が DXUTShapes を組み込もうとすると DXUT 全体を組み込まなければなりません。
    そこで、その中からティーポットを生成する関数だけを抜き出してみました。
    DXUT を組み込んだプロジェクトからは、簡単にティーポットを生成することが出来ます。
    詳細は ティーポットを回転しながら描画する を参照して下さい。
  2. Sample Brower で Tutorial01(X10) を構築して空のウインドウの表示を確認して下さい。
    詳細は DirectX10 のインストール を参照して下さい。
    画面がすぐに消える(エラーで終了する)ときは InitDevice() 関数の次の行をコメントアウトします。
    //#ifdef _DEBUG
    //    createDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG;
    //#endif
    
  3. プロジェクトを身軽にします。
    以下のファイルを残して削除してから「コンパイル&実行」が出来ることを確かめて下さい。
      DXUT\
      directx.ico
      Resource.h
      Tutorial01.cpp
      Tutorial01.manifest
      Tutorial01.rc
      Tutorial01_2005.sln
      Tutorial01_2005.vcproj
    
  4. これから追加する Create Teapot に合わせて構造体を定義します。
    Tutorial01.cpp の #include の次に追加して下さい。
    #define SAFE_DELETE_ARRAY(p) { if (p) { delete[] (p);   (p)=NULL; } }
    struct VERTEX
    {
        D3DXVECTOR3 pos;
        D3DXVECTOR3 norm;
    };
    static const D3D10_INPUT_ELEMENT_DESC s_ShapeLayout[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
        { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 },
    };
    
  5. Global Variables に次のソースコードを追加します。
    //--------------------------------------------------------------------------------------
    // Global Variables
    //--------------------------------------------------------------------------------------
        ・・・
    ID3D10Effect*               g_pEffect = NULL;
    ID3D10EffectTechnique*      g_pRender = NULL;
    ID3D10InputLayout*          g_pLayout = NULL;
    ID3DX10Mesh*                g_pMesh = NULL;
    
    ID3D10EffectMatrixVariable* g_pWorldVariable = NULL;
    ID3D10EffectMatrixVariable* g_pViewVariable = NULL;
    ID3D10EffectMatrixVariable* g_pProjectionVariable = NULL;
    D3DXMATRIX                  g_World;
    D3DXMATRIX                  g_View;
    D3DXMATRIX                  g_Projection;
    
  6. Forward declarations で次の関数を宣言します。
    //--------------------------------------------------------------------------------------
    // Forward declarations
    //--------------------------------------------------------------------------------------
        ・・・
    HRESULT CreateShapeMesh( ID3D10Device* pDev10, ID3DX10Mesh** ppMesh, VERTEX* pVertices,
                UINT NumVertices, WORD* pIndices, UINT NumIndices );
    static void MakeTeapot( VERTEX* pVertices, WORD* pwIndices );
    HRESULT WINAPI DXUTCreateTeapot( ID3D10Device* pDevice, ID3DX10Mesh** ppMesh );
    
    この状態でコンパイルして、最初と同様に空のウインドウの表示を確認して下さい。
  7. DXUTShapes.cpp から Teapot を生成する関数を Tutorial01.cpp の最後に追加します。
    DXUTShapes.cpp は Sample Brower で構築した DXUT/Optional に格納されています。
    Tutorial の DXUT には格納されないので念のため。
    追加する関数は先に宣言した3個と Teapot のデータ定義です。
    HRESULT CreateShapeMesh( ID3D10Device* pDev10, ID3DX10Mesh** ppMesh, VERTEX* pVertices,
                UINT NumVertices, WORD* pIndices, UINT NumIndices )
    {
        ※D3DX10Mesh を生成する関数です。
    }
    
  8. Teapot のデータ定義は相当な行数です。
    // Teapot data
    #define NUMTEAPOTVERTICES 1178
    #define NUMTEAPOTINDICES 6768
    static float teapotPositionsFloats[NUMTEAPOTVERTICES*3] =
        {
            ※頂点座標の定義が続きます。
        }
    static D3DXVECTOR3* teapotPositions = ( D3DXVECTOR3* )teapotPositionsFloats;
    static float teapotNormalsfloats[NUMTEAPOTVERTICES*3] =
        {
            ※法線の定義が続きます。
        }
    static D3DXVECTOR3* teapotNormals = ( D3DXVECTOR3* )teapotNormalsfloats;
    static WORD teapotIndices[NUMTEAPOTINDICES] =
        {
           ※Index の定義が続きます。
        }
    
  9. 残りの2個の関数です。
    // MakeTeapot Helper
    static void MakeTeapot( VERTEX* pVertices, WORD* pwIndices ) 
    {
        ※Teapot を生成する Helper 関数です。
    }
    // DXUTCreateTeapot - createa  teapot mesh
    HRESULT WINAPI DXUTCreateTeapot( ID3D10Device* pDevice, ID3DX10Mesh** ppMesh )
    {
        ※Teapot を生成する関数です。
    }
    
    この状態でコンパイルして、最初と同様に空のウインドウの表示を確認して下さい。
  10. InitDevice() の最後に次のコードを追加します。
    "Ligth.fx" は「頂点座標と法線ベクトル」のモデルを描画するシェーダーです。
    DXUTCreateTeapot( g_pd3dDevice, &g_pMesh ) でティーポットを生成します。
        // Setup the viewport
        D3D10_VIEWPORT vp;
        vp.Width = width;
        vp.Height = height;
        vp.MinDepth = 0.0f;
        vp.MaxDepth = 1.0f;
        vp.TopLeftX = 0;
        vp.TopLeftY = 0;
        g_pd3dDevice->RSSetViewports( 1, &vp );
    
        // Create the effect
        DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS;
        hr = D3DX10CreateEffectFromFile( L"Ligth.fx", NULL, NULL, "fx_4_0", dwShaderFlags, 0,
                                         g_pd3dDevice, NULL, NULL, &g_pEffect, NULL, NULL );
        if( FAILED( hr ) )
        {
            MessageBox( NULL,
                        L"The FX file cannot be located.", L"Error", MB_OK );
            return hr;
        }
    
        // Obtain the technique
        g_pRender = g_pEffect->GetTechniqueByName( "Render" );
    
        // Obtain the variables
        g_pWorldVariable = g_pEffect->GetVariableByName( "World" )->AsMatrix();
        g_pViewVariable = g_pEffect->GetVariableByName( "View" )->AsMatrix();
        g_pProjectionVariable = g_pEffect->GetVariableByName( "Projection" )->AsMatrix();
        UINT numElements = sizeof(s_ShapeLayout)/sizeof(s_ShapeLayout[0]);
    
        // Create the input layout
        D3D10_PASS_DESC PassDesc;
        g_pRender->GetPassByIndex( 0 )->GetDesc( &PassDesc );
        hr = g_pd3dDevice->CreateInputLayout( s_ShapeLayout, numElements, PassDesc.pIAInputSignature,
                                              PassDesc.IAInputSignatureSize, &g_pLayout );
        if( FAILED( hr ) )
            return hr;
    
        // Set the input layout
        g_pd3dDevice->IASetInputLayout( g_pLayout );
    
        // Create Teapot
        DXUTCreateTeapot( g_pd3dDevice, &g_pMesh );
    
        // Initialize the world matrix
        D3DXMatrixIdentity( &g_World );
    
        // Initialize the view matrix
        D3DXVECTOR3 Eye( 0.0f, 2.0f, -6.0f );
        D3DXVECTOR3 At( 0.0f, 1.0f, 0.0f );
        D3DXVECTOR3 Up( 0.0f, 1.0f, 0.0f );
        D3DXMatrixLookAtLH( &g_View, &Eye, &At, &Up );
    
        // Initialize the projection matrix
        D3DXMatrixPerspectiveFovLH( &g_Projection, (float)D3DX_PI * 0.25f, width/(FLOAT)height, 0.1f, 100.0f );
    
        return S_OK;
    }
    
  11. Render() の後に次のコードを追加します。
        // Update variables
        g_pWorldVariable->SetMatrix( ( float* )&g_World );
        g_pViewVariable->SetMatrix( ( float* )&g_View );
        g_pProjectionVariable->SetMatrix( ( float* )&g_Projection );
    
        // Update variables
        g_pWorldVariable->SetMatrix( (float*)&g_World );
        g_pViewVariable->SetMatrix( (float*)&g_View );
        g_pProjectionVariable->SetMatrix( (float*)&g_Projection );
    
        D3D10_TECHNIQUE_DESC techDesc;
        g_pRender->GetDesc( &techDesc );
    
        UINT NumSubsets;
        g_pMesh->GetAttributeTable( NULL, &NumSubsets );
    
        g_pd3dDevice->IASetInputLayout( g_pLayout );
    
        for( UINT p = 0; p < techDesc.Passes; p++ )
        {
            g_pRender->GetPassByIndex( p )->Apply( 0 );
    
            for( UINT s = 0; s < NumSubsets; s++ )
            {   g_pMesh->DrawSubset( s );  }
        }
    
        g_pSwapChain->Present( 0, 0 );
    }
    
  12. CleanupDevice() の後に次のコードを追加します。
        if( g_pLayout ) g_pLayout->Release();
        if( g_pEffect ) g_pEffect->Release();
        if( g_pRenderTargetView ) g_pRenderTargetView->Release();
        if( g_pDepthStencil ) g_pDepthStencil->Release();
        if( g_pDepthStencilView ) g_pDepthStencilView->Release();
        if( g_pSwapChain ) g_pSwapChain->Release();
        if( g_pd3dDevice ) g_pd3dDevice->Release();
        if( g_pDXGIFactory ) g_pDXGIFactory->Release(); 
    
  13. Ligth.fx をプロジェクトのフォルダーに格納して下さい。
    シェーダーは「頂点座標と法線ベクトル」のモデルを光源で照らして描画するものを使って下さい。
    Ligth.fx は 立方体を光源で照らして描画する から取得出来ます。
    実行すると Teapot が静止状態で描画されます。

回転しながら描画する

  1. 立方体のような単純なモデルはカリング(陰面消去)の設定だけでOKですが、今回は深度ステンシルバッファを使ったレンダリングが必要です。
    ステンシルバッファの領域を定義します。
    ID3D10Texture2D*            g_pDepthStencil = NULL;
    ID3D10DepthStencilView*     g_pDepthStencilView = NULL;
    
  2. InitDevice() でステンシルバッファを生成します。
        // Create depth stencil texture
        D3D10_TEXTURE2D_DESC descDepth;
        descDepth.Width = width;
        descDepth.Height = height;
        descDepth.MipLevels = 1;
        descDepth.ArraySize = 1;
        descDepth.Format = DXGI_FORMAT_D32_FLOAT;
        descDepth.SampleDesc.Count = 1;
        descDepth.SampleDesc.Quality = 0;
        descDepth.Usage = D3D10_USAGE_DEFAULT;
        descDepth.BindFlags = D3D10_BIND_DEPTH_STENCIL;
        descDepth.CPUAccessFlags = 0;
        descDepth.MiscFlags = 0;
        hr = g_pd3dDevice->CreateTexture2D( &descDepth, NULL, &g_pDepthStencil );
        if( FAILED(hr) )
            return hr;
    
        // Create the depth stencil view
        D3D10_DEPTH_STENCIL_VIEW_DESC descDSV;
        descDSV.Format = descDepth.Format;
        descDSV.ViewDimension = D3D10_DSV_DIMENSION_TEXTURE2D;
        descDSV.Texture2D.MipSlice = 0;
        hr = g_pd3dDevice->CreateDepthStencilView( g_pDepthStencil, &descDSV, &g_pDepthStencilView );
        if( FAILED(hr) )
            return hr;
    
        g_pd3dDevice->OMSetRenderTargets( 1, &g_pRenderTargetView, g_pDepthStencilView );
    
  3. Render() の最初で GetTickCount() で時刻を取得して Teapot を回転します。
    back buffer のクリアに続いて StencilView をクリアします。
        // Update our time
        static float t = 0.0f;
        static DWORD dwTimeStart = 0;
        DWORD dwTimeCur = GetTickCount();
        if( dwTimeStart == 0 )
            dwTimeStart = dwTimeCur;
        t = ( dwTimeCur - dwTimeStart ) / 1000.0f;
    
        // Animate the cube
        D3DXMatrixRotationY( &g_World, t );
    
        // Clear the back buffer
        float ClearColor[4] = { 0.2f, 0.2f, 0.6f, 0.0f };
        g_pd3dDevice->ClearRenderTargetView( g_pRenderTargetView, ClearColor );
    
        // Clear the depth buffer to 1.0 (max depth)
        g_pd3dDevice->ClearDepthStencilView( g_pDepthStencilView, D3D10_CLEAR_DEPTH | D3D10_CLEAR_STENCIL, 1.0f, 0 );
    
  4. CleanupDevice() で Stencil をクリアします。
        if( g_pDepthStencil ) g_pDepthStencil->Release();
        if( g_pDepthStencilView ) g_pDepthStencilView->Release();
    
  5. 深度ステンシルバッファを設定して、ティーポットが回転しながら描画されます。
    さすがにティーポットを生成するとなると凄いデータ量ですね。 (^_^;)

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