sdkmesh のアニメーション

SDK Mesh のアニメーションプログラムです。

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

プログラムの説明

  1. DXUT メッシュ形式(.sdkmesh) のアニメーションプログラムです。
    DirectX Sample Browser を起動すると、幾つかの sdkmesh animation のサンプルが格納されています。
    Install Project をクリックすると自動的にプロジェクトが構築され、そのまま実行することが出来ます。
    一覧から AdvancedParticles (Novenber 2007) を選んで実行してみて下さい。
    ドラゴンをアニメーションしながら、上からパーティクルが降り注ぎます。
    また MotionBlur10 (February 2006) を選んで実行してみて下さい。
    風車の回転を背景に、戦士のアニメーションです。
    サンプルプログラムを実行することは簡単なのですが、構成が複雑すぎてプログラムが理解不能です。
    そこで AdvancedParticles からドラゴンをアニメーションするソースコードだけを抜き出してみました。
  2. AdvancedParticles のプロジェクトフォルダーに AdvancedParticles.cpp を上書きして下さい。
    ドラゴンのアニメーションだけが描画されます。
    ファイル名 説明
    AdvancedParticles.zip AdvancedParticles.cpp 圧縮ファイル
  3. g_Camera がモデルを回転する CModelViewerCamera です。
    ドラゴンをマウスの操作で回転することが出来ます。
    g_pMeshEffect10 で "Meshes.fx" を制御します。
    g_pAnimVertexLayout は "lizardSIG.sdkmesh" の InputLayout です。
    MESH でメッシュをアニメーションする領域を構造体で定義します。
    MESH g_WorldMesh; がメッシュの定義です。
    // mesh fx から Shader にアクセスするためのポインタが定義されています。
    // Global variables
    CModelViewerCamera                  g_Camera;               // A model viewing camera
    
    ID3D10Effect*                       g_pMeshEffect10 = NULL;
    ID3D10InputLayout*                  g_pAnimVertexLayout = NULL;
    
    struct MESH
    {
        CDXUTSDKMesh Mesh;
        ID3D10Texture2D* pMeshPositionTexture;
        ID3D10ShaderResourceView* pMeshPositionRV;
        ID3D10RenderTargetView* pMeshPositionRTV;
    
        UINT MeshTextureWidth;
        UINT MeshTextureHeight;
        ID3D10Texture2D* pMeshTexture;
        ID3D10ShaderResourceView* pMeshRV;
        ID3D10RenderTargetView* pMeshRTV;
    
        D3DXMATRIX mWorld;
        D3DXMATRIX mWorldPrev;
    
        D3DXVECTOR3 vPosition;
        D3DXVECTOR3 vRotation;
    };
    
    MESH g_WorldMesh;
    
    // mesh fx
    ID3D10EffectTechnique*              g_pRenderAnimScene_Mesh;
    ID3D10EffectMatrixVariable*         g_pmWorldViewProj_Mesh;
    ID3D10EffectMatrixVariable*         g_pmViewProj_Mesh;
    ID3D10EffectMatrixVariable*         g_pmWorld_Mesh;
    ID3D10EffectMatrixVariable*         g_pmBoneWorld_Mesh;
    ID3D10EffectMatrixVariable*         g_pmBonePrev_Mesh;
    ID3D10EffectVectorVariable*         g_pvLightDir_Mesh;
    ID3D10EffectVectorVariable*         g_pvEyePt_Mesh;
    ID3D10EffectShaderResourceVariable* g_ptxDiffuse_Mesh;
    ID3D10EffectShaderResourceVariable* g_ptxNormal_Mesh;
    ID3D10EffectShaderResourceVariable* g_ptxSpecular_Mesh;
    ID3D10EffectShaderResourceVariable* g_ptxPaint_Mesh;
    
  4. OnD3D10CreateDevice() はデバイスを生成するときに呼ばれます。
    L"Meshes.fx" が lizardSIG.sdkmesh を描画するための Shader です。
    Shader はポインタの設定や input layout を見ても解るようにオーダーメイドで、X-FILE のように Mview で全て描画とはいかないようです。
    // Obtain the parameter handles for meshes fx から Shader のポインタを設定します。
    g_WorldMesh.Mesh.Create() で L"AdvancedParticles\\lizardSIG.sdkmesh" をロードします。
    g_WorldMesh.Mesh.LoadAnimation() で L"AdvancedParticles\\lizardSIG.sdkmesh_anim" をロードします。
    X-FILE と違い、メッシュのファイルとアニメーションデータは分かれているようです。
    // Create any D3D10 resources that aren't dependant on the back buffer
    HRESULT CALLBACK OnD3D10CreateDevice( ID3D10Device* pd3dDevice,
             const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
    {
        HRESULT hr;
    
        // Read the D3DX effect file
        WCHAR str[MAX_PATH];
        UINT uFlags = D3D10_SHADER_ENABLE_STRICTNESS | D3D10_SHADER_DEBUG;
    
        V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"Meshes.fx" ) );
        V_RETURN( D3DX10CreateEffectFromFile( str, NULL, NULL, "fx_4_0", uFlags, 0, pd3dDevice,
                NULL, NULL, &g_pMeshEffect10, NULL, NULL ) );
    
        // Obtain the technique handles for meshes fx
        g_pRenderAnimScene_Mesh = g_pMeshEffect10->GetTechniqueByName( "RenderAnimScene" );
        // Obtain the parameter handles for meshes fx
        g_pmWorldViewProj_Mesh = g_pMeshEffect10->GetVariableByName( "g_mWorldViewProj" )->AsMatrix();
        g_pmViewProj_Mesh = g_pMeshEffect10->GetVariableByName( "g_mViewProj" )->AsMatrix();
        g_pmWorld_Mesh = g_pMeshEffect10->GetVariableByName( "g_mWorld" )->AsMatrix();
        g_pmBoneWorld_Mesh = g_pMeshEffect10->GetVariableByName( "g_mBoneWorld" )->AsMatrix();
        g_pmBonePrev_Mesh = g_pMeshEffect10->GetVariableByName( "g_mBonePrev" )->AsMatrix();
        g_pvLightDir_Mesh = g_pMeshEffect10->GetVariableByName( "g_vLightDir" )->AsVector();
        g_pvEyePt_Mesh = g_pMeshEffect10->GetVariableByName( "g_vEyePt" )->AsVector();
        g_ptxDiffuse_Mesh = g_pMeshEffect10->GetVariableByName( "g_txDiffuse" )->AsShaderResource();
        g_ptxNormal_Mesh = g_pMeshEffect10->GetVariableByName( "g_txNormal" )->AsShaderResource();
        g_ptxSpecular_Mesh = g_pMeshEffect10->GetVariableByName( "g_txSpecular" )->AsShaderResource();
        g_ptxPaint_Mesh = g_pMeshEffect10->GetVariableByName( "g_txPaint" )->AsShaderResource();
    
        D3D10_PASS_DESC PassDesc;
        // Create our vertex input layout for meshes
        const D3D10_INPUT_ELEMENT_DESC skinnedlayout[] =
        {
            { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,  D3D10_INPUT_PER_VERTEX_DATA, 0 },
            { "WEIGHTS",  0, DXGI_FORMAT_R8G8B8A8_UNORM,  0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 },
            { "BONES",    0, DXGI_FORMAT_R8G8B8A8_UINT,   0, 16, D3D10_INPUT_PER_VERTEX_DATA, 0 },
            { "NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 20, D3D10_INPUT_PER_VERTEX_DATA, 0 },
            { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 32, D3D10_INPUT_PER_VERTEX_DATA, 0 },
            { "TANGENT",  0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 40, D3D10_INPUT_PER_VERTEX_DATA, 0 },
        };
        g_pRenderAnimScene_Mesh->GetPassByIndex( 0 )->GetDesc( &PassDesc );
        V_RETURN( pd3dDevice->CreateInputLayout( skinnedlayout, sizeof( skinnedlayout ) / sizeof( skinnedlayout[0] ),
                PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &g_pAnimVertexLayout ) );
    
        // Load meshes(ドラゴンメシュ&アニメ)
        V_RETURN( g_WorldMesh.Mesh.Create( pd3dDevice, L"AdvancedParticles\\lizardSIG.sdkmesh" ) );
        V_RETURN( g_WorldMesh.Mesh.LoadAnimation( L"AdvancedParticles\\lizardSIG.sdkmesh_anim" ) );
    
        D3DXMATRIX mIdentity;
        D3DXMatrixIdentity( &mIdentity );
        g_WorldMesh.Mesh.TransformBindPose( &mIdentity );
    
        // Setup the camera's view parameters
        D3DXVECTOR3 vecEye( 0.0f, 0.6f, -5.0f );
        D3DXVECTOR3 vecAt ( 0.0f, 0.6f, 0.0f );
        g_Camera.SetViewParams( &vecEye, &vecAt );
    
        return S_OK;
    }
    
  5. レンダリングで呼ばれる OnD3D10FrameRender() 関数です。
    g_WorldMesh の X,Y,Z を掛け合わせて回転座標を求めます。
    メッシュの描画は RenderAnimatedMeshes() で行っています。
    void CALLBACK OnD3D10FrameRender( ID3D10Device* pd3dDevice, double fTime,
            float fElapsedTime, void* pUserContext )
    {
        float ClearColor[4] = { 0.00f, 0.08f, 0.07f, 0.0f };
    
        // calc world matrix for dynamic object
        D3DXMATRIX mScale;
        D3DXMATRIX mRotX, mRotY, mRotZ;
        D3DXMATRIX mTrans;
    
        D3DXMatrixScaling( &mScale, 0.2f, 0.2f, 0.2f );
        D3DXMatrixRotationX( &mRotX, g_WorldMesh.vRotation.x );
        D3DXMatrixRotationY( &mRotY, g_WorldMesh.vRotation.y );
        D3DXMatrixRotationZ( &mRotZ, g_WorldMesh.vRotation.z );
        D3DXMatrixTranslation( &mTrans, g_WorldMesh.vPosition.x, g_WorldMesh.vPosition.y,
                               g_WorldMesh.vPosition.z );
        g_WorldMesh.mWorld = mScale * mRotX * mRotY * mRotZ * mTrans;
    
        ID3D10RenderTargetView* pRTV = DXUTGetD3D10RenderTargetView();
        pd3dDevice->ClearRenderTargetView( pRTV, ClearColor );
        ID3D10DepthStencilView* pDSV = DXUTGetD3D10DepthStencilView();
        pd3dDevice->ClearDepthStencilView( pDSV, D3D10_CLEAR_DEPTH, 1.0, 0 );
    
        D3DXMATRIX mView;
        D3DXMATRIX mProj;
    
        // Get the projection & view matrix from the camera class
        mProj = *g_Camera.GetProjMatrix();
        mView = *g_Camera.GetViewMatrix();
    
        // Render scene meshes
        RenderAnimatedMeshes( pd3dDevice, mView, mProj, g_pRenderAnimScene_Mesh, fTime, fElapsedTime, false );
    }
    
  6. メッシュを描画する RenderAnimatedMeshes() 関数です。
    回転座標を計算して、WorldViewProj, ViewProj, WorldMesh を設定します。
    Light と Eye を設定します。
    実際に描画するのは pMesh->Render() 関数です。
    // ドラゴンをアニメーションしながら描画
    bool RenderAnimatedMeshes( ID3D10Device* pd3dDevice, D3DXMATRIX& mView, D3DXMATRIX& mProj,
            ID3D10EffectTechnique* pTechnique, double fTime, float fElapsedTime, bool bVolume )
    {
        // Set the Vertex Layout
        pd3dDevice->IASetInputLayout( g_pAnimVertexLayout );
    
        D3DXMATRIX mWorldViewProj;
        D3DXMATRIX mViewProj;
        mWorldViewProj = g_WorldMesh.mWorld * mView * mProj;
        mViewProj = mView * mProj;
    
        CDXUTSDKMesh* pMesh = &g_WorldMesh.Mesh;
    
        g_pmWorldViewProj_Mesh->SetMatrix( ( float* )&mWorldViewProj );
        g_pmViewProj_Mesh->SetMatrix( ( float* )&mViewProj );
        g_pmWorld_Mesh->SetMatrix( ( float* )&g_WorldMesh.mWorld );
        D3DXVECTOR4 vLightDir( 0,1,0,0 );
        g_pvLightDir_Mesh->SetFloatVector( ( float* )&vLightDir );
        D3DXVECTOR4 vEye = D3DXVECTOR4( *g_Camera.GetEyePt(), 1 );
        g_pvEyePt_Mesh->SetFloatVector( ( float* )&vEye );
    
        UINT NumInfluences = pMesh->GetNumInfluences( 0 );
        if( NumInfluences > 0 )
        {
            // Transform current position
            pMesh->TransformMesh( &g_WorldMesh.mWorld, fTime );
            for( UINT g = 0; g < NumInfluences; g++ )
            {
                const D3DXMATRIX* pMat = pMesh->GetMeshInfluenceMatrix( 0, g );
                g_pmBoneWorld_Mesh->SetMatrixArray( ( float* )pMat, g, 1 );
            }
    
            // Transform previous position
            pMesh->TransformMesh( &g_WorldMesh.mWorldPrev, fTime - fElapsedTime );
            for( UINT g = 0; g < NumInfluences; g++ )
            {
                const D3DXMATRIX* pMat = pMesh->GetMeshInfluenceMatrix( 0, g );
                g_pmBonePrev_Mesh->SetMatrixArray( ( float* )pMat, g, 1 );
            }
        }
    
        g_ptxPaint_Mesh->SetResource( g_WorldMesh.pMeshRV );
        pMesh->Render( pd3dDevice, pTechnique, g_ptxDiffuse_Mesh, g_ptxNormal_Mesh, g_ptxSpecular_Mesh );
    
        return true;
    }
    
  7. OnD3D10SwapChainResized() では、縦横比を計算して g_Camera.SetProjParams() を設定します。
    次に g_Camera を使ってモデルとカメラをマウスで回転します。
    マウスで回転するプログラムは結構面倒なのですが、g_Camera を使うと g_Camera.SetWindow() を呼び出すだけです。
    マウスの左ドラッグでモデルが回転し、右ドラッグでカメラが回転します。
    HRESULT CALLBACK OnD3D10SwapChainResized( ID3D10Device* pd3dDevice, IDXGISwapChain* pSwapChain,
            const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
    {
        HRESULT hr = S_OK;
    
        // Setup the camera's projection parameters
        float fAspectRatio = pBackBufferSurfaceDesc->Width / ( FLOAT )pBackBufferSurfaceDesc->Height;
        g_Camera.SetProjParams( D3DX_PI / 4, fAspectRatio, 0.1f, 5000.0f );
        g_Camera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
        g_Camera.SetButtonMasks( 0, MOUSE_WHEEL, MOUSE_LEFT_BUTTON | MOUSE_MIDDLE_BUTTON | MOUSE_RIGHT_BUTTON );
    
        return hr;
    }
    

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