Tiny.sdkmesh を描画する

DirectX10 のメッシュファイル(Tiny.sdkmesh)を描画します。
sdkmesh の描画には「DirectX10 対応 GPU(グラフィックボード)」が必要です。 (^_^;)

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

プロジェクトの設定

  1. いよいよ待望の DirectX10 のメッシュファイル(Tiny.sdkmesh)を描画します。
    今回はモデルを回転しながら描画するだけで、アニメーションは行いません。
    Tiny.x でアニメーションするプログラムは Tiny.x でアニメーション を参照して下さい。
    テンプレートのプロジェクトをフォルダーごとコピーして来て下さい。
    プロジェクトのフォルダー名を Tiny に変更して下さい。
    テンプレートの作成は Novmnber 2008 のテンプレート を参照して下さい。
  2. DXUT のフォルダーから次のソースファイルをプロジェクトに組み込んで下さい。
    テンプレートの DXUT に最初から組み込まれているファイルも併せて掲載しています。
    DXUT.cpp
    DXUT.h
    DXUTenum.cpp
    DXUTenum.h
    DXUTmisc.cpp
    DXUTmisc.h
    SDKmesh.cpp
    SDKmesh.h
    SDKmisc.cpp
    SDKmisc.h
  3. ヘッダーファイルのインクルードと #define です。
        #include "DXUT.h"
        #include "DXUTmisc.h"
        #include "SDKmisc.h"
        #include "SDKmesh.h"
        #define DEG2RAD( a ) ( a * D3DX_PI / 180.f )
        
  4. ライブラリを #pragma でリンクします。
    sdkmesh のロードには IDirect3DDevice9 が使われているようなので、"d3dx9.lib", "d3d9.lib" もリンクします。
        #pragma once
        #pragma comment(lib,"dxerr.lib")
        #pragma comment(lib,"dxguid.lib")
        #pragma comment(lib,"d3dx9.lib")
        #pragma comment(lib,"d3d9.lib")
        #pragma comment(lib,"winmm.lib")
        #pragma comment(lib,"comctl32.lib")
        #pragma comment(lib,"dxgi.lib")
        #pragma comment(lib,"d3d10.lib")
        #pragma comment(lib,"d3dx10.lib")
        
  5. Global Variables の定義です。
        ID3D10Effect*                       g_pEffect = NULL;
        ID3D10InputLayout*                  g_pVertexLayout = NULL;
        ID3D10EffectTechnique*              g_pTechnique = NULL;
        CDXUTSDKMesh                        g_Mesh;
        ID3D10EffectShaderResourceVariable* g_ptxDiffuseVariable = NULL;
        ID3D10EffectMatrixVariable*         g_pWorldVariable = NULL;
        ID3D10EffectMatrixVariable*         g_pViewVariable = NULL;
        ID3D10EffectMatrixVariable*         g_pProjectionVariable = NULL;
        D3DXMATRIX                          g_World;
        D3DXMATRIX                          g_View;
        D3DXMATRIX                          g_Projection;
        
  6. OnD3D9CreateDevice() 関数です。
    モデルにテクスチャを張り付けて描画する Shader("Main.fx") を使います。
    "Main.fx" のソースコードは、全ソースコードに掲載しています。
    L"c:\\DATA\\DirectX\\Media\\Tiny\\tiny.sdkmesh" が tiny.sdkmesh のモデルです。
    事前に c:\DATA\DirectX\Media\Tiny\(または適当なフォルダー)に格納しておいて下さい。
        HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice,
                           const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
        {
            HRESULT hr;
    
            // Find the D3DX effect file
            WCHAR str[MAX_PATH];
            V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"Main.fx" ) );
            DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS;
        #if defined( DEBUG ) || defined( _DEBUG )
            dwShaderFlags |= D3D10_SHADER_DEBUG;
        #endif
    
            V_RETURN( D3DX10CreateEffectFromFile( str, NULL, NULL, "fx_4_0", dwShaderFlags, 0, pd3dDevice, NULL,
                                                  NULL, &g_pEffect, NULL, NULL ) );
    
            // Obtain the technique
            g_pTechnique = g_pEffect->GetTechniqueByName( "Render" );
            g_ptxDiffuseVariable = g_pEffect->GetVariableByName( "g_txDiffuse" )->AsShaderResource();
            g_pWorldVariable = g_pEffect->GetVariableByName( "World" )->AsMatrix();
            g_pViewVariable = g_pEffect->GetVariableByName( "View" )->AsMatrix();
            g_pProjectionVariable = g_pEffect->GetVariableByName( "Projection" )->AsMatrix();
    
            // Define the input layout
            const D3D10_INPUT_ELEMENT_DESC layout[] =
            {
                { "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 },
                { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0 },
            };
            UINT numElements = sizeof( layout ) / sizeof( layout[0] );
    
            // Create the input layout
            D3D10_PASS_DESC PassDesc;
            g_pTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc );
            V_RETURN( pd3dDevice->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature,
                      PassDesc.IAInputSignatureSize, &g_pVertexLayout ) );
    
            // Set the input layout
            pd3dDevice->IASetInputLayout( g_pVertexLayout );
    
            // Load the mesh
            V_RETURN( g_Mesh.Create( pd3dDevice, L"c:\\DATA\\DirectX\\Media\\Tiny\\tiny.sdkmesh", true ) );
    
            // Initialize the world matrices
            D3DXMatrixIdentity( &g_World );
    
            // Initialize the view matrix
            D3DXVECTOR3 Eye( 0.0f, 3.0f, -500.0f );
            D3DXVECTOR3 At( 0.0f, 1.0f, 0.0f );
            D3DXVECTOR3 Up( 0.0f, 1.0f, 0.0f );
            D3DXMatrixLookAtLH( &g_View, &Eye, &At, &Up );
    
            // Update Variables that never change
            g_pViewVariable->SetMatrix( ( float* )&g_View );
    
            return S_OK;
        }
        
  7. OnD3D10FrameRender() 関数です。
    モデルを回転しながら描画します。
        void CALLBACK OnD3D10FrameRender( ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
        {
            // 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_World );
    
            // Set the Vertex Layout
            pd3dDevice->IASetInputLayout( g_pVertexLayout );
    
            // Render the mesh
            UINT Strides[1];
            UINT Offsets[1];
            ID3D10Buffer* pVB[1];
            pVB[0] = g_Mesh.GetVB10( 0, 0 );
            Strides[0] = ( UINT )g_Mesh.GetVertexStride( 0, 0 );
            Offsets[0] = 0;
            pd3dDevice->IASetVertexBuffers( 0, 1, pVB, Strides, Offsets );
            pd3dDevice->IASetIndexBuffer( g_Mesh.GetIB10( 0 ), g_Mesh.GetIBFormat10( 0 ), 0 );
    
            D3D10_TECHNIQUE_DESC techDesc;
            g_pTechnique->GetDesc( &techDesc );
            SDKMESH_SUBSET* pSubset = NULL;
            ID3D10ShaderResourceView* pDiffuseRV = NULL;
            D3D10_PRIMITIVE_TOPOLOGY PrimType;
    
            for( UINT p = 0; p < techDesc.Passes; ++p )
            {
                for( UINT subset = 0; subset < g_Mesh.GetNumSubsets( 0 ); ++subset )
                {
                    pSubset = g_Mesh.GetSubset( 0, subset );
    
                    PrimType = g_Mesh.GetPrimitiveType10( ( SDKMESH_PRIMITIVE_TYPE )pSubset->PrimitiveType );
                    pd3dDevice->IASetPrimitiveTopology( PrimType );
    
                    pDiffuseRV = g_Mesh.GetMaterial( pSubset->MaterialID )->pDiffuseRV10;
                    g_ptxDiffuseVariable->SetResource( pDiffuseRV );
    
                    g_pTechnique->GetPassByIndex( p )->Apply( 0 );
                    pd3dDevice->DrawIndexed( ( UINT )pSubset->IndexCount, 0, ( UINT )pSubset->VertexStart );
                }
            }
    
            //次の一行に置き換えることが出来るので試して下さい。
            //the mesh class also had a render method that allows rendering the mesh with the most common options
            //g_Mesh.Render( pd3dDevice, g_pTechnique, g_ptxDiffuseVariable );
    
        }
        
  8. OnFrameMove() でY軸を中心に回転します。
        void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext )
        {
            // Rotate cube around the origin
            D3DXMatrixRotationY( &g_World, 60.0f * DEG2RAD((float)fTime) );
        }
        
  9. Tiny.x の描画は 前田稔の超初心者のプログラム入門 から「DirectX9/Mesh を描画/X_file Object Class & Tiny.x」を参照して下さい。
    Java でも XFILE の Animation プログラムとファイルの形式を説明しています。
    超初心者のプログラム入門(Java)/Loader の作成 /XFILE Loader を参照して下さい。
    プログラムの詳細は、この後に掲載している「全ソースコード」を参照して下さい。

【NOTE】

Shader に引き渡すパラメータ(メモリ)の配置が、今ひとつ納得いきません。
現在主流となっているコンピュータのメモリは、バイト(8ビット)単位にアドレスが割り振られています。
メモリ上に格納するデータは、そのサイズによって境界(バウンダリ)調整がされます。
例えば、short(16ビット)型のデータは偶数の番地から、int(32ビット)型のデータは4で割り切れる番地から格納されます。
バウンダリ調整によりメモリ上に隙間が出来るのですが、通常ゼロでパディングされています。
Shader に渡すメモリの場合は「偶数個の float(4バイト)」に調整されているようなのですが、今回使った Main.fx を見る限りそうとは言い切れません。
グラフィックボードもバウンダリ調整があり、こちらは CPU よりも大きな値(64ビットなど)に設定されているようです。
メモリの配置は CPU とグラフィックボードのバウンダリ調整を考慮して割り振られているようです。

超初心者の方のために全ソースコードを提供します。 (^_^;)
全ソースコード

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

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