您的位置:首页 > 其它

【Direct3D游戏开发】——蒙皮骨骼动画学习笔记

2013-08-22 18:01 495 查看
蒙皮骨骼动画

一、蒙皮骨骼动画原理:蒙皮骨骼动画的思想来源于自然界,大多数动物都拥有一套骨骼,骨骼是身体的框架,身体的皮毛血肉都是依附于骨骼。当骨骼开始运动的时候,依附于对应骨骼的皮毛血肉都会随骨骼一起运动。而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处理方式和走路的动画。

#include "CLD3D.h"
#include <stdio.h>

//常量
const wchar_t wndName[50] = L"蒙皮骨骼动画演示";
const wchar_t wndTitle[100] = L"【Direct3D】——蒙皮骨骼动画演示-coderling";
const wchar_t xFileName[20] = L"tiny.x";
const unsigned int wndWidth = 800;
const unsigned int wndHeight = 600;

//为每个骨骼添加一个控制矩阵
struct D3DXFRAME_EX: public D3DXFRAME
{
D3DXMATRIXA16 combinedTransformtionMatrix;
};

//保存蒙皮骨骼动画的结构体,包含网格模型
struct D3DXMESHCONTAINER_EX: public D3DXMESHCONTAINER
{
LPDIRECT3DTEXTURE9* ppTextures; //指向纹理信息指针的指针数组

//蒙皮骨骼信息
LPD3DXMESH pOrigMesh;
LPD3DXATTRIBUTERANGE pAttributeTable; //子集分布表格?
DWORD numAttributeGroups;
DWORD numInfl;
LPD3DXBUFFER pBoneCombinatonBuf; //骨骼名字缓冲区
D3DXMATRIX** ppBoneMatrixPtrs; //最终变换矩阵
D3DXMATRIX* pBoneOffsetMatrices; //offset矩阵数组指针
DWORD numPaletteEntries;
//bool useSoftwareVP;

};

HRESULT GenerateSkinnedMesh( D3DXMESHCONTAINER_EX* );

//重写ID3DXAllocateHierarchy接口
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* pEffectInstance,
DWORD numMaterials,
CONST DWORD* pAdjacency,
LPD3DXSKININFO pSkinInfo,
LPD3DXMESHCONTAINER* ppNewMeshContainer );
STDMETHOD(DestroyFrame)( THIS_ LPD3DXFRAME pFrameToFree );
STDMETHOD(DestroyMeshContainer)( THIS_ LPD3DXMESHCONTAINER pMeshContainer );

};

//创建新的帧
HRESULT CAllocateHierarchy::CreateFrame( LPCSTR name, LPD3DXFRAME* ppNewFrame )
{
HRESULT hr = S_OK;

D3DXFRAME_EX *pFrame;

*ppNewFrame = NULL;

pFrame = new D3DXFRAME_EX;
if( pFrame == NULL )
{
hr = E_OUTOFMEMORY;
return hr;
}

if( name )
{
unsigned int len = strlen( name ) + 1;
pFrame->Name = new char[len];
memcpy( pFrame->Name, name, sizeof(char)*len );
}

//初始化frame
D3DXMatrixIdentity( &pFrame->TransformationMatrix );
D3DXMatrixIdentity( &pFrame->combinedTransformtionMatrix );

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

*ppNewFrame = pFrame; //返回

pFrame = NULL;

return hr;
}

//创建新的meshcontainner
HRESULT CAllocateHierarchy::CreateMeshContainer(
LPCSTR name,
CONST D3DXMESHDATA* pMeshData,
CONST D3DXMATERIAL* pMaterials,
CONST D3DXEFFECTINSTANCE* pEffectInstances,
DWORD numMaterials,
CONST DWORD* pAdjacency,
LPD3DXSKININFO pSkinInfo,
LPD3DXMESHCONTAINER* ppNewMeshContainer )
{
D3DXMESHCONTAINER_EX* pMeshContainer = NULL;
unsigned int numFaces;
unsigned int iMaterial;
unsigned int iBone, cBones;
LPDIRECT3DDEVICE9 pD3DDevice = NULL;

LPD3DXMESH pMesh = NULL;

*ppNewMeshContainer = NULL;

if( pMeshData->Type != D3DXMESHTYPE_MESH )
return E_FAIL;

pMesh = pMeshData->pMesh;

if( pMesh->GetFVF() == 0 )
return E_FAIL;

pMeshContainer = new D3DXMESHCONTAINER_EX;
if( pMeshContainer == NULL )
return E_FAIL;
memset( pMeshContainer, 0, sizeof(D3DXMESHCONTAINER_EX) );

if( name )
{
unsigned int len = strlen( name ) + 1;
pMeshContainer->Name = new char[len];
memcpy( pMeshContainer->Name, name, sizeof(char)*len );
}

pMesh->GetDevice( &pD3DDevice );
numFaces = pMesh->GetNumFaces();

//添加顶点法线
if( !( pMesh->GetFVF() & D3DFVF_NORMAL ) )
{
pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;

HRESULT hr = pMesh->CloneMeshFVF( pMesh->GetOptions(), pMesh->GetFVF() | D3DFVF_NORMAL,
pD3DDevice, &pMeshContainer->MeshData.pMesh );
if( FAILED( hr ) )
return E_FAIL;

pMesh = pMeshContainer->MeshData.pMesh;

D3DXComputeNormals( pMesh, NULL );

}
else
{
pMeshContainer->MeshData.pMesh = pMesh;
pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;

pMesh->AddRef(); //增加引用计数
}

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 ) )
return E_FAIL;

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) * pMeshContainer->NumMaterials );

for( iMaterial = 0; iMaterial < numMaterials; iMaterial++ )
{
if( pMeshContainer->pMaterials[iMaterial].pTextureFilename != NULL )
{
HRESULT hr = D3DXCreateTextureFromFileA( pD3DDevice,
pMeshContainer->pMaterials[iMaterial].pTextureFilename,
&pMeshContainer->ppTextures[iMaterial] );
if( FAILED( hr ) )
pMeshContainer->ppTextures[iMaterial] = 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 )
return E_FAIL;

//获得offsetmatrix
for( iBone = 0; iBone < cBones; iBone++ )
{
pMeshContainer->pBoneOffsetMatrices[iBone] = *( pMeshContainer->pSkinInfo->GetBoneOffsetMatrix( iBone ) );
}

HRESULT hr = GenerateSkinnedMesh( pMeshContainer );
if( FAILED( hr ) )
return E_FAIL;
}

*ppNewMeshContainer = pMeshContainer;

//SAFE_RELEASE( pD3DDevice );

//if( pMeshContainer != NULL )
//DestroyMeshContainer( pMeshContainer );

return S_OK;
}

//销毁Frame
HRESULT CAllocateHierarchy::DestroyFrame( LPD3DXFRAME pFrameToFree )
{
SAFE_DELETE_ARRAY( pFrameToFree->Name );
SAFE_DELETE( pFrameToFree );

return S_OK;
}

//销毁container
HRESULT CAllocateHierarchy::DestroyMeshContainer( LPD3DXMESHCONTAINER pMeshContainerBase )
{
unsigned int iMaterial;
D3DXMESHCONTAINER_EX* pMeshContainer = (D3DXMESHCONTAINER_EX*)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->pBoneCombinatonBuf );
SAFE_RELEASE( pMeshContainer->pSkinInfo );
SAFE_RELEASE( pMeshContainer->pOrigMesh );
SAFE_DELETE( pMeshContainer );

return S_OK;
}

//---------------我是分割线---------------------------------------------------------------------------------------------

//全局变量
LPDIRECT3D9 g_pD3D = NULL; //direct3d对象用于创建direct设备
LPDIRECT3DDEVICE9 g_pD3DDevice = NULL; //direct3d设备指针
LPD3DXFONT g_pText = NULL;
LPD3DXFRAME g_pFrameRoot = NULL; //骨骼的根
LPD3DXANIMATIONCONTROLLER g_pAnimController; //动画控制句柄
double g_startTime = 0.0;
wchar_t* g_pAdapter = NULL;
unsigned int g_numBoneMatricesMax = 0;
D3DXMATRIXA16* g_pBoneMatrices = NULL;

//相关函数声明
LRESULT WINAPI MsgProc( HWND, UINT, WPARAM, LPARAM );
HRESULT InitApp( HWND, HINSTANCE );
HRESULT InitGeometry(); //场景数据
VOID InitTranformMatrix(); //初始变换
HRESULT InitText(); //字体接口
VOID Render( HWND ); //渲染
VOID RenderText( HWND ); //渲染提示信息
VOID UpdateScene( HWND ); //更新场景
VOID UpdateFrameMatrices( const LPD3DXFRAME, const LPD3DXMATRIX ); //为个骨骼更新变换矩阵,每帧
VOID InitLight(); //设置光源
VOID Cleanup();
HRESULT SetupBoneMatrixPointers( LPD3DXFRAME ); //设置骨骼链中的混合数组到container中,方便访问
HRESULT SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER ); //
VOID DrawFrame( LPD3DXFRAME ); //绘制骨骼
VOID DrawMeshContainer( const LPD3DXMESHCONTAINER, const LPD3DXFRAME ); //绘制单个pMeshContainer

int WINAPI WinMain( HINSTANCE hInst, HINSTANCE preInst, LPSTR lpCmdLine, int nCmdShow )
{
//设计并注册窗口类
WNDCLASSEX wcEx = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle( NULL ), NULL, NULL, NULL, NULL,
wndName, NULL };
RegisterClassEx( &wcEx );

//创建窗口
HWND hWnd = CreateWindow( wndName, wndTitle, WS_OVERLAPPEDWINDOW,
100, 100, wndWidth, wndHeight, GetDesktopWindow(),
NULL, hInst, NULL );

if( SUCCEEDED( InitApp( hWnd, hInst ) ) )
{
if( SUCCEEDED( InitGeometry() ) )
{
//显示并更新窗口
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );

//程序消息循环
MSG msg;
SecureZeroMemory( &msg, sizeof(msg) );
while( msg.message != WM_QUIT )
{
if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
Render( hWnd );
}
}
}

UnregisterClass( wndName, wcEx.hInstance );
return 0;
}

LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_KEYDOWN:
if( wParam == VK_ESCAPE )
DestroyWindow( hWnd );
break;
case WM_DESTROY:
Cleanup();
PostQuitMessage(0);
break;
default:
return DefWindowProc( hWnd, msg, wParam, lParam );
}
return S_OK;
}

HRESULT InitApp( HWND hWnd , HINSTANCE hInst )
{
//创建direct3d对象
if( FAILED( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION )) )
return E_FAIL;

//填写Direct3dDevice配置参数
D3DPRESENT_PARAMETERS d3dpp;
SecureZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.BackBufferWidth = wndWidth;
d3dpp.BackBufferHeight = wndHeight;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.BackBufferCount = 1; //缓冲数
d3dpp.hDeviceWindow = hWnd;
d3dpp.Windowed = true;
d3dpp.EnableAutoDepthStencil = true; //开启深度缓冲
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.Flags = 0;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

//检测硬件
D3DCAPS9 caps;
g_pD3D->GetDeviceCaps( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps );
int vp = 0;
if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

//创建Direct3d设备
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
hWnd, vp, &d3dpp, &g_pD3DDevice ) ) )
{
return E_FAIL;
}

InitText();

g_startTime = (double)timeGetTime();

return S_OK;
}

HRESULT InitGeometry()
{
HRESULT hr;
CAllocateHierarchy alloc;

hr = D3DXLoadMeshHierarchyFromX( xFileName, D3DXMESH_MANAGED, g_pD3DDevice, &alloc, NULL, &g_pFrameRoot, &g_pAnimController );
if( FAILED( hr ) )
return E_FAIL;

//设置骨骼链中的混合矩阵到Container中,方便访问
hr = SetupBoneMatrixPointers( g_pFrameRoot );

InitLight();

InitTranformMatrix();
g_pD3DDevice->SetRenderState( D3DRS_NORMALIZENORMALS, true ); //标准化顶点法线
//g_pD3DDevice->SetRenderState( D3DRS_SPECULARENABLE, true ); //开启镜面光

//显卡信息
wchar_t adapterTemp[200] = L"显卡型号:";
D3DADAPTER_IDENTIFIER9 adapter; //获取显卡信息的结构体
g_pAdapter = new wchar_t[200];
g_pD3D->GetAdapterIdentifier( 0, 0, &adapter ); //获取显卡信息,保存在adapter中

//将char*转化为wchar_t*
int len = MultiByteToWideChar( CP_ACP, 0, adapter.Description, -1, NULL, 0 );
MultiByteToWideChar( CP_ACP, 0, adapter.Description, -1, g_pAdapter, len );
wcscat_s(adapterTemp,g_pAdapter ); //链接两个字符串
memcpy( g_pAdapter, adapterTemp, sizeof(adapterTemp) ); //从新拷贝回g_pAdapter

return S_OK;
}

VOID InitTranformMatrix()
{
D3DXMATRIX matWorld;
D3DXMatrixIdentity( &matWorld );
g_pD3DDevice->SetTransform( D3DTS_WORLD, &matWorld );

// 摄像机
D3DXVECTOR3 pos(100.0f, 100.0f, -250.0f);
D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
//g_camera.ReSetting( &pos, &target, &up );

//D3DXVECTOR3 right( 1.0f, 0.0f, 0.0f);
D3DXMATRIX V;
//g_camera.GetViewMatrix( &V );
D3DXMatrixLookAtLH(
&V,
&pos,
&target,
&up);
g_pD3DDevice->SetTransform(D3DTS_VIEW, &V);

// 设置投影变换矩阵.
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(
&proj,
D3DX_PI * 0.5f,
(float)wndWidth/ (float)wndHeight,
1.0f,
1000.0f);
g_pD3DDevice->SetTransform(D3DTS_PROJECTION, &proj);

//视口剪切矩阵,实现视口变换
D3DVIEWPORT9 vp;
vp.X = 0;
vp.Y = 0;
vp.Width = wndWidth;
vp.Height = wndHeight;
vp.MinZ = 0;
vp.MaxZ = 1;
g_pD3DDevice->SetViewport( &vp );
}

HRESULT InitText()
{
HRESULT hr;
//创建字体
hr = D3DXCreateFont( g_pD3DDevice, 25, 0, 1000, 0, false,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
DEFAULT_QUALITY, 0, L"微软雅黑", &g_pText );

return hr;
}

VOID Render( HWND hWnd )
{
if( NULL == g_pD3DDevice )
return ;
//清屏
g_pD3DDevice->Clear( 0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB( 28, 154, 207 ), 1.0f, 0 );

if( SUCCEEDED( g_pD3DDevice->BeginScene() ) )
{
UpdateScene( hWnd );
DrawFrame( g_pFrameRoot ); //绘制骨骼动画

RenderText( hWnd );
g_pD3DDevice->EndScene();
}

g_pD3DDevice->Present( NULL, NULL, NULL, NULL );
//::Sleep(10000);
}

//递归绘制骨骼动画
VOID DrawFrame( LPD3DXFRAME pFrame )
{
LPD3DXMESHCONTAINER pMeshContainer;

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

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

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

//绘制单个pMeshContainer
VOID DrawMeshContainer( const LPD3DXMESHCONTAINER pMeshContainerBase, const LPD3DXFRAME pFrameBase )
{
D3DXMESHCONTAINER_EX* pMeshContainer = (D3DXMESHCONTAINER_EX*)pMeshContainerBase;
D3DXFRAME_EX* pFrame = (D3DXFRAME_EX*)pFrameBase;
unsigned int iMaterial;
//unsigned int numBlend;
unsigned int iAttrib;
//DWORD attribIdPrev;
//LPD3DXBONECOMBINATION pBoneComb;

//unsigned int iMatrixIndex;
//unsigned int iPaletteEntry;
D3DXMATRIXA16 matTemp;

if( pMeshContainer->pSkinInfo != NULL )
{
//只采用软件处理方式
//D3DXMATRIX Identity;
DWORD cBones = pMeshContainer->pSkinInfo->GetNumBones();
DWORD iBone;
PBYTE pbVerticesSrc;
PBYTE pbVerticesDest;

//D3DXMATRIX* pBoneMatrices = new D3DXMATRIX[cBones];
for( iBone = 0; iBone < cBones; ++iBone )
{
D3DXMatrixMultiply(
&g_pBoneMatrices[iBone],
&pMeshContainer->pBoneOffsetMatrices[iBone],
pMeshContainer->ppBoneMatrixPtrs[iBone]
);
}

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

pMeshContainer->pSkinInfo->UpdateSkinnedMesh( g_pBoneMatrices, NULL, pbVerticesSrc, pbVerticesDest );

//delete[] pBoneMatrices;
//pBoneMatrices = NULL;

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

for( iAttrib = 0; iAttrib < pMeshContainer->numAttributeGroups; iAttrib++ )
{
g_pD3DDevice->SetMaterial( &( pMeshContainer->pMaterials[pMeshContainer->pAttributeTable[iAttrib].AttribId].MatD3D ) );
g_pD3DDevice->SetTexture( 0, pMeshContainer->ppTextures[pMeshContainer->pAttributeTable[iAttrib].AttribId]);
pMeshContainer->MeshData.pMesh->DrawSubset( pMeshContainer->pAttributeTable[iAttrib].AttribId);
}
}
else
{
for( iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++ )
{
g_pD3DDevice->SetMaterial( &pMeshContainer->pMaterials[iMaterial].MatD3D );
g_pD3DDevice->SetTexture( 0, pMeshContainer->ppTextures[iMaterial] );
pMeshContainer->MeshData.pMesh->DrawSubset( iMaterial );
}
}
}

VOID RenderText( HWND hWnd )
{
RECT clientRect;
GetClientRect( hWnd, &clientRect );

//-绘制显卡信息
g_pText->DrawText( NULL, g_pAdapter, -1, &clientRect,
DT_TOP | DT_LEFT, D3DXCOLOR( 1.0f, 0.0f, 0.0f, 1.0f ) );

//绘制FPS
wchar_t strFPS[20];
int len = swprintf_s(strFPS, 20, L"FPS:%.3f", GetFPS());
g_pText->DrawText( NULL, strFPS, len, &clientRect, DT_TOP | DT_RIGHT,
D3DXCOLOR( 0.0f, 1.0f, 0.0f, 1.0f ) );

}

VOID UpdateScene( HWND hWnd )
{
if( g_pAnimController != NULL )
{
double time = (double)timeGetTime();
time = ( time - g_startTime ) * 0.001;
g_startTime = (double)timeGetTime();
g_pAnimController->AdvanceTime( time, NULL );
}

D3DXMATRIX matWorld;
//D3DXMatrixIdentity( &matWorld );
g_pD3DDevice->GetTransform( D3DTS_WORLD, &matWorld );
UpdateFrameMatrices( g_pFrameRoot, &matWorld );
}

VOID UpdateFrameMatrices( const LPD3DXFRAME pFrameBase, const LPD3DXMATRIX pParentMatrix )
{
D3DXFRAME_EX* pFrame = (D3DXFRAME_EX*)pFrameBase;

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

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

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

VOID InitLight()
{
//------------------------------
//-1、填写D3DLIGHT9结构体
//-2、SetLinght
//-3、LightEnable
//-----------------------------

//填写光源结构体
D3DLIGHT9 pointLight;
SecureZeroMemory( &pointLight, sizeof(pointLight) );
D3DXCOLOR white = D3DCOLOR_RGBA( 255, 255, 255, 255 );
D3DXCOLOR black = D3DCOLOR_RGBA( 0, 0, 0, 0 );
pointLight.Type = D3DLIGHT_POINT;
pointLight.Ambient = white*0.4f;
pointLight.Diffuse = white;
pointLight.Specular = white*0.6f;
pointLight.Position = D3DXVECTOR3( 200.0f, 200.0f, 0.0f ); //根据需要进行更改
pointLight.Range = 500.0f;
pointLight.Attenuation0 = 1.0f;
pointLight.Attenuation1 = 0.0f;
pointLight.Attenuation2 = 0.0f;

g_pD3DDevice->SetLight( 0, &pointLight );
g_pD3DDevice->LightEnable( 0, true );
}

VOID Cleanup()
{
SAFE_DELETE( g_pAdapter );
SAFE_RELEASE( g_pD3D );
SAFE_RELEASE( g_pD3DDevice );
SAFE_RELEASE( g_pText );
SAFE_RELEASE( g_pAnimController );

if( g_pFrameRoot != NULL )
{
CAllocateHierarchy alloc;
D3DXFrameDestroy( g_pFrameRoot, &alloc );
g_pFrameRoot = NULL;
}
}

//递归设置骨骼链的混合数组
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;
}

HRESULT SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER pMeshContainerBase )
{
unsigned int iBone;
unsigned int cBones;
D3DXFRAME_EX* pFrame;

D3DXMESHCONTAINER_EX* pMeshContainer = ( D3DXMESHCONTAINER_EX* )pMeshContainerBase;

//如果是骨骼动画
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_EX*)D3DXFrameFind( g_pFrameRoot, pMeshContainer->pSkinInfo->GetBoneName( iBone ) );
if( pFrame == NULL )
return E_FAIL;

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

//--------
/*HRESULT hr = pMeshContainer->MeshData.pMesh->GetAttributeTable( NULL, &pMeshContainer->numAttributeGroups );
if( FAILED( hr ) )
return E_FAIL;
pMeshContainer->pAttributeTable = new D3DXATTRIBUTERANGE[pMeshContainer->numAttributeGroups];
if( pMeshContainer->pAttributeTable == NULL )
return E_FAIL;
hr = pMeshContainer->MeshData.pMesh->GetAttributeTable( pMeshContainer->pAttributeTable, NULL );
if( FAILED( hr ) )
return E_FAIL;*/

return S_OK;
}

//在SkinMesh加载或者改变渲染方式时是调用
HRESULT GenerateSkinnedMesh( D3DXMESHCONTAINER_EX* pMeshContainer )
{
HRESULT hr = S_OK;

if( pMeshContainer->pSkinInfo == NULL )
return hr;
SAFE_RELEASE( pMeshContainer->MeshData.pMesh );
SAFE_RELEASE( pMeshContainer->pBoneCombinatonBuf );

hr = pMeshContainer->pOrigMesh->CloneMeshFVF( D3DXMESH_MANAGED, pMeshContainer->pOrigMesh->GetFVF(),
g_pD3DDevice, &pMeshContainer->MeshData.pMesh );
if( FAILED(hr) )
return hr;

hr = pMeshContainer->MeshData.pMesh->GetAttributeTable( NULL, &pMeshContainer->numAttributeGroups );
if( FAILED(hr) )
return hr;

delete[] pMeshContainer->pAttributeTable;
pMeshContainer->pAttributeTable = new D3DXATTRIBUTERANGE[pMeshContainer->numAttributeGroups];
if( pMeshContainer->pAttributeTable == NULL )
return E_OUTOFMEMORY;

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

if( g_numBoneMatricesMax < pMeshContainer->pSkinInfo->GetNumBones() )
{
g_numBoneMatricesMax = pMeshContainer->pSkinInfo->GetNumBones();

//为材质分配空间
g_pBoneMatrices = new D3DXMATRIXA16[g_numBoneMatricesMax];
if( g_pBoneMatrices == NULL )
return E_OUTOFMEMORY;
}

return hr;
}




后记:好久,好久没更新了,一个由于自己突然抽风了,变得放纵,还有就是还是被其他事情影响到了。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐