D3D9中的蒙皮骨骼动画

蒙皮骨骼动画

        一、蒙皮骨骼动画原理:蒙皮骨骼动画的思想来源于自然界,大多数动物都拥有一套骨骼,骨骼是身体的框架,身体的皮毛血肉都是依附于骨骼。当骨骼开始运动的时候,依附于对应骨骼的皮毛血肉都会随骨骼一起运动。而Mesh模型是由大量的三角形组成,三角形由定点组成。当我们运动时,有必要知道那些定点依附于那块骨骼,根据骨骼的移动来移动对应的顶点。
            蒙皮骨骼动画的加载:和Mesh模型的加载一样,骨骼加载时也是基于本地空间,我们需要把骨骼一块一块的从基于本地空间转换到整个Mesh模型空间。对于一套骨骼,有一个根(root)骨骼,这个根骨骼位于模型的一个定点,如坐标原点,其他骨骼都是直接或者间接与之联系。每根骨骼都有相对于其父母骨骼的相对位置(包括位移,和绕关节进行的转动),这种转换由一个矩阵完成:LocalTransformMatrix,这只是完成了骨骼的定位,要实现动画还需要对骨骼进行各种变换,如你所料,这肯定也是利用矩阵完成:CombinedTransformMatrix。当上层骨骼运动时,下层骨骼并不会主动运动,而是被牵连着运动,所以上层的运动会传递到下层骨骼,这个原理表示为:(子骨骼)CombinedTransformMatrix = (子骨骼)LocalTransformMatrix * (父母骨骼的)CombinedTransformMatrix.当然这中传递是渲染之前计算好的。
            关键结构体:Direct3d中一套骨骼是以树形结构存放的,有两个关键的结构体和一个接口。
                    1:typedef struct _D3DXFRAME
                            {
                                LPSTR                   Name;
                                D3DXMATRIX              TransformationMatrix;

                                LPD3DXMESHCONTAINER     pMeshContainer;

                                struct _D3DXFRAME       *pFrameSibling;
                                struct _D3DXFRAME       *pFrameFirstChild;
                            } D3DXFRAME, *LPD3DXFRAME;
                        这个结构体代表了一块骨骼,有一个标识的Name,变换矩阵TransformationMatrix对应于之前所说的LocalTransformMatrix,还有分别指向兄弟结点和第一个孩子结点的指针,最后是包含了一个指向D3DXMESHCONTAINER结构体的指针,这是第二个关键的结构体。
                    2:typedef struct _D3DXMESHCONTAINER
                            {
                                LPSTR                   Name;

                                D3DXMESHDATA            MeshData;

                                LPD3DXMATERIAL          pMaterials;
                                LPD3DXEFFECTINSTANCE    pEffects;
                                DWORD                   NumMaterials;
                                DWORD                  *pAdjacency;

                                LPD3DXSKININFO          pSkinInfo;

                                struct _D3DXMESHCONTAINER *pNextMeshContainer;
                            } D3DXMESHCONTAINER, *LPD3DXMESHCONTAINER;
                    对于这个结构体还是比较了解的,所以略。
                    3:ID3DXAllocateHierarchy 接口,这个接口只包含四个纯虚函数,我们需要去重写他们,这些函数无需我们自己调用,在我们使用D3DXLoadMeshHierarchyFromX()接口加载SkineMesh数据是自动调用。

                    4:D3DXLoadMeshHierarchyFromX  (
    LPCWSTR Filename,
    DWORD MeshOptions,
    LPDIRECT3DDEVICE9 pD3DDevice,
    LPD3DXALLOCATEHIERARCHY pAlloc,
    LPD3DXLOADUSERDATA pUserDataLoader, 
    LPD3DXFRAME *ppFrameHierarchy,
    LPD3DXANIMATIONCONTROLLER   *ppAnimController
    );
有几个关键的参数:pAlloc,这是一个指向3中所说的
ID3DXAllocateHierarchy 接口的指针;ppFrameHierarchy,骨骼层次,也就是一个代表骨骼的树,是一个返回值;ppAnimController,这是动画控制器,是一个返回值,利用这个动画控制器就可以对SkinMesh进行控制。
     蒙皮骨骼动画的渲染:渲染这部分比较简单,递归渲染每个MeshContainer,这样说可能很奇怪,因为每个骨骼结构体(D3DXFRAME)都包含了一个指向MeshContainer的指针,而每次渲染每个MeshContainer都是整副骨骼进行设置纹理和材质,然后就有问题了?这不是重复渲染了?百度,google和经自己调试发现,网上并没有找到标准答案,就是大多时候一个骨骼的MeshContainer指针都是空的,我在调试时候只有骨骼Name为空字符串时MeshContainer不为空,所以只渲染了一次,哦,我的模型是tiny.x。最后我估计:一套骨骼中也许只有一个或几个不为空的MeshContainer指针,通常是一个如果没必要分割渲染的话,递归只是为了寻找这个不为空的pMeshContainer.

笔记到此先告一段落,由于理解只在十分基本的层面,没法就很多细节进行分析,故在此只记录十分表面的东西,以后补足。PS:笔记主要参考《Direct3D游戏开发技术详解》,MSDN


参考:Direct3D游戏开发技术详解 和 SDK simple 简单的加载了tiny.x动画,只实现了SOFTWARE处理方式和走路的动画。

[cpp]  view plain copy
  1. #include "CLD3D.h"  
  2. #include <stdio.h>  
  3.   
  4. //常量  
  5. const wchar_t wndName[50] = L"蒙皮骨骼动画演示";  
  6. const wchar_t wndTitle[100] = L"【Direct3D】——蒙皮骨骼动画演示-coderling";  
  7. const wchar_t xFileName[20] = L"tiny.x";  
  8. const unsigned int wndWidth = 800;  
  9. const unsigned int wndHeight = 600;  
  10.   
  11. //为每个骨骼添加一个控制矩阵  
  12. struct D3DXFRAME_EX: public D3DXFRAME  
  13. {  
  14.     D3DXMATRIXA16 combinedTransformtionMatrix;   
  15. };  
  16.   
  17. //保存蒙皮骨骼动画的结构体,包含网格模型  
  18. struct D3DXMESHCONTAINER_EX: public D3DXMESHCONTAINER  
  19. {  
  20.     LPDIRECT3DTEXTURE9* ppTextures; //指向纹理信息指针的指针数组  
  21.   
  22.     //蒙皮骨骼信息  
  23.     LPD3DXMESH pOrigMesh;  
  24.     LPD3DXATTRIBUTERANGE pAttributeTable; //子集分布表格?  
  25.     DWORD numAttributeGroups;  
  26.     DWORD numInfl;  
  27.     LPD3DXBUFFER pBoneCombinatonBuf; //骨骼名字缓冲区  
  28.     D3DXMATRIX** ppBoneMatrixPtrs; //最终变换矩阵  
  29.     D3DXMATRIX* pBoneOffsetMatrices; //offset矩阵数组指针  
  30.     DWORD numPaletteEntries;  
  31.     //bool useSoftwareVP;  
  32.   
  33.   
  34. };  
  35.   
  36. HRESULT GenerateSkinnedMesh( D3DXMESHCONTAINER_EX* );  
  37.   
  38. //重写ID3DXAllocateHierarchy接口  
  39. class CAllocateHierarchy: public ID3DXAllocateHierarchy  
  40. {  
  41. public:  
  42.     STDMETHOD(CreateFrame)( THIS_ LPCSTR name, LPD3DXFRAME* ppNewFrame );  
  43.     STDMETHOD(CreateMeshContainer)( THIS_  
  44.         LPCSTR Name,  
  45.         CONST D3DXMESHDATA* pMeshData,  
  46.         CONST D3DXMATERIAL* pMaterials,  
  47.         CONST D3DXEFFECTINSTANCE* pEffectInstance,  
  48.         DWORD numMaterials,  
  49.         CONST DWORD* pAdjacency,  
  50.         LPD3DXSKININFO pSkinInfo,  
  51.         LPD3DXMESHCONTAINER* ppNewMeshContainer );  
  52.     STDMETHOD(DestroyFrame)( THIS_ LPD3DXFRAME pFrameToFree );  
  53.     STDMETHOD(DestroyMeshContainer)( THIS_ LPD3DXMESHCONTAINER pMeshContainer );  
  54.   
  55. };  
  56.   
  57. //创建新的帧  
  58. HRESULT CAllocateHierarchy::CreateFrame( LPCSTR name, LPD3DXFRAME* ppNewFrame )  
  59. {  
  60.     HRESULT hr = S_OK;  
  61.   
  62.     D3DXFRAME_EX *pFrame;  
  63.   
  64.     *ppNewFrame = NULL;  
  65.       
  66.     pFrame = new D3DXFRAME_EX;  
  67.     if( pFrame == NULL )  
  68.     {  
  69.         hr = E_OUTOFMEMORY;  
  70.         return hr;  
  71.     }  
  72.   
  73.     if( name )  
  74.     {  
  75.         unsigned int len = strlen( name ) + 1;  
  76.         pFrame->Name = new char[len];  
  77.         memcpy( pFrame->Name, name, sizeof(char)*len );  
  78.     }  
  79.   
  80.     //初始化frame  
  81.     D3DXMatrixIdentity( &pFrame->TransformationMatrix );  
  82.     D3DXMatrixIdentity( &pFrame->combinedTransformtionMatrix );  
  83.   
  84.     pFrame->pMeshContainer = NULL;  
  85.     pFrame->pFrameFirstChild = NULL;  
  86.     pFrame->pFrameSibling = NULL;  
  87.   
  88.     *ppNewFrame = pFrame; //返回  
  89.   
  90.     pFrame = NULL;  
  91.   
  92.     return hr;  
  93. }  
  94.   
  95.   
  96. //创建新的meshcontainner  
  97. HRESULT CAllocateHierarchy::CreateMeshContainer(  
  98.     LPCSTR name,  
  99.     CONST D3DXMESHDATA* pMeshData,  
  100.     CONST D3DXMATERIAL* pMaterials,  
  101.     CONST D3DXEFFECTINSTANCE* pEffectInstances,  
  102.     DWORD numMaterials,  
  103.     CONST DWORD* pAdjacency,  
  104.     LPD3DXSKININFO pSkinInfo,  
  105.     LPD3DXMESHCONTAINER* ppNewMeshContainer )  
  106. {  
  107.     D3DXMESHCONTAINER_EX* pMeshContainer = NULL;  
  108.     unsigned int numFaces;  
  109.     unsigned int iMaterial;  
  110.     unsigned int iBone, cBones;  
  111.     LPDIRECT3DDEVICE9 pD3DDevice = NULL;  
  112.   
  113.     LPD3DXMESH pMesh = NULL;  
  114.       
  115.     *ppNewMeshContainer = NULL;  
  116.   
  117.     if( pMeshData->Type != D3DXMESHTYPE_MESH )  
  118.         return E_FAIL;  
  119.   
  120.     pMesh = pMeshData->pMesh;  
  121.   
  122.     if( pMesh->GetFVF() == 0 )  
  123.         return E_FAIL;  
  124.   
  125.     pMeshContainer = new D3DXMESHCONTAINER_EX;  
  126.     if( pMeshContainer == NULL )  
  127.         return E_FAIL;  
  128.     memset( pMeshContainer, 0, sizeof(D3DXMESHCONTAINER_EX) );  
  129.   
  130.     if( name )  
  131.     {  
  132.         unsigned int len = strlen( name ) + 1;  
  133.         pMeshContainer->Name = new char[len];  
  134.         memcpy( pMeshContainer->Name, name, sizeof(char)*len );  
  135.     }  
  136.   
  137.     pMesh->GetDevice( &pD3DDevice );  
  138.     numFaces = pMesh->GetNumFaces();  
  139.   
  140.     //添加顶点法线  
  141.     if( !( pMesh->GetFVF() & D3DFVF_NORMAL ) )  
  142.     {  
  143.         pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;  
  144.   
  145.         HRESULT hr = pMesh->CloneMeshFVF( pMesh->GetOptions(), pMesh->GetFVF() | D3DFVF_NORMAL,  
  146.                                           pD3DDevice, &pMeshContainer->MeshData.pMesh );  
  147.         if( FAILED( hr ) )  
  148.             return E_FAIL;  
  149.   
  150.         pMesh = pMeshContainer->MeshData.pMesh;  
  151.   
  152.         D3DXComputeNormals( pMesh, NULL );  
  153.   
  154.     }  
  155.     else  
  156.     {  
  157.         pMeshContainer->MeshData.pMesh = pMesh;  
  158.         pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;  
  159.   
  160.         pMesh->AddRef(); //增加引用计数  
  161.     }  
  162.   
  163.     pMeshContainer->NumMaterials = max( 1, numMaterials );  
  164.     pMeshContainer->pMaterials = new D3DXMATERIAL[pMeshContainer->NumMaterials];  
  165.     pMeshContainer->ppTextures = new LPDIRECT3DTEXTURE9[pMeshContainer->NumMaterials];  
  166.     pMeshContainer->pAdjacency = new DWORD[numFaces*3];  
  167.     if( (pMeshContainer->pAdjacency == NULL ) || ( pMeshContainer->pMaterials == NULL ) )  
  168.         return E_FAIL;  
  169.   
  170.     memcpy( pMeshContainer->pAdjacency, pAdjacency, sizeof(DWORD) * numFaces*3 );  
  171.     memset( pMeshContainer->ppTextures, 0, sizeof(LPDIRECT3DTEXTURE9) * pMeshContainer->NumMaterials );  
  172.   
  173.     if( numMaterials > 0 )  
  174.     {  
  175.         memcpy( pMeshContainer->pMaterials, pMaterials, sizeof(D3DXMATERIAL) * pMeshContainer->NumMaterials );  
  176.           
  177.         for( iMaterial = 0; iMaterial < numMaterials; iMaterial++ )  
  178.         {  
  179.             if( pMeshContainer->pMaterials[iMaterial].pTextureFilename != NULL )  
  180.             {  
  181.                 HRESULT hr = D3DXCreateTextureFromFileA( pD3DDevice,  
  182.                                 pMeshContainer->pMaterials[iMaterial].pTextureFilename,  
  183.                                 &pMeshContainer->ppTextures[iMaterial] );  
  184.                 if( FAILED( hr ) )  
  185.                     pMeshContainer->ppTextures[iMaterial] = NULL;  
  186.             }  
  187.         }  
  188.     }  
  189.     else  
  190.     {//默认  
  191.         pMeshContainer->pMaterials[0].pTextureFilename = NULL;  
  192.         memset( &pMeshContainer->pMaterials[0].MatD3D, 0, sizeof(D3DMATERIAL9) );  
  193.         pMeshContainer->pMaterials[0].MatD3D.Diffuse.r = 0.5f;  
  194.         pMeshContainer->pMaterials[0].MatD3D.Diffuse.g = 0.5f;  
  195.         pMeshContainer->pMaterials[0].MatD3D.Diffuse.b = 0.5f;  
  196.         pMeshContainer->pMaterials[0].MatD3D.Specular = pMeshContainer->pMaterials[0].MatD3D.Diffuse;  
  197.     }  
  198.   
  199.     if( pSkinInfo != NULL )  
  200.     {  
  201.         pMeshContainer->pSkinInfo = pSkinInfo;  
  202.         pSkinInfo->AddRef();  
  203.   
  204.         pMeshContainer->pOrigMesh = pMesh;  
  205.         pMesh->AddRef();  
  206.   
  207.         //  
  208.         cBones = pSkinInfo->GetNumBones();  
  209.         pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[cBones];  
  210.         if( pMeshContainer->pBoneOffsetMatrices == NULL )  
  211.             return E_FAIL;  
  212.   
  213.         //获得offsetmatrix  
  214.         for( iBone = 0; iBone < cBones; iBone++ )  
  215.         {  
  216.             pMeshContainer->pBoneOffsetMatrices[iBone] = *( pMeshContainer->pSkinInfo->GetBoneOffsetMatrix( iBone ) );  
  217.         }  
  218.   
  219.         HRESULT hr = GenerateSkinnedMesh( pMeshContainer );  
  220.         if( FAILED( hr ) )  
  221.             return E_FAIL;  
  222.     }  
  223.   
  224.     *ppNewMeshContainer = pMeshContainer;  
  225.   
  226.     //SAFE_RELEASE( pD3DDevice );  
  227.   
  228.     //if( pMeshContainer != NULL )  
  229.         //DestroyMeshContainer( pMeshContainer );  
  230.   
  231.     return S_OK;  
  232. }  
  233.   
  234. //销毁Frame  
  235. HRESULT CAllocateHierarchy::DestroyFrame( LPD3DXFRAME pFrameToFree )  
  236. {  
  237.     SAFE_DELETE_ARRAY( pFrameToFree->Name );  
  238.     SAFE_DELETE( pFrameToFree );  
  239.   
  240.     return S_OK;  
  241. }  
  242.   
  243. //销毁container  
  244. HRESULT CAllocateHierarchy::DestroyMeshContainer( LPD3DXMESHCONTAINER pMeshContainerBase )  
  245. {  
  246.     unsigned int iMaterial;  
  247.     D3DXMESHCONTAINER_EX* pMeshContainer = (D3DXMESHCONTAINER_EX*)pMeshContainerBase;  
  248.   
  249.     SAFE_DELETE_ARRAY( pMeshContainer->Name );  
  250.     SAFE_DELETE_ARRAY( pMeshContainer->pAdjacency );  
  251.     SAFE_DELETE_ARRAY( pMeshContainer->pMaterials );  
  252.     SAFE_DELETE_ARRAY( pMeshContainer->pBoneOffsetMatrices );  
  253.   
  254.     if( pMeshContainer->ppTextures != NULL )  
  255.     {  
  256.         for( iMaterial = 0; iMaterial< pMeshContainer->NumMaterials; iMaterial++ )  
  257.         {  
  258.             SAFE_RELEASE( pMeshContainer->ppTextures[iMaterial] );  
  259.         }  
  260.     }  
  261.   
  262.     SAFE_DELETE_ARRAY( pMeshContainer->ppTextures );  
  263.     SAFE_DELETE_ARRAY( pMeshContainer->ppBoneMatrixPtrs );  
  264.     SAFE_RELEASE( pMeshContainer->pBoneCombinatonBuf );  
  265.     SAFE_RELEASE( pMeshContainer->pSkinInfo );  
  266.     SAFE_RELEASE( pMeshContainer->pOrigMesh );  
  267.     SAFE_DELETE( pMeshContainer );  
  268.   
  269.     return S_OK;  
  270. }  
  271.   
  272.   
  273. //---------------我是分割线---------------------------------------------------------------------------------------------  
  274.   
  275. //全局变量  
  276. LPDIRECT3D9 g_pD3D = NULL; //direct3d对象用于创建direct设备  
  277. LPDIRECT3DDEVICE9 g_pD3DDevice = NULL; //direct3d设备指针  
  278. LPD3DXFONT g_pText = NULL;  
  279. LPD3DXFRAME g_pFrameRoot = NULL; //骨骼的根  
  280. LPD3DXANIMATIONCONTROLLER g_pAnimController; //动画控制句柄  
  281. double g_startTime = 0.0;  
  282. wchar_t* g_pAdapter = NULL;  
  283. unsigned int g_numBoneMatricesMax = 0;  
  284. D3DXMATRIXA16* g_pBoneMatrices = NULL;  
  285.   
  286. //相关函数声明  
  287. LRESULT WINAPI MsgProc( HWNDUINTWPARAMLPARAM );  
  288. HRESULT InitApp( HWNDHINSTANCE );  
  289. HRESULT InitGeometry(); //场景数据  
  290. VOID InitTranformMatrix(); //初始变换  
  291. HRESULT InitText(); //字体接口  
  292. VOID Render( HWND ); //渲染  
  293. VOID RenderText( HWND ); //渲染提示信息  
  294. VOID UpdateScene( HWND ); //更新场景  
  295. VOID UpdateFrameMatrices( const LPD3DXFRAME, const LPD3DXMATRIX ); //为个骨骼更新变换矩阵,每帧  
  296. VOID InitLight(); //设置光源  
  297. VOID Cleanup();   
  298. HRESULT SetupBoneMatrixPointers( LPD3DXFRAME ); //设置骨骼链中的混合数组到container中,方便访问  
  299. HRESULT SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER ); //  
  300. VOID DrawFrame( LPD3DXFRAME ); //绘制骨骼  
  301. VOID DrawMeshContainer( const LPD3DXMESHCONTAINER, const LPD3DXFRAME ); //绘制单个pMeshContainer  
  302.   
  303. int WINAPI WinMain( HINSTANCE hInst, HINSTANCE preInst, LPSTR lpCmdLine, int nCmdShow )  
  304. {  
  305. //设计并注册窗口类  
  306.     WNDCLASSEX wcEx = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,  
  307.                         GetModuleHandle( NULL ), NULL, NULL, NULL, NULL,  
  308.                         wndName, NULL };  
  309.     RegisterClassEx( &wcEx );  
  310.   
  311.     //创建窗口  
  312.     HWND hWnd = CreateWindow( wndName, wndTitle, WS_OVERLAPPEDWINDOW,  
  313.                               100, 100, wndWidth, wndHeight, GetDesktopWindow(),  
  314.                               NULL, hInst, NULL );  
  315.   
  316.     if( SUCCEEDED( InitApp( hWnd, hInst ) ) )  
  317.     {  
  318.         if( SUCCEEDED( InitGeometry() ) )  
  319.         {  
  320.             //显示并更新窗口  
  321.             ShowWindow( hWnd, SW_SHOWDEFAULT );  
  322.             UpdateWindow( hWnd );  
  323.   
  324.             //程序消息循环  
  325.             MSG msg;  
  326.             SecureZeroMemory( &msg, sizeof(msg) );  
  327.             while( msg.message != WM_QUIT )  
  328.             {  
  329.                 if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )  
  330.                 {  
  331.                     TranslateMessage( &msg );  
  332.                     DispatchMessage( &msg );  
  333.                 }  
  334.                 else  
  335.                     Render( hWnd );  
  336.             }  
  337.         }  
  338.     }  
  339.   
  340.     UnregisterClass( wndName, wcEx.hInstance );  
  341.     return 0;  
  342. }  
  343.   
  344. LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )  
  345. {  
  346.     switch( msg )  
  347.     {  
  348.     case WM_KEYDOWN:  
  349.         if( wParam == VK_ESCAPE )  
  350.             DestroyWindow( hWnd );  
  351.         break;  
  352.     case WM_DESTROY:  
  353.         Cleanup();  
  354.         PostQuitMessage(0);  
  355.         break;  
  356.     default:  
  357.         return DefWindowProc( hWnd, msg, wParam, lParam );  
  358.     }  
  359.     return S_OK;  
  360. }  
  361.   
  362. HRESULT InitApp( HWND hWnd , HINSTANCE hInst )  
  363. {  
  364.     //创建direct3d对象  
  365.     if( FAILED( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION )) )  
  366.         return E_FAIL;  
  367.   
  368.     //填写Direct3dDevice配置参数  
  369.     D3DPRESENT_PARAMETERS d3dpp;  
  370.     SecureZeroMemory( &d3dpp, sizeof(d3dpp) );  
  371.     d3dpp.BackBufferWidth = wndWidth;  
  372.     d3dpp.BackBufferHeight = wndHeight;  
  373.     d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;  
  374.     d3dpp.BackBufferCount = 1; //缓冲数  
  375.     d3dpp.hDeviceWindow = hWnd;  
  376.     d3dpp.Windowed = true;  
  377.     d3dpp.EnableAutoDepthStencil = true//开启深度缓冲  
  378.     d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;  
  379.     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;  
  380.     d3dpp.Flags = 0;  
  381.     d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;  
  382.     d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;  
  383.   
  384.     //检测硬件  
  385.     D3DCAPS9 caps;  
  386.     g_pD3D->GetDeviceCaps( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps );  
  387.     int vp = 0;  
  388.     if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )  
  389.         vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;  
  390.     else  
  391.         vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;  
  392.   
  393.     //创建Direct3d设备  
  394.     if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,  
  395.                 hWnd, vp, &d3dpp, &g_pD3DDevice ) ) )  
  396.     {  
  397.         return E_FAIL;  
  398.     }  
  399.   
  400.     InitText();  
  401.   
  402.     g_startTime = (double)timeGetTime();  
  403.   
  404.     return S_OK;  
  405. }  
  406.   
  407. HRESULT InitGeometry()  
  408. {  
  409.     HRESULT hr;  
  410.     CAllocateHierarchy alloc;  
  411.   
  412.     hr = D3DXLoadMeshHierarchyFromX( xFileName, D3DXMESH_MANAGED, g_pD3DDevice, &alloc, NULL, &g_pFrameRoot, &g_pAnimController );  
  413.     if( FAILED( hr ) )  
  414.         return E_FAIL;  
  415.       
  416.     //设置骨骼链中的混合矩阵到Container中,方便访问  
  417.     hr = SetupBoneMatrixPointers( g_pFrameRoot );  
  418.   
  419.     InitLight();  
  420.       
  421.     InitTranformMatrix();  
  422.     g_pD3DDevice->SetRenderState( D3DRS_NORMALIZENORMALS, true ); //标准化顶点法线  
  423.     //g_pD3DDevice->SetRenderState( D3DRS_SPECULARENABLE, true ); //开启镜面光  
  424.   
  425.     //显卡信息  
  426.     wchar_t adapterTemp[200] = L"显卡型号:";  
  427.     D3DADAPTER_IDENTIFIER9 adapter; //获取显卡信息的结构体  
  428.     g_pAdapter = new wchar_t[200];  
  429.     g_pD3D->GetAdapterIdentifier( 0, 0, &adapter ); //获取显卡信息,保存在adapter中  
  430.   
  431.     //将char*转化为wchar_t*  
  432.     int len = MultiByteToWideChar( CP_ACP, 0, adapter.Description, -1, NULL, 0 );  
  433.     MultiByteToWideChar( CP_ACP, 0, adapter.Description, -1, g_pAdapter, len );  
  434.     wcscat_s(adapterTemp,g_pAdapter ); //链接两个字符串  
  435.     memcpy( g_pAdapter, adapterTemp, sizeof(adapterTemp) ); //从新拷贝回g_pAdapter  
  436.   
  437.   
  438.     return S_OK;  
  439. }  
  440.   
  441. VOID InitTranformMatrix()  
  442. {  
  443.     D3DXMATRIX matWorld;  
  444.     D3DXMatrixIdentity( &matWorld );  
  445.     g_pD3DDevice->SetTransform( D3DTS_WORLD, &matWorld );  
  446.   
  447.     // 摄像机  
  448.     D3DXVECTOR3 pos(100.0f, 100.0f, -250.0f);  
  449.     D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);  
  450.     D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);  
  451.     //g_camera.ReSetting( &pos, &target, &up );  
  452.   
  453.     //D3DXVECTOR3 right( 1.0f, 0.0f, 0.0f);  
  454.     D3DXMATRIX V;  
  455.     //g_camera.GetViewMatrix( &V );  
  456.     D3DXMatrixLookAtLH(  
  457.         &V,  
  458.         &pos,  
  459.         &target,  
  460.         &up);  
  461.     g_pD3DDevice->SetTransform(D3DTS_VIEW, &V);  
  462.       
  463.     // 设置投影变换矩阵.  
  464.     D3DXMATRIX proj;  
  465.     D3DXMatrixPerspectiveFovLH(  
  466.             &proj,  
  467.             D3DX_PI * 0.5f,   
  468.             (float)wndWidth/ (float)wndHeight,  
  469.             1.0f,  
  470.             1000.0f);  
  471.     g_pD3DDevice->SetTransform(D3DTS_PROJECTION, &proj);  
  472.   
  473.     //视口剪切矩阵,实现视口变换  
  474.     D3DVIEWPORT9 vp;  
  475.     vp.X = 0;  
  476.     vp.Y = 0;  
  477.     vp.Width = wndWidth;  
  478.     vp.Height = wndHeight;  
  479.     vp.MinZ = 0;  
  480.     vp.MaxZ = 1;  
  481.     g_pD3DDevice->SetViewport( &vp );  
  482. }  
  483.   
  484. HRESULT InitText()  
  485. {  
  486.     HRESULT hr;  
  487.     //创建字体  
  488.     hr = D3DXCreateFont( g_pD3DDevice, 25, 0, 1000, 0, false,  
  489.                     DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,  
  490.                     DEFAULT_QUALITY, 0, L"微软雅黑", &g_pText );  
  491.   
  492.     return hr;  
  493. }  
  494.   
  495. VOID Render( HWND hWnd )  
  496. {  
  497.     if( NULL == g_pD3DDevice )  
  498.         return ;  
  499.     //清屏  
  500.     g_pD3DDevice->Clear( 0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,  
  501.                          D3DCOLOR_XRGB( 28, 154, 207 ), 1.0f, 0 );  
  502.   
  503.     if( SUCCEEDED( g_pD3DDevice->BeginScene() ) )  
  504.     {  
  505.         UpdateScene( hWnd );  
  506.         DrawFrame( g_pFrameRoot ); //绘制骨骼动画  
  507.   
  508.         RenderText( hWnd );  
  509.         g_pD3DDevice->EndScene();  
  510.     }  
  511.   
  512.     g_pD3DDevice->Present( NULL, NULL, NULL, NULL );  
  513.     //::Sleep(10000);  
  514. }  
  515.   
  516. //递归绘制骨骼动画  
  517. VOID DrawFrame( LPD3DXFRAME pFrame )  
  518. {  
  519.     LPD3DXMESHCONTAINER pMeshContainer;  
  520.   
  521.     pMeshContainer = pFrame->pMeshContainer;  
  522.     while( pMeshContainer != NULL )  
  523.     {  
  524.         DrawMeshContainer( pMeshContainer, pFrame );  
  525.         pMeshContainer = pMeshContainer->pNextMeshContainer;  
  526.     }  
  527.   
  528.     if( pFrame->pFrameSibling != NULL )  
  529.     {  
  530.         DrawFrame( pFrame->pFrameSibling );  
  531.     }  
  532.   
  533.     if( pFrame->pFrameFirstChild != NULL )  
  534.     {  
  535.         DrawFrame( pFrame->pFrameFirstChild );  
  536.     }  
  537. }  
  538.   
  539. //绘制单个pMeshContainer  
  540. VOID DrawMeshContainer( const LPD3DXMESHCONTAINER pMeshContainerBase, const LPD3DXFRAME pFrameBase )  
  541. {  
  542.     D3DXMESHCONTAINER_EX* pMeshContainer = (D3DXMESHCONTAINER_EX*)pMeshContainerBase;  
  543.     D3DXFRAME_EX* pFrame = (D3DXFRAME_EX*)pFrameBase;  
  544.     unsigned int iMaterial;  
  545.     //unsigned int numBlend;  
  546.     unsigned int iAttrib;  
  547.     //DWORD attribIdPrev;  
  548.     //LPD3DXBONECOMBINATION pBoneComb;  
  549.   
  550.     //unsigned int iMatrixIndex;  
  551.     //unsigned int iPaletteEntry;  
  552.     D3DXMATRIXA16 matTemp;  
  553.   
  554.       
  555.     if( pMeshContainer->pSkinInfo != NULL )  
  556.     {  
  557.         //只采用软件处理方式  
  558.         //D3DXMATRIX Identity;  
  559.         DWORD cBones = pMeshContainer->pSkinInfo->GetNumBones();  
  560.         DWORD iBone;  
  561.         PBYTE pbVerticesSrc;  
  562.         PBYTE pbVerticesDest;  
  563.   
  564.         //D3DXMATRIX* pBoneMatrices = new D3DXMATRIX[cBones];  
  565.         for( iBone = 0; iBone < cBones; ++iBone )  
  566.         {  
  567.             D3DXMatrixMultiply(  
  568.                 &g_pBoneMatrices[iBone],  
  569.                 &pMeshContainer->pBoneOffsetMatrices[iBone],  
  570.                 pMeshContainer->ppBoneMatrixPtrs[iBone]   
  571.             );  
  572.         }  
  573.   
  574.         pMeshContainer->pOrigMesh->LockVertexBuffer( D3DLOCK_READONLY, (LPVOID*)&pbVerticesSrc );  
  575.         pMeshContainer->MeshData.pMesh->LockVertexBuffer( 0, (LPVOID*)&pbVerticesDest );  
  576.   
  577.         pMeshContainer->pSkinInfo->UpdateSkinnedMesh( g_pBoneMatrices, NULL, pbVerticesSrc, pbVerticesDest );  
  578.   
  579.         //delete[] pBoneMatrices;  
  580.         //pBoneMatrices = NULL;  
  581.   
  582.         pMeshContainer->pOrigMesh->UnlockVertexBuffer();  
  583.         pMeshContainer->MeshData.pMesh->UnlockVertexBuffer();  
  584.           
  585.         for( iAttrib = 0; iAttrib < pMeshContainer->numAttributeGroups; iAttrib++ )  
  586.         {  
  587.             g_pD3DDevice->SetMaterial( &( pMeshContainer->pMaterials[pMeshContainer->pAttributeTable[iAttrib].AttribId].MatD3D ) );  
  588.             g_pD3DDevice->SetTexture( 0, pMeshContainer->ppTextures[pMeshContainer->pAttributeTable[iAttrib].AttribId]);  
  589.             pMeshContainer->MeshData.pMesh->DrawSubset( pMeshContainer->pAttributeTable[iAttrib].AttribId);  
  590.         }  
  591.     }  
  592.     else  
  593.     {  
  594.         for( iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++ )  
  595.         {  
  596.             g_pD3DDevice->SetMaterial( &pMeshContainer->pMaterials[iMaterial].MatD3D );  
  597.             g_pD3DDevice->SetTexture( 0, pMeshContainer->ppTextures[iMaterial] );  
  598.             pMeshContainer->MeshData.pMesh->DrawSubset( iMaterial );  
  599.         }  
  600.     }  
  601. }  
  602.   
  603. VOID RenderText( HWND hWnd )  
  604. {  
  605.     RECT clientRect;  
  606.     GetClientRect( hWnd, &clientRect );  
  607.   
  608.     //-绘制显卡信息  
  609.     g_pText->DrawText( NULL, g_pAdapter, -1, &clientRect,  
  610.                     DT_TOP | DT_LEFT, D3DXCOLOR( 1.0f, 0.0f, 0.0f, 1.0f ) );  
  611.   
  612.     //绘制FPS  
  613.     wchar_t strFPS[20];  
  614.     int len = swprintf_s(strFPS, 20, L"FPS:%.3f", GetFPS());  
  615.     g_pText->DrawText( NULL, strFPS, len, &clientRect, DT_TOP | DT_RIGHT,  
  616.                     D3DXCOLOR( 0.0f, 1.0f, 0.0f, 1.0f ) );  
  617.   
  618. }  
  619.   
  620. VOID UpdateScene( HWND hWnd )  
  621. {  
  622.     if( g_pAnimController != NULL )  
  623.     {  
  624.         double time = (double)timeGetTime();  
  625.         time = ( time - g_startTime ) * 0.001;  
  626.         g_startTime = (double)timeGetTime();  
  627.         g_pAnimController->AdvanceTime( time, NULL );  
  628.     }  
  629.   
  630.     D3DXMATRIX matWorld;  
  631.     //D3DXMatrixIdentity( &matWorld );  
  632.     g_pD3DDevice->GetTransform( D3DTS_WORLD, &matWorld );  
  633.     UpdateFrameMatrices( g_pFrameRoot, &matWorld );  
  634. }  
  635.       
  636.       
  637.   
  638. VOID UpdateFrameMatrices( const LPD3DXFRAME pFrameBase, const LPD3DXMATRIX pParentMatrix )  
  639. {  
  640.     D3DXFRAME_EX* pFrame = (D3DXFRAME_EX*)pFrameBase;  
  641.   
  642.     if( pParentMatrix != NULL )  
  643.         D3DXMatrixMultiply( &pFrame->combinedTransformtionMatrix, &pFrame->TransformationMatrix, pParentMatrix );  
  644.     else  
  645.         pFrame->combinedTransformtionMatrix = pFrame->TransformationMatrix;  
  646.       
  647.     if( pFrame->pFrameSibling != NULL )  
  648.     {  
  649.         UpdateFrameMatrices( pFrame->pFrameSibling, pParentMatrix );  
  650.     }  
  651.   
  652.     if( pFrame->pFrameFirstChild != NULL )  
  653.     {  
  654.         UpdateFrameMatrices( pFrame->pFrameFirstChild, &pFrame->combinedTransformtionMatrix );  
  655.     }  
  656. }  
  657.   
  658. VOID InitLight()  
  659. {  
  660.         //------------------------------  
  661.     //-1、填写D3DLIGHT9结构体  
  662.     //-2、SetLinght  
  663.     //-3、LightEnable  
  664.     //-----------------------------  
  665.       
  666.     //填写光源结构体  
  667.     D3DLIGHT9 pointLight;  
  668.     SecureZeroMemory( &pointLight, sizeof(pointLight) );  
  669.     D3DXCOLOR white = D3DCOLOR_RGBA( 255, 255, 255, 255 );  
  670.     D3DXCOLOR black = D3DCOLOR_RGBA( 0, 0, 0, 0 );  
  671.     pointLight.Type = D3DLIGHT_POINT;  
  672.     pointLight.Ambient = white*0.4f;  
  673.     pointLight.Diffuse = white;  
  674.     pointLight.Specular = white*0.6f;  
  675.     pointLight.Position = D3DXVECTOR3( 200.0f, 200.0f, 0.0f ); //根据需要进行更改  
  676.     pointLight.Range = 500.0f;  
  677.     pointLight.Attenuation0 = 1.0f;  
  678.     pointLight.Attenuation1 = 0.0f;  
  679.     pointLight.Attenuation2 = 0.0f;  
  680.   
  681.     g_pD3DDevice->SetLight( 0, &pointLight );  
  682.     g_pD3DDevice->LightEnable( 0, true );  
  683. }  
  684.   
  685. VOID Cleanup()  
  686. {  
  687.     SAFE_DELETE( g_pAdapter );  
  688.     SAFE_RELEASE( g_pD3D );  
  689.     SAFE_RELEASE( g_pD3DDevice );  
  690.     SAFE_RELEASE( g_pText );  
  691.     SAFE_RELEASE( g_pAnimController );  
  692.       
  693.   
  694.     if( g_pFrameRoot != NULL )  
  695.     {  
  696.         CAllocateHierarchy alloc;  
  697.         D3DXFrameDestroy( g_pFrameRoot, &alloc );  
  698.         g_pFrameRoot = NULL;  
  699.     }  
  700. }  
  701.   
  702. //递归设置骨骼链的混合数组  
  703. HRESULT SetupBoneMatrixPointers( LPD3DXFRAME pFrame )  
  704. {  
  705.     HRESULT hr;  
  706.     if( pFrame->pMeshContainer != NULL )  
  707.     {  
  708.         hr = SetupBoneMatrixPointersOnMesh( pFrame->pMeshContainer );  
  709.         if( FAILED( hr ) )  
  710.             return hr;  
  711.     }  
  712.   
  713.     if( pFrame->pFrameSibling != NULL )  
  714.     {  
  715.         hr = SetupBoneMatrixPointers( pFrame->pFrameSibling );  
  716.         if( FAILED( hr ) )  
  717.             return hr;  
  718.     }  
  719.   
  720.     if( pFrame->pFrameFirstChild != NULL )  
  721.     {  
  722.         hr = SetupBoneMatrixPointers( pFrame->pFrameFirstChild );  
  723.         if( FAILED( hr ) )  
  724.             return hr;  
  725.     }  
  726.   
  727.     return S_OK;  
  728. }  
  729.   
  730. HRESULT SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER pMeshContainerBase )  
  731. {  
  732.     unsigned int iBone;  
  733.     unsigned int cBones;  
  734.     D3DXFRAME_EX* pFrame;  
  735.   
  736.     D3DXMESHCONTAINER_EX* pMeshContainer = ( D3DXMESHCONTAINER_EX* )pMeshContainerBase;  
  737.       
  738.     //如果是骨骼动画  
  739.     if( pMeshContainer->pSkinInfo != NULL )  
  740.     {  
  741.         cBones = pMeshContainer->pSkinInfo->GetNumBones();  
  742.   
  743.         pMeshContainer->ppBoneMatrixPtrs = new D3DXMATRIX*[cBones];  
  744.         if( pMeshContainer->ppBoneMatrixPtrs == NULL )  
  745.             return E_OUTOFMEMORY;  
  746.   
  747.         for( iBone = 0; iBone < cBones; iBone++ )  
  748.         {  
  749.             //根据骨骼名字寻找对应骨骼  
  750.             pFrame = (D3DXFRAME_EX*)D3DXFrameFind( g_pFrameRoot, pMeshContainer->pSkinInfo->GetBoneName( iBone ) );  
  751.             if( pFrame == NULL )  
  752.                 return E_FAIL;  
  753.   
  754.             pMeshContainer->ppBoneMatrixPtrs[iBone] = &pFrame->combinedTransformtionMatrix;  
  755.         }  
  756.     }  
  757.   
  758.     //--------  
  759.     /*HRESULT hr = pMeshContainer->MeshData.pMesh->GetAttributeTable( NULL, &pMeshContainer->numAttributeGroups ); 
  760.     if( FAILED( hr ) ) 
  761.         return E_FAIL; 
  762.     pMeshContainer->pAttributeTable = new D3DXATTRIBUTERANGE[pMeshContainer->numAttributeGroups]; 
  763.     if( pMeshContainer->pAttributeTable == NULL ) 
  764.         return E_FAIL; 
  765.     hr = pMeshContainer->MeshData.pMesh->GetAttributeTable( pMeshContainer->pAttributeTable, NULL ); 
  766.     if( FAILED( hr ) ) 
  767.         return E_FAIL;*/  
  768.   
  769.   
  770.     return S_OK;  
  771. }  
  772.   
  773. //在SkinMesh加载或者改变渲染方式时是调用  
  774. HRESULT GenerateSkinnedMesh( D3DXMESHCONTAINER_EX* pMeshContainer )  
  775. {  
  776.     HRESULT hr = S_OK;  
  777.   
  778.     if( pMeshContainer->pSkinInfo == NULL )  
  779.         return hr;  
  780.     SAFE_RELEASE( pMeshContainer->MeshData.pMesh );  
  781.     SAFE_RELEASE( pMeshContainer->pBoneCombinatonBuf );  
  782.   
  783.     hr = pMeshContainer->pOrigMesh->CloneMeshFVF( D3DXMESH_MANAGED, pMeshContainer->pOrigMesh->GetFVF(),  
  784.                                                 g_pD3DDevice, &pMeshContainer->MeshData.pMesh );  
  785.     if( FAILED(hr) )  
  786.         return hr;  
  787.   
  788.     hr = pMeshContainer->MeshData.pMesh->GetAttributeTable( NULL, &pMeshContainer->numAttributeGroups );  
  789.     if( FAILED(hr) )  
  790.         return hr;  
  791.   
  792.     delete[] pMeshContainer->pAttributeTable;  
  793.     pMeshContainer->pAttributeTable = new D3DXATTRIBUTERANGE[pMeshContainer->numAttributeGroups];  
  794.     if( pMeshContainer->pAttributeTable == NULL )  
  795.         return E_OUTOFMEMORY;  
  796.   
  797.     hr = pMeshContainer->MeshData.pMesh->GetAttributeTable( pMeshContainer->pAttributeTable, NULL );  
  798.     if( FAILED(hr) )  
  799.         return hr;  
  800.   
  801.     if( g_numBoneMatricesMax < pMeshContainer->pSkinInfo->GetNumBones() )  
  802.     {  
  803.         g_numBoneMatricesMax = pMeshContainer->pSkinInfo->GetNumBones();  
  804.   
  805.         //为材质分配空间  
  806.         g_pBoneMatrices = new D3DXMATRIXA16[g_numBoneMatricesMax];  
  807.         if( g_pBoneMatrices == NULL )  
  808.             return E_OUTOFMEMORY;  
  809.     }  
  810.   
  811.     return hr;  
  812. }  




原文来自:http://blog.csdn.net/coderling/article/details/10168277

你可能感兴趣的:(动画,3D,DirectX,网格,骨骼)