スキンメッシュアニメーション

DirectXの最初の難関、スキンメッシュアニメーション。
学習方法は人それぞれですがSDKサンプルのSkinnedMesh.cppからヘルパーライブラリDXUTの関数を外していく
方向でソースファイルを短くすると解りやすいかも知れません。

SkinnedMesh.cpp

//--------------------------------------------------------------------------------------
//スキンメッシュアニメーション
//--------------------------------------------------------------------------------------
#include "d3dx9.h"
#include "SkinnedMesh.h"
LPDIRECT3D9             g_pD3D       = NULL;//Direct3D9
LPDIRECT3DDEVICE9       pd3dDevice = NULL;//レンダリングデバイス


HWND hWnd;
#define MESHFILENAME L"soldier.x"

float timef=0.0f;

HRESULT Init()
{
    //Direct3Dを生成する
 if(NULL==(g_pD3D=Direct3DCreate9(D3D_SDK_VERSION))){return E_FAIL;}

    //デバイス生成用のパラメーター
    D3DPRESENT_PARAMETERS d3dpp;//パラメーター構造体
    ZeroMemory( &d3dpp, sizeof(d3dpp) );//ゼロで初期化
    d3dpp.Windowed = TRUE;//ウインドウモードで起動
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;//バックバッファのスワップエフェクト Direct3Dにスワップエフェクトをまかせる
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;//バックバッファのフォーマット今表示されているモニタの設定と同じ
    d3dpp.BackBufferCount = 1;//バックバッファの数
    d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;//マルチサンプリングは行わない
    d3dpp.MultiSampleQuality = 0;//マルチサンプリングは行わないので0
    d3dpp.EnableAutoDepthStencil = TRUE;//Direct3Dに深度バッファの管理をまかせる
    d3dpp.AutoDepthStencilFormat = D3DFMT_D16;//深度バッファのフォーマット(通常はこの値で問題ない)
    d3dpp.hDeviceWindow = hWnd;//カバーウィンドウ=アプリケーションのウィンドウ
    d3dpp.Flags = 0;//フラグは使わない
    d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;//今のリフレッシュレートをそのまま使う
    d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;//モニタの垂直回帰を待つ

    //Direct3Dデバイスの生成 HAL(ハードウェアアクセラレーション)
    if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice))){
  //HALが駄目ならHEL(ソフトウェアエミュレーション)
        if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice))){
   //駄目なら終了
   return(E_FAIL);
        }
    }
 // Zバッファー処理を有効にする
    pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
 // ライトを有効にする
 pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
 // アンビエントライト(環境光)を設定する
 pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x00111111 );
 // スペキュラ(鏡面反射)を有効にする
 pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE,TRUE);

    CAllocateHierarchy Alloc;

    //シェーダーファイル読み込み

 D3DXCreateEffectFromFileW( pd3dDevice, L"SkinnedMesh.fx", NULL, NULL, D3DXSHADER_DEBUG,NULL, &g_pEffect, NULL );
    //メッシュ読み込み
 //WCHAR str[MAX_PATH];
 //MtoW(str,MESHFILENAME,MAX_PATH);

 D3DXLoadMeshHierarchyFromXW( MESHFILENAME, D3DXMESH_MANAGED, pd3dDevice,&Alloc, NULL, &g_pFrameRoot, &g_pAnimController );
 SetupBoneMatrixPointers( g_pFrameRoot );
 D3DXFrameCalculateBoundingSphere( g_pFrameRoot, &g_vObjectCenter, &g_fObjectRadius );

    //ビヘイビアフラグを得てください
    D3DDEVICE_CREATION_PARAMETERS cp;
    pd3dDevice->GetCreationParameters( &cp );
    g_dwBehaviorFlags = cp.BehaviorFlags;

    //セットアップ レンダーステート
    pd3dDevice->SetRenderState( D3DRS_LIGHTING,         TRUE );
    pd3dDevice->SetRenderState( D3DRS_DITHERENABLE,     TRUE );
    pd3dDevice->SetRenderState( D3DRS_ZENABLE,          TRUE );
    pd3dDevice->SetRenderState( D3DRS_CULLMODE,         D3DCULL_CCW );
    pd3dDevice->SetRenderState( D3DRS_AMBIENT,          0x33333333 );
    pd3dDevice->SetRenderState( D3DRS_NORMALIZENORMALS, TRUE );
    pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
    pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );


    for( DWORD iInfl = 0; iInfl < 4; ++iInfl )
    {
        LPD3DXBUFFER pCode;

        //頂点シェーダーアセンブル
        D3DXAssembleShaderFromFileW( ShaderSource[iInfl], NULL, NULL, D3DXSHADER_DEBUG, &pCode, NULL );

        //頂点シェーダー生成
        pd3dDevice->CreateVertexShader( (DWORD*)pCode->GetBufferPointer(),&g_pIndexedVertexShader[iInfl] );

        pCode->Release();
    }

    //セットアップ プロジェクションマトリックス
 float fAspect = (float)640.0f / (float)480.0f;
    D3DXMatrixPerspectiveFovLH( &g_matProj, D3DX_PI/4, fAspect,
                                g_fObjectRadius/64.0f, g_fObjectRadius*200.0f );
    pd3dDevice->SetTransform( D3DTS_PROJECTION, &g_matProj );
    D3DXMatrixTranspose( &g_matProjT, &g_matProj );
 return true;
}

void MainLoop()
{

    HRESULT hr;

    //バックバッファ
    pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
                         D3DCOLOR_ARGB(0, 255, 255, 255), 1.0f, 0L );

     //セットアップ ワールドマトリクス
    D3DXMATRIXA16 matWorld;
    D3DXMatrixTranslation( &matWorld, -g_vObjectCenter.x,
                                      -g_vObjectCenter.y,
                                      -g_vObjectCenter.z );
    pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );

    D3DXVECTOR3 vEye( 150, 10, -2*g_fObjectRadius );
    D3DXVECTOR3 vAt( 0, 10, 0 );
    D3DXVECTOR3 vUp( 0, 1, 0 );
    D3DXMatrixLookAtLH( &g_matView, &vEye, &vAt, &vUp);

    pd3dDevice->SetTransform( D3DTS_VIEW,  &g_matView );

    if( g_pAnimController != NULL )
        g_pAnimController->AdvanceTime( 0.03f, NULL );

    UpdateFrameMatrices( g_pFrameRoot, &matWorld );

    //ライトセットアップ
    D3DLIGHT9 light;
    D3DXVECTOR3 vecLightDirUnnormalized(0.0f, -1.0f, 1.0f);
    ZeroMemory( &light, sizeof(D3DLIGHT9) );
    light.Type        = D3DLIGHT_DIRECTIONAL;
    light.Diffuse.r   = 1.0f;
    light.Diffuse.g   = 1.0f;
    light.Diffuse.b   = 1.0f;
    D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &vecLightDirUnnormalized );
    light.Position.x   = 0.0f;
    light.Position.y   = -1.0f;
    light.Position.z   = 1.0f;
    light.Range        = 1000.0f;
    V( pd3dDevice->SetLight(0, &light ) );
    V( pd3dDevice->LightEnable(0, TRUE ) );

    //プロジェクションセット
    if( g_SkinningMethod == D3DINDEXEDVS )
    {
        V( pd3dDevice->SetVertexShaderConstantF( 2, (float*)&g_matProjT, 4 ) );
    }
    else
    if( g_SkinningMethod == D3DINDEXEDHLSLVS )
    {
        V( g_pEffect->SetMatrix( "mViewProj", &g_matProj ) );
    }

    //セットライト
    D3DXVECTOR4 vLightDir( 0.0f, 1.0f, -1.0f, 0.0f );
    D3DXVec4Normalize( &vLightDir, &vLightDir );
    V( pd3dDevice->SetVertexShaderConstantF(1, (float*)&vLightDir, 1) );
    V( g_pEffect->SetVector( "lhtDir", &vLightDir) );

    //ビギンシーン
    if( SUCCEEDED( pd3dDevice->BeginScene() ) )
    {
        DrawFrame( pd3dDevice, g_pFrameRoot );

        //シーンエンド
        pd3dDevice->EndScene();
    }
 pd3dDevice->Present( NULL, NULL, NULL, NULL );
 Sleep(10);
}

//メッセージプロシージャ
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch( msg )
    {
        case WM_DESTROY://終了時
            PostQuitMessage(0);
            return 0;
        case WM_PAINT://ウインドウ描画時
   MainLoop();
            return 0;
  case WM_SIZE://ウインドウサイズ変更時
   InvalidateRect(hWnd,NULL,true);//画面更新
   return 0;
    }

    return DefWindowProc( hWnd, msg, wParam, lParam );
}
//--------------------------------------------------------------------------------------
//メイン
//--------------------------------------------------------------------------------------
INT WINAPI wWinMain( HINSTANCE, HINSTANCE, LPWSTR, int )
{
 //ウインドウクラスの登録
    WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
                      GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
                      "Window1", NULL };
    RegisterClassEx( &wc );

 //タイトルバーとウインドウ枠の分を含めてウインドウサイズを設定
 RECT rect;
 SetRect(&rect,0,0,640,480);
 AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
 rect.right=rect.right-rect.left;
 rect.bottom=rect.bottom-rect.top;
 rect.top=0;
 rect.left=0;

    //ウインドウの生成
    hWnd = CreateWindow( "Window1", "Hello DirectX9 World !!",
    WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, rect.right, rect.bottom,
                              NULL, NULL, wc.hInstance, NULL );

 Init();
 //頂点シェーダー解放
    for( DWORD iInfl = 0; iInfl < 4; ++iInfl )
        SAFE_RELEASE( g_pIndexedVertexShader[iInfl] );

 ShowWindow(hWnd,SW_SHOWDEFAULT);
        UpdateWindow(hWnd);

        //メッセージループ
        MSG msg;
        while( GetMessage(&msg,NULL,0,0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }


 UnregisterClass("Window1",wc.hInstance);

    ReleaseAttributeTable( g_pFrameRoot );
    delete[] g_pBoneMatrices;

 SAFE_RELEASE( g_pEffect );

    CAllocateHierarchy Alloc;
    D3DXFrameDestroy( g_pFrameRoot, &Alloc );
    SAFE_RELEASE( g_pAnimController );
    return 0;
}

 

SkinnedMesh.h

#define V(x)           { hr = (x); }
#define SAFE_DELETE_ARRAY(p) { if (p) { delete[] (p);   (p)=NULL; } }
#define SAFE_DELETE(p)       { if (p) { delete (p);     (p)=NULL; } }
#define SAFE_RELEASE(p)  {if(p){(p)->Release();(p)=NULL;}}//安全に解放する

// 様々なスキニングモードを可能にするための列挙
enum METHOD
{
    D3DNONINDEXED,//ノンインデックス
    D3DINDEXED,//インデックス
    SOFTWARE,//ソフトウェア
    D3DINDEXEDVS,//インデックスVS
    D3DINDEXEDHLSLVS,//インデックスHLSLVS
    NONE//スキニング無し
};

//フレーム構造体
struct D3DXFRAME_DERIVED: public D3DXFRAME
{
    D3DXMATRIXA16        CombinedTransformationMatrix;
};

//メッシュコンテナ構造体
struct D3DXMESHCONTAINER_DERIVED: public D3DXMESHCONTAINER
{
    LPDIRECT3DTEXTURE9*  ppTextures;//テクスチャーの配列、テクスチャーがなかったらNULL   
                               
    //スキンメッシュ情報           
    LPD3DXMESH           pOrigMesh;//メッシュ
    LPD3DXATTRIBUTERANGE pAttributeTable;//属性
    DWORD                NumAttributeGroups;//属性のグループ
    DWORD                NumInfl;
    LPD3DXBUFFER         pBoneCombinationBuf;//ボーンの組み合わせバッファ
    D3DXMATRIX**         ppBoneMatrixPtrs;//ボーンマトリクスポインタ
    D3DXMATRIX*          pBoneOffsetMatrices;//ボーンオフセットマトリクス
    DWORD                NumPaletteEntries;//パレットエントリー
    bool                 UseSoftwareVP;//ソフトウェアVPを使う
    DWORD                iAttributeSW;//ノンインデックススキニングならソフトウェアとハードウェアで分けて指定する必要がある
};

//階層割り当てクラス
class CAllocateHierarchy: public ID3DXAllocateHierarchy
{
public:
    STDMETHOD(CreateFrame)(THIS_ LPCSTR Name, LPD3DXFRAME *ppNewFrame);//フレーム作成
    STDMETHOD(CreateMeshContainer)(THIS_ //メッシュコンテナ作成
        LPCSTR Name, //名前
        CONST D3DXMESHDATA *pMeshData,//メッシュデータ
        CONST D3DXMATERIAL *pMaterials, //マテリアル
        CONST D3DXEFFECTINSTANCE *pEffectInstances, //エフェクトの実体
        DWORD NumMaterials, //マテリアル数
        CONST DWORD *pAdjacency, //隣接関係
        LPD3DXSKININFO pSkinInfo, //スキン情報
        LPD3DXMESHCONTAINER *ppNewMeshContainer);//メッシュコンテナのポインタ
    STDMETHOD(DestroyFrame)(THIS_ LPD3DXFRAME pFrameToFree);//フレーム削除
    STDMETHOD(DestroyMeshContainer)(THIS_ LPD3DXMESHCONTAINER pMeshContainerBase);//メッシュコンテナ削除

    CAllocateHierarchy() {}
};

WCHAR ShaderSource[4][30] =
{
    L"skinmesh1.vsh",
    L"skinmesh2.vsh",
    L"skinmesh3.vsh",
    L"skinmesh4.vsh"
};


//グローバル変数
ID3DXEffect*            g_pEffect = NULL;       //エフェクトインターフェース
LPD3DXFRAME             g_pFrameRoot = NULL; //フレームルート
ID3DXAnimationController* g_pAnimController = NULL;//アニメーションコントローラー
D3DXVECTOR3             g_vObjectCenter;        //オブジェクトのバウンディングスフィアの中心
FLOAT                   g_fObjectRadius;        //オブジェクトのバウンディングスフィアの半径
METHOD                  g_SkinningMethod = D3DNONINDEXED; //現在のスキニングメソッド、ノンインデックス
D3DXMATRIXA16*          g_pBoneMatrices = NULL;//ボーンマトリックス
UINT                    g_NumBoneMatricesMax = 0;//ボーンマトリックスの最大数
IDirect3DVertexShader9* g_pIndexedVertexShader[4];//頂点シェーダー
D3DXMATRIXA16           g_matView;              //ビュー行列
D3DXMATRIXA16           g_matProj;              //プロジェクション行列
D3DXMATRIXA16           g_matProjT;             //asmシェーダー用
DWORD                   g_dwBehaviorFlags;      //ビヘイビアフラグ
bool                    g_bUseSoftwareVP;       //ソフトウェアVPフラグ、ハードウェアが無かった時のために必要

HRESULT LoadMesh( IDirect3DDevice9* pd3dDevice, WCHAR* strFileName, ID3DXMesh** ppMesh );//メッシュロード
void    DrawMeshContainer( IDirect3DDevice9 *pd3dDevice, LPD3DXMESHCONTAINER pMeshContainerBase, LPD3DXFRAME pFrameBase );//メッシュコンテナー描画
void    DrawFrame( IDirect3DDevice9 *pd3dDevice, LPD3DXFRAME pFrame );//フレーム描画
HRESULT SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER pMeshContainer );//メッシュコンテナのボーンマトリクスポインター
HRESULT SetupBoneMatrixPointers( LPD3DXFRAME pFrame );//フレームのボーンマトリクスポインター
void    UpdateFrameMatrices( LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix );//フレームマトリクスの更新
void    UpdateSkinningMethod( IDirect3DDevice9 *pd3dDevice,LPD3DXFRAME pFrameBase );//スキニングメソッドの更新
HRESULT GenerateSkinnedMesh( IDirect3DDevice9 *pd3dDevice, D3DXMESHCONTAINER_DERIVED *pMeshContainer );//スキニングメッシュの生成
void    ReleaseAttributeTable( LPD3DXFRAME pFrameBase );//アトリビュートテーブルの解放

void MtoW(WCHAR * lpuni, LPSTR lpsjis, int buffersize)
{
 int len = MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,lpsjis,-1,NULL,0);

 if (buffersize) {
  //必要な文字数がバッファサイズより大きい場合はバッファイサイズ分を返還
  if (len > buffersize-1) len = buffersize-1;
 }

 MultiByteToWideChar(
  CP_ACP,   // ANSI Code Page (MBCS/マルチバイト文字)
  MB_PRECOMPOSED, // 既定変換方法
  lpsjis,   // 変換元文字列
  -1,    // 変換元文字列サイズ(-1指定で自動計算)(pInはゼロ終端であること)
  lpuni,   // 変換先バッファ
  len);  // 変換先バッファサイズ
}

//--------------------------------------------------------------------------------------
//割り当て名:フレームかメッシュ
//--------------------------------------------------------------------------------------
HRESULT AllocateName( LPCSTR Name, LPSTR *pNewName )
{
    UINT cbLength;

    if( Name != NULL )//名前が存在するなら
    {
        cbLength = (UINT)strlen(Name) + 1;//名前の文字数+1
        *pNewName = new CHAR[cbLength];//名前用メモリ確保
        if (*pNewName == NULL)//確保できなかったら
            return E_OUTOFMEMORY;//エラー
        memcpy( *pNewName, Name, cbLength*sizeof(CHAR) );//Nameをコピー
    }
    else//名前が存在しなかったらNULL
    {
        *pNewName = NULL;
    }

    return S_OK;
}

 


//--------------------------------------------------------------------------------------
//階層割り当て:フレーム作成
//--------------------------------------------------------------------------------------
HRESULT CAllocateHierarchy::CreateFrame( LPCSTR Name, LPD3DXFRAME *ppNewFrame )
{
    HRESULT hr = S_OK;
    D3DXFRAME_DERIVED *pFrame;//フレーム

    *ppNewFrame = NULL;

    pFrame = new D3DXFRAME_DERIVED;
    if (pFrame == NULL)//フレームが作成できなかったら
    {
        hr = E_OUTOFMEMORY;
        goto e_Exit;
    }

    hr = AllocateName(Name, &pFrame->Name);//割り当て名を設定
    if (FAILED(hr))
        goto e_Exit;

    //フレームの部品を初期化
    D3DXMatrixIdentity(&pFrame->TransformationMatrix);
    D3DXMatrixIdentity(&pFrame->CombinedTransformationMatrix);

    pFrame->pMeshContainer = NULL;
    pFrame->pFrameSibling = NULL;
    pFrame->pFrameFirstChild = NULL;

    *ppNewFrame = pFrame;
    pFrame = NULL;

e_Exit:
    delete pFrame;
    return hr;
}

 


//--------------------------------------------------------------------------------------
//メッシュコンテナ作成
//--------------------------------------------------------------------------------------
HRESULT CAllocateHierarchy::CreateMeshContainer(
    LPCSTR Name,//名前
    CONST D3DXMESHDATA *pMeshData,//メッシュデータ
    CONST D3DXMATERIAL *pMaterials,//マテリアル
    CONST D3DXEFFECTINSTANCE *pEffectInstances,//エフェクトの実体
    DWORD NumMaterials,//マテリアル数
    CONST DWORD *pAdjacency,//隣接関係
    LPD3DXSKININFO pSkinInfo,//スキン情報
    LPD3DXMESHCONTAINER *ppNewMeshContainer)//メッシュコンテナのポインタ
{
    HRESULT hr;
    D3DXMESHCONTAINER_DERIVED *pMeshContainer = NULL;
    UINT NumFaces;//面の数
    UINT iMaterial;//マテリアルの数
    UINT iBone, cBones;//ボーンの数
    LPDIRECT3DDEVICE9 pd3dDevice = NULL;

    LPD3DXMESH pMesh = NULL;

    *ppNewMeshContainer = NULL;

    //パッチメッシュは扱えないので見つかったら終了
    if (pMeshData->Type != D3DXMESHTYPE_MESH)
    {
        hr = E_FAIL;
        goto e_Exit;
    }

    // メッシュポインタをメッシュデータ構造体から得る
    pMesh = pMeshData->pMesh;

    //FVFコンパチブルメッシュは扱えないので見つかったら終了
    if (pMesh->GetFVF() == 0)
    {
        hr = E_FAIL;
        goto e_Exit;
    }

    //D3DXMESHCONTAINERとしてリターンするためにオーバーロード状態の構造体を設定する
    pMeshContainer = new D3DXMESHCONTAINER_DERIVED;
    if (pMeshContainer == NULL)
    {
        hr = E_OUTOFMEMORY;
        goto e_Exit;
    }
    memset(pMeshContainer, 0, sizeof(D3DXMESHCONTAINER_DERIVED));

    //名前を設定する
    hr = AllocateName(Name, &pMeshContainer->Name);
    if (FAILED(hr))
        goto e_Exit;       

    pMesh->GetDevice(&pd3dDevice);
    NumFaces = pMesh->GetNumFaces();

    //法線がメッシュにないなら、法線を設定する
    if (!(pMesh->GetFVF() & D3DFVF_NORMAL))
    {
        pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;

        //メッシュのクローンを作って法線の場所を空ける
        hr = pMesh->CloneMeshFVF( pMesh->GetOptions(),
                                    pMesh->GetFVF() | D3DFVF_NORMAL,
                                    pd3dDevice, &pMeshContainer->MeshData.pMesh );
        if (FAILED(hr))
            goto e_Exit;

        //使用するメッシュコンテナからメッシュポインタを取り戻す
        //注意:それの参照がまだないので解放はしない
        pMesh = pMeshContainer->MeshData.pMesh;

        //メッシュポインタに法線を作る
        D3DXComputeNormals( pMesh, NULL );
    }
    else  //法線が無ければ、ただメッシュにメッシュコンテナの参照をセットする
    {
        pMeshContainer->MeshData.pMesh = pMesh;
        pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;

        pMesh->AddRef();
    }
       
    //メモリを割り当てマテリアル情報を設定する
    //シェーダーの代わりにD3D9のマテリアルとテクスチャ
    pMeshContainer->NumMaterials = max(1, NumMaterials);
    pMeshContainer->pMaterials = new D3DXMATERIAL[pMeshContainer->NumMaterials];
    pMeshContainer->ppTextures = new LPDIRECT3DTEXTURE9[pMeshContainer->NumMaterials];
    pMeshContainer->pAdjacency = new DWORD[NumFaces*3];
    if ((pMeshContainer->pAdjacency == NULL) || (pMeshContainer->pMaterials == NULL))
    {
        hr = E_OUTOFMEMORY;
        goto e_Exit;
    }

    memcpy(pMeshContainer->pAdjacency, pAdjacency, sizeof(DWORD) * NumFaces*3);
    memset(pMeshContainer->ppTextures, 0, sizeof(LPDIRECT3DTEXTURE9) * pMeshContainer->NumMaterials);

    //マテリアルが設定されたらそれをコピーする
    if (NumMaterials > 0)           
    {
        memcpy(pMeshContainer->pMaterials, pMaterials, sizeof(D3DXMATERIAL) * NumMaterials);

        for (iMaterial = 0; iMaterial < NumMaterials; iMaterial++)
        {
            if (pMeshContainer->pMaterials[iMaterial].pTextureFilename != NULL)
            {
                WCHAR str[MAX_PATH];
    
                MtoW( str,pMeshContainer->pMaterials[iMaterial].pTextureFilename, MAX_PATH );
                if( FAILED( D3DXCreateTextureFromFileW( pd3dDevice, str,
                                                        &pMeshContainer->ppTextures[iMaterial] ) ) )
                    pMeshContainer->ppTextures[iMaterial] = NULL;
     

                //ポインタをダイナミックメモリに確保しない事、テクスチャ名はNULLにする
                pMeshContainer->pMaterials[iMaterial].pTextureFilename = NULL;
            }
        }
    }
    else //もし、マテリアルが無かったらデフォルトの材質を
    {
        pMeshContainer->pMaterials[0].pTextureFilename = NULL;
        memset(&pMeshContainer->pMaterials[0].MatD3D, 0, sizeof(D3DMATERIAL9));
        pMeshContainer->pMaterials[0].MatD3D.Diffuse.r = 0.5f;
        pMeshContainer->pMaterials[0].MatD3D.Diffuse.g = 0.5f;
        pMeshContainer->pMaterials[0].MatD3D.Diffuse.b = 0.5f;
        pMeshContainer->pMaterials[0].MatD3D.Specular = pMeshContainer->pMaterials[0].MatD3D.Diffuse;
    }

    //スキン情報があれば、ハードウェアスキニングのためにそれを使う
    if (pSkinInfo != NULL)
    {
        //まず最初にデータはスキン情報とメッシュに保存される
        pMeshContainer->pSkinInfo = pSkinInfo;
        pSkinInfo->AddRef();

        pMeshContainer->pOrigMesh = pMesh;
        pMesh->AddRef();

        //フィギュアスペースからボーンスペースへの頂点を移すためにオフセットマトリクスの配列が必要
        cBones = pSkinInfo->GetNumBones();
        pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[cBones];
        if (pMeshContainer->pBoneOffsetMatrices == NULL)
        {
            hr = E_OUTOFMEMORY;
            goto e_Exit;
        }

        //ここでボーンマトリクスを得て後で取得する必要を無くする
        for (iBone = 0; iBone < cBones; iBone++)
        {
            pMeshContainer->pBoneOffsetMatrices[iBone] = *(pMeshContainer->pSkinInfo->GetBoneOffsetMatrix(iBone));
        }

        //GenerateSkinnedMeshはハードウェアスキニングに最適なバージョンに変える
        hr = GenerateSkinnedMesh( pd3dDevice, pMeshContainer );
        if (FAILED(hr))
            goto e_Exit;
    }

    *ppNewMeshContainer = pMeshContainer;
    pMeshContainer = NULL;

e_Exit:
    SAFE_RELEASE(pd3dDevice);

    //適当に割り当てられたデータをきれいにする
    if (pMeshContainer != NULL)
    {
        DestroyMeshContainer(pMeshContainer);
    }

    return hr;
}

 


//--------------------------------------------------------------------------------------
//フレーム削除
//--------------------------------------------------------------------------------------
HRESULT CAllocateHierarchy::DestroyFrame(LPD3DXFRAME pFrameToFree)
{
    SAFE_DELETE_ARRAY( pFrameToFree->Name );
    SAFE_DELETE( pFrameToFree );
    return S_OK;
}

 


//--------------------------------------------------------------------------------------
//メッシュコンテナ削除
//--------------------------------------------------------------------------------------
HRESULT CAllocateHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER pMeshContainerBase)
{
    UINT iMaterial;
    D3DXMESHCONTAINER_DERIVED *pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;

    SAFE_DELETE_ARRAY( pMeshContainer->Name );
    SAFE_DELETE_ARRAY( pMeshContainer->pAdjacency );
    SAFE_DELETE_ARRAY( pMeshContainer->pMaterials );
    SAFE_DELETE_ARRAY( pMeshContainer->pBoneOffsetMatrices );

    //割り当てられた全てのテクスチャを解放する
    if (pMeshContainer->ppTextures != NULL)
    {
        for (iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++)
        {
            SAFE_RELEASE( pMeshContainer->ppTextures[iMaterial] );
        }
    }

    SAFE_DELETE_ARRAY( pMeshContainer->ppTextures );
    SAFE_DELETE_ARRAY( pMeshContainer->ppBoneMatrixPtrs );
    SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf );
    SAFE_RELEASE( pMeshContainer->MeshData.pMesh );
    SAFE_RELEASE( pMeshContainer->pSkinInfo );
    SAFE_RELEASE( pMeshContainer->pOrigMesh );
    SAFE_DELETE( pMeshContainer );
    return S_OK;
}

//--------------------------------------------------------------------------------------
//スキンメッシュ生成
//--------------------------------------------------------------------------------------
HRESULT GenerateSkinnedMesh( IDirect3DDevice9 *pd3dDevice, D3DXMESHCONTAINER_DERIVED *pMeshContainer )
{
    HRESULT hr = S_OK;
    D3DCAPS9 d3dCaps;
    pd3dDevice->GetDeviceCaps( &d3dCaps );

    if( pMeshContainer->pSkinInfo == NULL )
        return hr;

    g_bUseSoftwareVP = false;

    SAFE_RELEASE( pMeshContainer->MeshData.pMesh );
    SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf );

    //ノンインデックススキンモードが選択されて、ConvertToBlendedMeshを使用して、描画可能メッシュを発生させなさいという場合
    if( g_SkinningMethod == D3DNONINDEXED )
    {

        hr = pMeshContainer->pSkinInfo->ConvertToBlendedMesh
                                   (
                                       pMeshContainer->pOrigMesh,
                                       D3DXMESH_MANAGED|D3DXMESHOPT_VERTEXCACHE,
                                       pMeshContainer->pAdjacency,
                                       NULL, NULL, NULL,
                                       &pMeshContainer->NumInfl,
                                       &pMeshContainer->NumAttributeGroups,
                                       &pMeshContainer->pBoneCombinationBuf,
                                       &pMeshContainer->MeshData.pMesh
                                   );
        if (FAILED(hr))
            goto e_Exit;


        //デバイスが2つのマトリクスブレンドしかできないなら、ConvertToBlendedMeshは近似できません。
  //1番目は、装置のHW頂点処理を使用することで描かれます、そして、残りは、SW頂点処理を使用することで描かれます。
        LPD3DXBONECOMBINATION rgBoneCombinations  = reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());

        //キャップスに合わないどんなセットのボーンの組み合わせも探してください。
        for (pMeshContainer->iAttributeSW = 0; pMeshContainer->iAttributeSW < pMeshContainer->NumAttributeGroups; pMeshContainer->iAttributeSW++)
        {
            DWORD cInfl   = 0;

            for (DWORD iInfl = 0; iInfl < pMeshContainer->NumInfl; iInfl++)
            {
                if (rgBoneCombinations[pMeshContainer->iAttributeSW].BoneId[iInfl] != UINT_MAX)
                {
                    ++cInfl;
                }
            }

            if (cInfl > d3dCaps.MaxVertexBlendMatrices)
            {
                break;
            }
        }

        //HWとSWの両方があれば、Software Processingフラグを加えてください。
        if (pMeshContainer->iAttributeSW < pMeshContainer->NumAttributeGroups)
        {
            LPD3DXMESH pMeshTmp;

            hr = pMeshContainer->MeshData.pMesh->CloneMeshFVF(D3DXMESH_SOFTWAREPROCESSING|pMeshContainer->MeshData.pMesh->GetOptions(),
                                                pMeshContainer->MeshData.pMesh->GetFVF(),
                                                pd3dDevice, &pMeshTmp);
            if (FAILED(hr))
            {
                goto e_Exit;
            }

            pMeshContainer->MeshData.pMesh->Release();
            pMeshContainer->MeshData.pMesh = pMeshTmp;
            pMeshTmp = NULL;
        }
    }
    //選択されたモードにスキンインデックスをつけられるなら、ConvertToIndexedsBlendedMeshを使用して、描画可能メッシュを発生させてください。
    else if( g_SkinningMethod == D3DINDEXED )
    {
        DWORD NumMaxFaceInfl;
        DWORD Flags = D3DXMESHOPT_VERTEXCACHE;

        LPDIRECT3DINDEXBUFFER9 pIB;
        hr = pMeshContainer->pOrigMesh->GetIndexBuffer(&pIB);
        if (FAILED(hr))
            goto e_Exit;

        hr = pMeshContainer->pSkinInfo->GetMaxFaceInfluences(pIB, pMeshContainer->pOrigMesh->GetNumFaces(), &NumMaxFaceInfl);
        pIB->Release();
        if (FAILED(hr))
            goto e_Exit;

        //12のエントリーパレット保証 どんな三角形(3つの頂点あたり4つの独立している影響)も扱うことができる
        NumMaxFaceInfl = min(NumMaxFaceInfl, 12);

        if( d3dCaps.MaxVertexBlendMatrixIndex + 1 < NumMaxFaceInfl )
        {
            //HWはインデックスをつけられた頂点ブレンドを支持しません。 代わりにSWを使用してください。
            pMeshContainer->NumPaletteEntries = min(256, pMeshContainer->pSkinInfo->GetNumBones());
            pMeshContainer->UseSoftwareVP = true;
            g_bUseSoftwareVP = true;
            Flags |= D3DXMESH_SYSTEMMEM;
        }
        else
        {
            //ハードウェアはボーンのキャップと数からパレットサイズを決定するのを使用する
   //法線はライトのためにブレンドされる必要があり頂点データに存在しています
   //マトリクスの数はMaxVertexBlendMatrixIndexによって指定された半数です。
            pMeshContainer->NumPaletteEntries = min( ( d3dCaps.MaxVertexBlendMatrixIndex + 1 ) / 2,
                                                     pMeshContainer->pSkinInfo->GetNumBones() );
            pMeshContainer->UseSoftwareVP = false;
            Flags |= D3DXMESH_MANAGED;
        }

        hr = pMeshContainer->pSkinInfo->ConvertToIndexedBlendedMesh
                                                (
                                                pMeshContainer->pOrigMesh,
                                                Flags,
                                                pMeshContainer->NumPaletteEntries,
                                                pMeshContainer->pAdjacency,
                                                NULL, NULL, NULL,
                                                &pMeshContainer->NumInfl,
                                                &pMeshContainer->NumAttributeGroups,
                                                &pMeshContainer->pBoneCombinationBuf,
                                                &pMeshContainer->MeshData.pMesh);
        if (FAILED(hr))
            goto e_Exit;
    }
    //頂点シェーダがインデックススキンモードを選択したなら、ConvertToIndexedsBlendedMeshを使用して、描画可能メッシュを発生させてください。
    else if( ( g_SkinningMethod == D3DINDEXEDVS ) || ( g_SkinningMethod == D3DINDEXEDHLSLVS ) )
    {
        //パレットサイズを得る
        //最初の9つの定数が他のデータに使用されます。 それぞれの4×3マトリクスは3つの定数を持っている。
        //(96 - 9) /3 すなわち、Maximumの一定のカウント-- 中古の定数
        UINT MaxMatrices = 26;
        pMeshContainer->NumPaletteEntries = min(MaxMatrices, pMeshContainer->pSkinInfo->GetNumBones());

        DWORD Flags = D3DXMESHOPT_VERTEXCACHE;
        if (d3dCaps.VertexShaderVersion >= D3DVS_VERSION(1, 1))
        {
            pMeshContainer->UseSoftwareVP = false;
            Flags |= D3DXMESH_MANAGED;
        }
        else
        {
            pMeshContainer->UseSoftwareVP = true;
            g_bUseSoftwareVP = true;
            Flags |= D3DXMESH_SYSTEMMEM;
        }

        SAFE_RELEASE(pMeshContainer->MeshData.pMesh);

        hr = pMeshContainer->pSkinInfo->ConvertToIndexedBlendedMesh
                                                (
                                                pMeshContainer->pOrigMesh,
                                                Flags,
                                                pMeshContainer->NumPaletteEntries,
                                                pMeshContainer->pAdjacency,
                                                NULL, NULL, NULL,            
                                                &pMeshContainer->NumInfl,
                                                &pMeshContainer->NumAttributeGroups,
                                                &pMeshContainer->pBoneCombinationBuf,
                                                &pMeshContainer->MeshData.pMesh);
        if (FAILED(hr))
            goto e_Exit;


        //FVFは当プログラムの宣言に合わなければなりません。 頂点シェーダはFFパイプラインほど寛大ではありません。
        DWORD NewFVF = (pMeshContainer->MeshData.pMesh->GetFVF() & D3DFVF_POSITION_MASK) | D3DFVF_NORMAL | D3DFVF_TEX1 | D3DFVF_LASTBETA_UBYTE4;
        if (NewFVF != pMeshContainer->MeshData.pMesh->GetFVF())
        {
            LPD3DXMESH pMesh;
            hr = pMeshContainer->MeshData.pMesh->CloneMeshFVF(pMeshContainer->MeshData.pMesh->GetOptions(), NewFVF, pd3dDevice, &pMesh);
            if (!FAILED(hr))
            {
                pMeshContainer->MeshData.pMesh->Release();
                pMeshContainer->MeshData.pMesh = pMesh;
                pMesh = NULL;
            }
        }

        D3DVERTEXELEMENT9 pDecl[MAX_FVF_DECL_SIZE];
        LPD3DVERTEXELEMENT9 pDeclCur;
        hr = pMeshContainer->MeshData.pMesh->GetDeclaration(pDecl);
        if (FAILED(hr))
            goto e_Exit;

        //頂点シェーダが、D3DCOLORとしてUBYTE4を解釈するので、タイプをアップデートしてください。
        //メモ:CloneMeshと共にこれができません、そして、それは、floatにUBYTE4データを変換するでしょう。D3DCOLORにキャスト操作。
        pDeclCur = pDecl;
        while (pDeclCur->Stream != 0xff)
        {
            if ((pDeclCur->Usage == D3DDECLUSAGE_BLENDINDICES) && (pDeclCur->UsageIndex == 0))
                pDeclCur->Type = D3DDECLTYPE_D3DCOLOR;
            pDeclCur++;
        }

        hr = pMeshContainer->MeshData.pMesh->UpdateSemantics(pDecl);
        if (FAILED(hr))
            goto e_Exit;

        //別のメッシュが同じサイズ以上のマトリクスを割り当てていない場合にだけ、ボーンのマトリクスのためのバッファを割り当ててください。
        if( g_NumBoneMatricesMax < pMeshContainer->pSkinInfo->GetNumBones() )
        {
            g_NumBoneMatricesMax = pMeshContainer->pSkinInfo->GetNumBones();

            //ブレンドマトリクスのためのスペースを割り当て
            delete[] g_pBoneMatrices;
            g_pBoneMatrices  = new D3DXMATRIXA16[g_NumBoneMatricesMax];
            if( g_pBoneMatrices == NULL )
            {
                hr = E_OUTOFMEMORY;
                goto e_Exit;
            }
        }

    }
    //ソフトウェアスキンが選択されて、GenerateSkinnedMeshを使用して、UpdateSkinnedMeshと共に使用できるメッシュを作成する場合
    else if( g_SkinningMethod == SOFTWARE )
    {
        hr = pMeshContainer->pOrigMesh->CloneMeshFVF(D3DXMESH_MANAGED, pMeshContainer->pOrigMesh->GetFVF(),
                                              pd3dDevice, &pMeshContainer->MeshData.pMesh);
        if (FAILED(hr))
            goto e_Exit;

        hr = pMeshContainer->MeshData.pMesh->GetAttributeTable(NULL, &pMeshContainer->NumAttributeGroups);
        if (FAILED(hr))
            goto e_Exit;

        delete[] pMeshContainer->pAttributeTable;
        pMeshContainer->pAttributeTable  = new D3DXATTRIBUTERANGE[pMeshContainer->NumAttributeGroups];
        if (pMeshContainer->pAttributeTable == NULL)
        {
            hr = E_OUTOFMEMORY;
            goto e_Exit;
        }

        hr = pMeshContainer->MeshData.pMesh->GetAttributeTable(pMeshContainer->pAttributeTable, NULL);
        if (FAILED(hr))
            goto e_Exit;

        //別のメッシュが同じサイズ以上のマトリクスを割り当てていない場合にだけ、ボーンのマトリクスのためのバッファを割り当ててください。
        if (g_NumBoneMatricesMax < pMeshContainer->pSkinInfo->GetNumBones())
        {
            g_NumBoneMatricesMax = pMeshContainer->pSkinInfo->GetNumBones();

            //ブレンドマトリクスのためのスペースを割り当て
            delete[] g_pBoneMatrices;
            g_pBoneMatrices  = new D3DXMATRIXA16[g_NumBoneMatricesMax];
            if( g_pBoneMatrices == NULL )
            {
                hr = E_OUTOFMEMORY;
                goto e_Exit;
            }
        }
    }
    else  //無効のg_SkinningMethod値
    {       
        //メソッド値のスキニングエラーによるリターン失敗
        hr = E_INVALIDARG;
        goto e_Exit;
    }

e_Exit:
    return hr;
}

 

//--------------------------------------------------------------------------------------
//メッシュコンテナ描画
//--------------------------------------------------------------------------------------
void DrawMeshContainer( IDirect3DDevice9 *pd3dDevice, LPD3DXMESHCONTAINER pMeshContainerBase, LPD3DXFRAME pFrameBase )
{
    HRESULT hr;
    D3DXMESHCONTAINER_DERIVED *pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;
    D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;
    UINT iMaterial;
    UINT NumBlend;
    UINT iAttrib;
    DWORD AttribIdPrev;
    LPD3DXBONECOMBINATION pBoneComb;

    UINT iMatrixIndex;
    UINT iPaletteEntry;
    D3DXMATRIXA16 matTemp;
    D3DCAPS9 d3dCaps;
    pd3dDevice->GetDeviceCaps( &d3dCaps );

    //最初にスキン情報が無いかチェックする
    if (pMeshContainer->pSkinInfo != NULL)
    {
        if( g_SkinningMethod == D3DNONINDEXED )
        {
            AttribIdPrev = UNUSED32;
            pBoneComb = reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());

            //デバイス(通常HW)のデフォルトvtx処理を使用して、描いてください。
            for (iAttrib = 0; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++)
            {
                NumBlend = 0;
                for (DWORD i = 0; i < pMeshContainer->NumInfl; ++i)
                {
                    if (pBoneComb[iAttrib].BoneId[i] != UINT_MAX)
                    {
                        NumBlend = i;
                    }
                }

                if( d3dCaps.MaxVertexBlendMatrices >= NumBlend + 1 )
                {
                    //まず最初に、現在のセットのブレンドウェイトのためのワールドマトリクスを計算してください、そして、ブレンドの数の正確な計算を得てください。
                    for (DWORD i = 0; i < pMeshContainer->NumInfl; ++i)
                    {
                        iMatrixIndex = pBoneComb[iAttrib].BoneId[i];
                        if (iMatrixIndex != UINT_MAX)
                        {
                            D3DXMatrixMultiply( &matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex], pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );
                            V( pd3dDevice->SetTransform( D3DTS_WORLDMATRIX( i ), &matTemp ) );
                        }
                    }

                    V( pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, NumBlend) );

                    //マテリアルが面のサブセットに使用したルックアップ
                    if ((AttribIdPrev != pBoneComb[iAttrib].AttribId) || (AttribIdPrev == UNUSED32))
                    {
                        V( pd3dDevice->SetMaterial( &pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D ) );
                        V( pd3dDevice->SetTexture( 0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ) );
                        AttribIdPrev = pBoneComb[iAttrib].AttribId;
                    }

                    //正しいマテリアルとマトリクスがロードされているので、サブセットを描いてください。
                    V( pMeshContainer->MeshData.pMesh->DrawSubset(iAttrib) );
                }
            }

            //必要なら、SWを使用することでHWが扱うことができなかったサブセットを描いてください。
            if (pMeshContainer->iAttributeSW < pMeshContainer->NumAttributeGroups)
            {
                AttribIdPrev = UNUSED32;
                V( pd3dDevice->SetSoftwareVertexProcessing(TRUE) );
                for (iAttrib = pMeshContainer->iAttributeSW; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++)
                {
                    NumBlend = 0;
                    for (DWORD i = 0; i < pMeshContainer->NumInfl; ++i)
                    {
                        if (pBoneComb[iAttrib].BoneId[i] != UINT_MAX)
                        {
                            NumBlend = i;
                        }
                    }

                    if (d3dCaps.MaxVertexBlendMatrices < NumBlend + 1)
                    {
                        //まず最初に、現在のセットのブレンドウェイトのためのワールドマトリクスを計算してください、そして、ブレンドの数の正確な計算を得てください。
                        for (DWORD i = 0; i < pMeshContainer->NumInfl; ++i)
                        {
                            iMatrixIndex = pBoneComb[iAttrib].BoneId[i];
                            if (iMatrixIndex != UINT_MAX)
                            {
                                D3DXMatrixMultiply( &matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex], pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );
                                V( pd3dDevice->SetTransform( D3DTS_WORLDMATRIX( i ), &matTemp ) );
                            }
                        }

                        V( pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, NumBlend) );

                        //マテリアルが面のサブセットに使用したルックアップ
                        if ((AttribIdPrev != pBoneComb[iAttrib].AttribId) || (AttribIdPrev == UNUSED32))
                        {
                            V( pd3dDevice->SetMaterial( &pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D ) );
                            V( pd3dDevice->SetTexture( 0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ) );
                            AttribIdPrev = pBoneComb[iAttrib].AttribId;
                        }

                        //正しいマテリアルとマトリクスがロードされているので、サブセットを描いてください。
                        V( pMeshContainer->MeshData.pMesh->DrawSubset(iAttrib) );
                    }
                }
                V( pd3dDevice->SetSoftwareVertexProcessing( FALSE ) );
            }

            V( pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND, 0) );
        }
        else if (g_SkinningMethod == D3DINDEXED)
        {
            //HWがインデックスをつけられた頂点処理をサポートしないなら、ソフトウェア頂点処理に切り替わってください。
            if (pMeshContainer->UseSoftwareVP)
            {
                //HWが純粋なHW頂点処理が無理なら、メッシュをレンダリングできないので、外にただ出てください。
    //アプリケーションは、このためにメソッドのスキン情報を調べながら、適切な頂点処理能力でデバイスを作成するべきです。
                if( g_dwBehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING )
                    return;

                V( pd3dDevice->SetSoftwareVertexProcessing(TRUE) );
            }

            //頂点ブレンドインデックスリストの数にブレンドされるように設定してください。
            if (pMeshContainer->NumInfl == 1)
            {
                V( pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_0WEIGHTS) );
            }
            else
            {
                V( pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, pMeshContainer->NumInfl - 1) );
            }

            if (pMeshContainer->NumInfl)
                V( pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, TRUE) );

            //メッシュの各属性グループは、パレットでマトリクスのセットについて計算してください、そして、次に、メッシュサブセットを描いてください。
            pBoneComb = reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());
            for (iAttrib = 0; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++)
            {
                //まず最初にワールドマトリクスを計算する
                for (iPaletteEntry = 0; iPaletteEntry < pMeshContainer->NumPaletteEntries; ++iPaletteEntry)
                {
                    iMatrixIndex = pBoneComb[iAttrib].BoneId[iPaletteEntry];
                    if (iMatrixIndex != UINT_MAX)
                    {
                        D3DXMatrixMultiply( &matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex], pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );
                        V( pd3dDevice->SetTransform( D3DTS_WORLDMATRIX( iPaletteEntry ), &matTemp ) );
                    }
                }
               
                //メッシュサブセットのマテリアルをセットアップしてください-- オリジナルなIDを得るのにオリジナルのプレスキニング属性IDを使用する
                V( pd3dDevice->SetMaterial( &pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D ) );
                V( pd3dDevice->SetTexture( 0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ) );

                //最終的に現在のワールドマトリクスパレットとマテリアルステートとサブセットを描いてください。
                V( pMeshContainer->MeshData.pMesh->DrawSubset( iAttrib ) );
            }

            //リセット ブレンディングステート
            V( pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE) );
            V( pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, 0) );

            //ソフトウェアが必要であったなら、HW頂点処理をリセットして戻してください。
            if (pMeshContainer->UseSoftwareVP)
            {
                V( pd3dDevice->SetSoftwareVertexProcessing(FALSE) );
            }
        }
        else if (g_SkinningMethod == D3DINDEXEDVS)
        {
            //UBYTE4の代わりにCOLORを使用してください。Geforce3がそれを支持しないので。
            D3DXVECTOR4 vConst( 1.0f, 0.0f, 0.0f, 765.01f );

            if (pMeshContainer->UseSoftwareVP)
            {
                //HWが純粋なHW頂点処理が無理なら、メッシュをレンダリングできないので、外にただ出てください。
    //アプリケーションは、このためにメソッドのスキン情報を調べながら、適切な頂点処理能力でデバイスを作成するべきです。
                if( g_dwBehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING )
                    return;

                V( pd3dDevice->SetSoftwareVertexProcessing(TRUE) );
            }

            V( pd3dDevice->SetVertexShader( g_pIndexedVertexShader[pMeshContainer->NumInfl - 1] ) );

            pBoneComb = reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());
            for (iAttrib = 0; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++)
            {
                //まず最初にワールドマトリクスを計算する
                for (iPaletteEntry = 0; iPaletteEntry < pMeshContainer->NumPaletteEntries; ++iPaletteEntry)
                {
                    iMatrixIndex = pBoneComb[iAttrib].BoneId[iPaletteEntry];
                    if (iMatrixIndex != UINT_MAX)
                    {
                        D3DXMatrixMultiply(&matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex], pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex]);
                        D3DXMatrixMultiplyTranspose(&matTemp, &matTemp, &g_matView);
                        V( pd3dDevice->SetVertexShaderConstantF(iPaletteEntry*3 + 9, (float*)&matTemp, 3) );
                    }
                }

                //全てのアンビエントとエミッシブの合計
                D3DXCOLOR color1(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Ambient);
                D3DXCOLOR color2(.25, .25, .25, 1.0);
                D3DXCOLOR ambEmm;
                D3DXColorModulate(&ambEmm, &color1, &color2);
                ambEmm += D3DXCOLOR(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Emissive);

                //マテリアルカラープロパティーセット
                V( pd3dDevice->SetVertexShaderConstantF(8, (float*)&(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Diffuse), 1) );
                V( pd3dDevice->SetVertexShaderConstantF(7, (float*)&ambEmm, 1) );
                vConst.y = pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Power;
                V( pd3dDevice->SetVertexShaderConstantF(0, (float*)&vConst, 1) );

                V( pd3dDevice->SetTexture(0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId]) );

                //最終的に現在のワールドマトリクスパレットとマテリアルステートのサブセットを描いてください。
                V( pMeshContainer->MeshData.pMesh->DrawSubset( iAttrib ) );
            }

            //ソフトウェアが必要であったなら、HW頂点処理をリセットして戻してください。
            if (pMeshContainer->UseSoftwareVP)
            {
                V( pd3dDevice->SetSoftwareVertexProcessing(FALSE) );
            }
            V( pd3dDevice->SetVertexShader( NULL ) );
        }
        else if (g_SkinningMethod == D3DINDEXEDHLSLVS)
        {
            if (pMeshContainer->UseSoftwareVP)
            {
                //HWが純粋なHW頂点処理が無理なら、メッシュをレンダリングできないので、外にただ出てください。
    //アプリケーションは、このためにメソッドのスキン情報を調べながら、適切な頂点処理能力でデバイスを作成するべきです。
                if( g_dwBehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING )
                    return;

                V( pd3dDevice->SetSoftwareVertexProcessing(TRUE) );
            }

            pBoneComb = reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());
            for (iAttrib = 0; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++)
            {
                //まず最初にワールドマトリクスを計算する
                for (iPaletteEntry = 0; iPaletteEntry < pMeshContainer->NumPaletteEntries; ++iPaletteEntry)
                {
                    iMatrixIndex = pBoneComb[iAttrib].BoneId[iPaletteEntry];
                    if (iMatrixIndex != UINT_MAX)
                    {
                        D3DXMatrixMultiply(&matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex], pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex]);
                        D3DXMatrixMultiply(&g_pBoneMatrices[iPaletteEntry], &matTemp, &g_matView);
                    }
                }
                V( g_pEffect->SetMatrixArray( "mWorldMatrixArray", g_pBoneMatrices, pMeshContainer->NumPaletteEntries) );

                //全てのアンビエントとエミッシブの合計
                D3DXCOLOR color1(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Ambient);
                D3DXCOLOR color2(.25, .25, .25, 1.0);
                D3DXCOLOR ambEmm;
                D3DXColorModulate(&ambEmm, &color1, &color2);
                ambEmm += D3DXCOLOR(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Emissive);

                //マテリアルカラープロパティーセット
                V( g_pEffect->SetVector("MaterialDiffuse", (D3DXVECTOR4*)&(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Diffuse)) );
                V( g_pEffect->SetVector("MaterialAmbient", (D3DXVECTOR4*)&ambEmm) );

                //メッシュサブセットのマテリアルをセットアップしてください-- オリジナルなIDを得るのにオリジナルのプレスキニング属性IDを使用する
                V( pd3dDevice->SetTexture( 0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ) );

                //CurNumBonesにボーンの数のための正しい頂点シェーダを選択するように設定してください。
                V( g_pEffect->SetInt( "CurNumBones", pMeshContainer->NumInfl -1) );

                //現在のすべてのパラメータをアップデートしたシェーダーをスタートしてください。
                UINT numPasses;
                V( g_pEffect->Begin( &numPasses, D3DXFX_DONOTSAVESTATE ) );
                for( UINT iPass = 0; iPass < numPasses; iPass++ )
                {
                    V( g_pEffect->BeginPass( iPass ) );

                    //現在のワールドマトリクスパレットとマテリアルステートのサブセットを描いてください。
                    V( pMeshContainer->MeshData.pMesh->DrawSubset( iAttrib ) );

                    V( g_pEffect->EndPass() );
                }

                V( g_pEffect->End() );

                V( pd3dDevice->SetVertexShader(NULL) );
            }

            //ソフトウェアが必要であったなら、HW頂点処理をリセットして戻してください。
            if (pMeshContainer->UseSoftwareVP)
            {
                V( pd3dDevice->SetSoftwareVertexProcessing(FALSE) );
            }
        }
        else if (g_SkinningMethod == SOFTWARE)
        {
            D3DXMATRIX  Identity;
            DWORD       cBones  = pMeshContainer->pSkinInfo->GetNumBones();
            DWORD       iBone;
            PBYTE       pbVerticesSrc;
            PBYTE       pbVerticesDest;

            //ボーントランスフォームセットアップ
            for (iBone = 0; iBone < cBones; ++iBone)
            {
                D3DXMatrixMultiply
                (
                    &g_pBoneMatrices[iBone],                 // output
                    &pMeshContainer->pBoneOffsetMatrices[iBone],
                    pMeshContainer->ppBoneMatrixPtrs[iBone]
                );
            }

            //ワールドトランスフォームセットアップ
            D3DXMatrixIdentity(&Identity);
            V( pd3dDevice->SetTransform(D3DTS_WORLD, &Identity) );

            V( pMeshContainer->pOrigMesh->LockVertexBuffer(D3DLOCK_READONLY, (LPVOID*)&pbVerticesSrc) );
            V( pMeshContainer->MeshData.pMesh->LockVertexBuffer(0, (LPVOID*)&pbVerticesDest) );

            //スキンメッシュ生成
            pMeshContainer->pSkinInfo->UpdateSkinnedMesh(g_pBoneMatrices, NULL, pbVerticesSrc, pbVerticesDest);

            V( pMeshContainer->pOrigMesh->UnlockVertexBuffer() );
            V( pMeshContainer->MeshData.pMesh->UnlockVertexBuffer() );

            for (iAttrib = 0; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++)
            {
                V( pd3dDevice->SetMaterial(&(pMeshContainer->pMaterials[pMeshContainer->pAttributeTable[iAttrib].AttribId].MatD3D)) );
                V( pd3dDevice->SetTexture(0, pMeshContainer->ppTextures[pMeshContainer->pAttributeTable[iAttrib].AttribId]) );
                V( pMeshContainer->MeshData.pMesh->DrawSubset(pMeshContainer->pAttributeTable[iAttrib].AttribId) );
            }
        }
        else //バグアウト サポート外のメッシュ
        {
            return;
        }
    }
    else  //スタンダードメッシュに、マテリアルプロパティーを設定した後に、ただそれを描いてください。
    {
        V( pd3dDevice->SetTransform(D3DTS_WORLD, &pFrame->CombinedTransformationMatrix) );

        for (iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++)
        {
            V( pd3dDevice->SetMaterial( &pMeshContainer->pMaterials[iMaterial].MatD3D ) );
            V( pd3dDevice->SetTexture( 0, pMeshContainer->ppTextures[iMaterial] ) );
            V( pMeshContainer->MeshData.pMesh->DrawSubset(iMaterial) );
        }
    }
}

 


//--------------------------------------------------------------------------------------
//フレーム描画
//--------------------------------------------------------------------------------------
void DrawFrame( IDirect3DDevice9 *pd3dDevice, LPD3DXFRAME pFrame )
{
    LPD3DXMESHCONTAINER pMeshContainer;

    pMeshContainer = pFrame->pMeshContainer;
    while (pMeshContainer != NULL)
    {
        DrawMeshContainer( pd3dDevice, pMeshContainer, pFrame );

        pMeshContainer = pMeshContainer->pNextMeshContainer;
    }

    if (pFrame->pFrameSibling != NULL)
    {
        DrawFrame( pd3dDevice, pFrame->pFrameSibling);
    }

    if (pFrame->pFrameFirstChild != NULL)
    {
        DrawFrame( pd3dDevice, pFrame->pFrameFirstChild );
    }
}

 

//--------------------------------------------------------------------------------------
//メッシュ上のボーンマトリクスポインターをセット
//--------------------------------------------------------------------------------------
HRESULT SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER pMeshContainerBase )
{
    UINT iBone, cBones;
    D3DXFRAME_DERIVED *pFrame;

    D3DXMESHCONTAINER_DERIVED *pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;

    //skinmeshがあれば、ボーンのマトリクスをセットアップしてください。
    if (pMeshContainer->pSkinInfo != NULL)
    {
        cBones = pMeshContainer->pSkinInfo->GetNumBones();

        pMeshContainer->ppBoneMatrixPtrs = new D3DXMATRIX*[cBones];
        if (pMeshContainer->ppBoneMatrixPtrs == NULL)
            return E_OUTOFMEMORY;

        for (iBone = 0; iBone < cBones; iBone++)
        {
            pFrame = (D3DXFRAME_DERIVED*)D3DXFrameFind( g_pFrameRoot, pMeshContainer->pSkinInfo->GetBoneName(iBone) );
            if (pFrame == NULL)
                return E_FAIL;

            pMeshContainer->ppBoneMatrixPtrs[iBone] = &pFrame->CombinedTransformationMatrix;
        }
    }

    return S_OK;
}


//--------------------------------------------------------------------------------------
//ボーンマトリクスポインターセット
//--------------------------------------------------------------------------------------
HRESULT SetupBoneMatrixPointers( LPD3DXFRAME pFrame )
{
    HRESULT hr;

    if (pFrame->pMeshContainer != NULL)
    {
        hr = SetupBoneMatrixPointersOnMesh(pFrame->pMeshContainer);
        if (FAILED(hr))
            return hr;
    }

    if (pFrame->pFrameSibling != NULL)
    {
        hr = SetupBoneMatrixPointers(pFrame->pFrameSibling);
        if (FAILED(hr))
            return hr;
    }

    if (pFrame->pFrameFirstChild != NULL)
    {
        hr = SetupBoneMatrixPointers(pFrame->pFrameFirstChild);
        if (FAILED(hr))
            return hr;
    }

    return S_OK;
}

 


//--------------------------------------------------------------------------------------
//フレームマトリクス更新
//--------------------------------------------------------------------------------------
void UpdateFrameMatrices( LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix )
{
    D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;

    if (pParentMatrix != NULL)
        D3DXMatrixMultiply(&pFrame->CombinedTransformationMatrix, &pFrame->TransformationMatrix, pParentMatrix);
    else
        pFrame->CombinedTransformationMatrix = pFrame->TransformationMatrix;

    if (pFrame->pFrameSibling != NULL)
    {
        UpdateFrameMatrices(pFrame->pFrameSibling, pParentMatrix);
    }

    if (pFrame->pFrameFirstChild != NULL)
    {
        UpdateFrameMatrices(pFrame->pFrameFirstChild, &pFrame->CombinedTransformationMatrix);
    }
}


//--------------------------------------------------------------------------------------
//スキニングメソッド更新
//--------------------------------------------------------------------------------------
void UpdateSkinningMethod( IDirect3DDevice9 *pd3dDevice, LPD3DXFRAME pFrameBase )
{
    D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;
    D3DXMESHCONTAINER_DERIVED *pMeshContainer;

    pMeshContainer = (D3DXMESHCONTAINER_DERIVED *)pFrame->pMeshContainer;

    while( pMeshContainer != NULL )
    {
  GenerateSkinnedMesh( pd3dDevice, pMeshContainer );

        pMeshContainer = (D3DXMESHCONTAINER_DERIVED *)pMeshContainer->pNextMeshContainer;
    }

    if (pFrame->pFrameSibling != NULL)
    {
        UpdateSkinningMethod(pd3dDevice,pFrame->pFrameSibling);
    }

    if (pFrame->pFrameFirstChild != NULL)
    {
        UpdateSkinningMethod(pd3dDevice,pFrame->pFrameFirstChild);
    }
}


//--------------------------------------------------------------------------------------
//アトリビュートテーブルの解放
//--------------------------------------------------------------------------------------
void ReleaseAttributeTable( LPD3DXFRAME pFrameBase )
{
    D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;
    D3DXMESHCONTAINER_DERIVED *pMeshContainer;

    pMeshContainer = (D3DXMESHCONTAINER_DERIVED *)pFrame->pMeshContainer;

    while( pMeshContainer != NULL )
    {
        delete[] pMeshContainer->pAttributeTable;

        pMeshContainer = (D3DXMESHCONTAINER_DERIVED *)pMeshContainer->pNextMeshContainer;
    }

    if (pFrame->pFrameSibling != NULL)
    {
        ReleaseAttributeTable(pFrame->pFrameSibling);
    }

    if (pFrame->pFrameFirstChild != NULL)
    {
        ReleaseAttributeTable(pFrame->pFrameFirstChild);
    }
}

以下はシェーダーファイル

skinmesh1.vsh

vs.1.1

;------------------------------------------------------------------------------
; v0 = position
; v1 = blend weights
; v2 = blend indices
; v3 = normal
; v4 = texture coordinates
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; r0.w = Last blend weight
; r1 = Blend indices
; r2 = Temp position
; r3 = Temp normal
; r4 = Blended position in camera space
; r5 = Blended normal in camera space
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; Constants specified by the app;
;
; c9-c95 = world-view matrix palette
; c8   = diffuse * light.diffuse
; c7   = ambient color
; c2-c5   = projection matrix
; c1   = light direction
; c0   = {1, power, 0, 1020.01};
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; oPos   = Output position
; oD0   = Diffuse
; oD1   = Specular
; oT0   = texture coordinates
;------------------------------------------------------------------------------

dcl_position v0;
dcl_blendweight v1;
dcl_blendindices v2;
dcl_normal v3;
dcl_texcoord0 v4;

// Compensate for lack of UBYTE4 on Geforce3
mul r1,v2.zyxw,c0.wwww
//mul r1,v2,c0.wwww


//Set 1
mov a0.x,r1.x
m4x3 r4.xyz,v0,c[a0.x + 9];
m3x3 r5.xyz,v3,c[a0.x + 9];

//compute position
mov r4.w,c0.x
m4x4 oPos,r4,c2

// normalize normals
dp3 r5.w, r5, r5;
rsq r5.w, r5.w;
mul r5, r5, r5.w;

; Do the lighting calculation
dp3 r1.x, r5, c1      ; normal dot light
lit r1, r1
mul r0, r1.y, c8      ; Multiply with diffuse
add r0, r0, c7        ; Add in ambient
min oD0, r0, c0.x     ; clamp if > 1
mov oD1, c0.zzzz     ; output specular

; Copy texture coordinate
mov oT0, v4

skinmesh2.vsh

vs.1.1

;------------------------------------------------------------------------------
; v0 = position
; v1 = blend weights
; v2 = blend indices
; v3 = normal
; v4 = texture coordinates
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; r0.w = Last blend weight
; r1 = Blend indices
; r2 = Temp position
; r3 = Temp normal
; r4 = Blended position in camera space
; r5 = Blended normal in camera space
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; Constants specified by the app;
;
; c9-c95 = world-view matrix palette
; c8   = diffuse * light.diffuse
; c7   = ambient color
; c2-c5   = projection matrix
; c1   = light direction
; c0   = {1, power, 0, 1020.01};
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; oPos   = Output position
; oD0   = Diffuse
; oD1   = Specular
; oT0   = texture coordinates
;------------------------------------------------------------------------------

dcl_position v0;
dcl_blendweight v1;
dcl_blendindices v2;
dcl_normal v3;
dcl_texcoord0 v4;

// Compensate for lack of UBYTE4 on Geforce3
mul r1,v2.zyxw,c0.wwww
//mul r1,v2,c0.wwww


//first compute the last blending weight
dp3 r0.w,v1.xyz,c0.xzz;
add r0.w,-r0.w,c0.x

//Set 1
mov a0.x,r1.x
m4x3 r4.xyz,v0,c[a0.x + 9];
m3x3 r5.xyz,v3,c[a0.x + 9];

//blend them
mul r4.xyz,r4.xyz,v1.xxxx
mul r5.xyz,r5.xyz,v1.xxxx

//Set 2
mov a0.x,r1.y
m4x3 r2.xyz,v0,c[a0.x + 9];
m3x3 r3.xyz,v3,c[a0.x + 9];

//add them in
mad r4.xyz,r2.xyz,r0.wwww,r4;
mad r5.xyz,r3.xyz,r0.wwww,r5;

//compute position
mov r4.w,c0.x
m4x4 oPos,r4,c2

// normalize normals
dp3 r5.w, r5, r5;
rsq r5.w, r5.w;
mul r5, r5, r5.w;

; Do the lighting calculation
dp3 r1.x, r5, c1      ; normal dot light
lit r1, r1
mul r0, r1.y, c8      ; Multiply with diffuse
add r0, r0, c7        ; Add in ambient
min oD0, r0, c0.x     ; clamp if > 1
mov oD1, c0.zzzz      ; output specular

; Copy texture coordinate
mov oT0, v4

skinmesh3.vsh

vs.1.1

;------------------------------------------------------------------------------
; v0 = position
; v1 = blend weights
; v2 = blend indices
; v3 = normal
; v4 = texture coordinates
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; r0.w = Last blend weight
; r1 = Blend indices
; r2 = Temp position
; r3 = Temp normal
; r4 = Blended position in camera space
; r5 = Blended normal in camera space
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; Constants specified by the app;
;
; c9-c95 = world-view matrix palette
; c8   = diffuse * light.diffuse
; c7   = ambient color
; c2-c5   = projection matrix
; c1   = light direction
; c0   = {1, power, 0, 1020.01};
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; oPos   = Output position
; oD0   = Diffuse
; oD1   = Specular
; oT0   = texture coordinates
;------------------------------------------------------------------------------

dcl_position v0;
dcl_blendweight v1;
dcl_blendindices v2;
dcl_normal v3;
dcl_texcoord0 v4;

// Compensate for lack of UBYTE4 on Geforce3
mul r1,v2.zyxw,c0.wwww
//mul r1,v2,c0.wwww


//first compute the last blending weight
dp3 r0.w,v1.xyz,c0.xxz;
add r0.w,-r0.w,c0.x

//Set 1
mov a0.x,r1.x
m4x3 r4.xyz,v0,c[a0.x + 9];
m3x3 r5.xyz,v3,c[a0.x + 9];

//blend them
mul r4.xyz,r4.xyz,v1.xxxx
mul r5.xyz,r5.xyz,v1.xxxx

//Set 2
mov a0.x,r1.y
m4x3 r2.xyz,v0,c[a0.x + 9];
m3x3 r3.xyz,v3,c[a0.x + 9];

//add them in
mad r4.xyz,r2.xyz,v1.yyyy,r4;
mad r5.xyz,r3.xyz,v1.yyyy,r5;
  
//Set 3
mov a0.x,r1.z
m4x3 r2.xyz,v0,c[a0.x + 9];
m3x3 r3.xyz,v3,c[a0.x + 9];

//add them in
mad r4.xyz,r2.xyz,r0.wwww,r4;
mad r5.xyz,r3.xyz,r0.wwww,r5;

//compute position
mov r4.w,c0.x
m4x4 oPos,r4,c2

// normalize normals
dp3 r5.w, r5, r5;
rsq r5.w, r5.w;
mul r5, r5, r5.w;

; Do the lighting calculation
dp3 r1.x, r5, c1      ; normal dot light
lit r1, r1
mul r0, r1.y, c8      ; Multiply with diffuse
add r0, r0, c7        ; Add in ambient
min oD0, r0, c0.x     ; clamp if > 1
mov oD1, c0.zzzz     ; output specular

; Copy texture coordinate
mov oT0, v4

skinmesh4.vsh

vs.1.1

;------------------------------------------------------------------------------
; v0 = position
; v1 = blend weights
; v2 = blend indices
; v3 = normal
; v4 = texture coordinates
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; r0.w = Last blend weight
; r1 = Blend indices
; r2 = Temp position
; r3 = Temp normal
; r4 = Blended position in camera space
; r5 = Blended normal in camera space
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; Constants specified by the app;
;
; c9-c95 = world-view matrix palette
; c8   = diffuse * light.diffuse
; c7   = ambient color
; c2-c5   = projection matrix
; c1   = light direction
; c0   = {1, power, 0, 1020.01};
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; oPos   = Output position
; oD0   = Diffuse
; oD1   = Specular
; oT0   = texture coordinates
;------------------------------------------------------------------------------

dcl_position v0;
dcl_blendweight v1;
dcl_blendindices v2;
dcl_normal v3;
dcl_texcoord0 v4;

// Compensate for lack of UBYTE4 on Geforce3
mul r1,v2.zyxw,c0.wwww
//mul r1,v2,c0.wwww


//first compute the last blending weight
dp3 r0.w,v1.xyz,c0.xxx;
add r0.w,-r0.w,c0.x

//Set 1
mov a0.x,r1.x
m4x3 r4.xyz,v0,c[a0.x + 9];
m3x3 r5.xyz,v3,c[a0.x + 9];

//blend them
mul r4.xyz,r4.xyz,v1.xxxx
mul r5.xyz,r5.xyz,v1.xxxx

//Set 2
mov a0.x,r1.y
m4x3 r2.xyz,v0,c[a0.x + 9];
m3x3 r3.xyz,v3,c[a0.x + 9];

//add them in
mad r4.xyz,r2.xyz,v1.yyyy,r4;
mad r5.xyz,r3.xyz,v1.yyyy,r5;
  
//Set 3
mov a0.x,r1.z
m4x3 r2.xyz,v0,c[a0.x + 9];
m3x3 r3.xyz,v3,c[a0.x + 9];

//add them in
mad r4.xyz,r2.xyz,v1.zzzz,r4;
mad r5.xyz,r3.xyz,v1.zzzz,r5;

//Set 4
mov a0.x,r1.w
m4x3 r2.xyz,v0,c[a0.x + 9];
m3x3 r3.xyz,v3,c[a0.x + 9];

//add them in
mad r4.xyz,r2.xyz,r0.wwww,r4;
mad r5.xyz,r3.xyz,r0.wwww,r5;

//compute position
mov r4.w,c0.x
m4x4 oPos,r4,c2

// normalize normals
dp3 r5.w, r5, r5;
rsq r5.w, r5.w;
mul r5, r5, r5.w;

; Do the lighting calculation
dp3 r1.x, r5, c1      ; normal dot light
lit r1, r1
mul r0, r1.y, c8      ; Multiply with diffuse
add r0, r0, c7        ; Add in ambient
min oD0, r0, c0.x     ; clamp if > 1
mov oD1, c0.zzzz     ; output specular

; Copy texture coordinate
mov oT0, v4

SkinnedMesh.fx

//
// Skinned Mesh Effect file
// Copyright (c) 2000-2002 Microsoft Corporation. All rights reserved.
//

float4 lhtDir = {0.0f, 0.0f, -1.0f, 1.0f};    //light Direction
float4 lightDiffuse = {0.6f, 0.6f, 0.6f, 1.0f}; // Light Diffuse
float4 MaterialAmbient : MATERIALAMBIENT = {0.1f, 0.1f, 0.1f, 1.0f};
float4 MaterialDiffuse : MATERIALDIFFUSE = {0.8f, 0.8f, 0.8f, 1.0f};

// Matrix Pallette
static const int MAX_MATRICES = 26;
float4x3    mWorldMatrixArray[MAX_MATRICES] : WORLDMATRIXARRAY;
float4x4    mViewProj : VIEWPROJECTION;

///////////////////////////////////////////////////////
struct VS_INPUT
{
    float4  Pos             : POSITION;
    float4  BlendWeights    : BLENDWEIGHT;
    float4  BlendIndices    : BLENDINDICES;
    float3  Normal          : NORMAL;
    float3  Tex0            : TEXCOORD0;
};

struct VS_OUTPUT
{
    float4  Pos     : POSITION;
    float4  Diffuse : COLOR;
    float2  Tex0    : TEXCOORD0;
};


float3 Diffuse(float3 Normal)
{
    float CosTheta;
   
    // N.L Clamped
    CosTheta = max(0.0f, dot(Normal, lhtDir.xyz));
      
    // propogate scalar result to vector
    return (CosTheta);
}


VS_OUTPUT VShade(VS_INPUT i, uniform int NumBones)
{
    VS_OUTPUT   o;
    float3      Pos = 0.0f;
    float3      Normal = 0.0f;   
    float       LastWeight = 0.0f;
    
    // Compensate for lack of UBYTE4 on Geforce3
    int4 IndexVector = D3DCOLORtoUBYTE4(i.BlendIndices);

    // cast the vectors to arrays for use in the for loop below
    float BlendWeightsArray[4] = (float[4])i.BlendWeights;
    int   IndexArray[4]        = (int[4])IndexVector;
   
    // calculate the pos/normal using the "normal" weights
    //        and accumulate the weights to calculate the last weight
    for (int iBone = 0; iBone < NumBones-1; iBone++)
    {
        LastWeight = LastWeight + BlendWeightsArray[iBone];
       
        Pos += mul(i.Pos, mWorldMatrixArray[IndexArray[iBone]]) * BlendWeightsArray[iBone];
        Normal += mul(i.Normal, mWorldMatrixArray[IndexArray[iBone]]) * BlendWeightsArray[iBone];
    }
    LastWeight = 1.0f - LastWeight;

    // Now that we have the calculated weight, add in the final influence
    Pos += (mul(i.Pos, mWorldMatrixArray[IndexArray[NumBones-1]]) * LastWeight);
    Normal += (mul(i.Normal, mWorldMatrixArray[IndexArray[NumBones-1]]) * LastWeight);
   
    // transform position from world space into view and then projection space
    o.Pos = mul(float4(Pos.xyz, 1.0f), mViewProj);

    // normalize normals
    Normal = normalize(Normal);

    // Shade (Ambient + etc.)
    o.Diffuse.xyz = MaterialAmbient.xyz + Diffuse(Normal) * MaterialDiffuse.xyz;
    o.Diffuse.w = 1.0f;

    // copy the input texture coordinate through
    o.Tex0  = i.Tex0.xy;

    return o;
}

int CurNumBones = 2;
VertexShader vsArray[4] = { compile vs_2_0 VShade(1),
                            compile vs_2_0 VShade(2),
                            compile vs_2_0 VShade(3),
                            compile vs_2_0 VShade(4)
                          };


//////////////////////////////////////
// Techniques specs follow
//////////////////////////////////////
technique t0
{
    pass p0
    {
        VertexShader = (vsArray[CurNumBones]);
    }
}

最終更新:2009年05月10日 14:49
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。
添付ファイル