《精通DirectX 3D》 第二十一章 HLSL高级应用 07_HLSLSkinMesh
![《精通DirectX 3D》 第二十一章 HLSL高级应用 07_HLSLSkinMesh_第1张图片](http://img.e-com-net.com/image/product/194309270f6643608082908ede01ee86.jpg)
HLSLSkinMesh.fx
//
=========================================================
// Desc: 效果源代码
// =========================================================
// ---------------------------------------------------------
// 全局变量
// ---------------------------------------------------------
float4 lightDir = { 0.0f , 0.0f , - 1.0f , 1.0f };
float4 lightDiffuse = { 0.6f , 0.6f , 0.6f , 1.0f };
float4 MaterialAmbient = { 0.1f , 0.1f , 0.1f , 1.0f };
float4 MaterialDiffuse = { 0.8f , 0.8f , 0.8f , 1.0f };
static const int MAX_MATRICES = 26 ;
float4x3 mWorldMatrixArray[MAX_MATRICES]; // 骨骼调色板矩阵
int CurNumBones = 2 ; // 当前骨骼数量
float4x4 mProj;
// ----------------------------------------------------------
// 顶点渲染器输入和输出结构
// ----------------------------------------------------------
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;
CosTheta = max( 0.0f , dot(Normal, lightDir.xyz));
return (CosTheta);
}
// ---------------------------------------------------------
// 子函数, 完成顶点处理
// ---------------------------------------------------------
VS_OUTPUT VShade(VS_INPUT i, uniform int NumBones)
{
VS_OUTPUT o;
float3 Pos = 0.0f ;
float3 Normal = 0.0f ;
float sumWeight = 0.0f ;
float LastWeight = 0.0f ;
// 为Geforce3类型的显卡所做的补偿
int4 IndexVector = D3DCOLORtoUBYTE4(i.BlendIndices);
// 将骨骼权重向量和骨骼索引向量变换至数组
float BlendWeightsArray[ 4 ] = ( float [ 4 ])i.BlendWeights;
int IndexArray[ 4 ] = ( int [ 4 ])IndexVector;
// 计算前NumBones-1个骨骼对于该顶点位置及法向量的影响
for ( int iBone = 0 ; iBone < NumBones - 1 ; iBone ++ )
{
sumWeight = sumWeight + BlendWeightsArray[iBone];
Pos += mul(i.Pos, mWorldMatrixArray[IndexArray[iBone]]) * BlendWeightsArray[iBone];
Normal += mul(i.Normal, mWorldMatrixArray[IndexArray[iBone]]) * BlendWeightsArray[iBone];
}
LastWeight = 1.0f - sumWeight;
// 计算最后一个骨骼对于顶点位置及法向量的影响
Pos += (mul(i.Pos, mWorldMatrixArray[IndexArray[NumBones - 1 ]]) * LastWeight);
Normal += (mul(i.Normal, mWorldMatrixArray[IndexArray[NumBones - 1 ]]) * LastWeight);
o.Pos = mul(float4(Pos.xyz, 1.0f ), mProj);
Normal = normalize(Normal);
// 计算光照
o.Diffuse.xyz = MaterialAmbient.xyz + Diffuse(Normal) * MaterialDiffuse.xyz;
o.Diffuse.w = 1.0f ;
// 输出纹理坐标
o.Tex0 = i.Tex0.xy;
return o;
}
// ---------------------------------------------------------
// 顶点渲染器
// ---------------------------------------------------------
VertexShader vsArray[ 4 ] = {
compile vs_1_1 VShade( 1 ),
compile vs_1_1 VShade( 2 ),
compile vs_1_1 VShade( 3 ),
compile vs_1_1 VShade( 4 )
};
// ---------------------------------------------------------
// 技术与通道
// ---------------------------------------------------------
technique t0
{
pass p0
{
VertexShader = (vsArray[CurNumBones]);
}
}
// Desc: 效果源代码
// =========================================================
// ---------------------------------------------------------
// 全局变量
// ---------------------------------------------------------
float4 lightDir = { 0.0f , 0.0f , - 1.0f , 1.0f };
float4 lightDiffuse = { 0.6f , 0.6f , 0.6f , 1.0f };
float4 MaterialAmbient = { 0.1f , 0.1f , 0.1f , 1.0f };
float4 MaterialDiffuse = { 0.8f , 0.8f , 0.8f , 1.0f };
static const int MAX_MATRICES = 26 ;
float4x3 mWorldMatrixArray[MAX_MATRICES]; // 骨骼调色板矩阵
int CurNumBones = 2 ; // 当前骨骼数量
float4x4 mProj;
// ----------------------------------------------------------
// 顶点渲染器输入和输出结构
// ----------------------------------------------------------
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;
CosTheta = max( 0.0f , dot(Normal, lightDir.xyz));
return (CosTheta);
}
// ---------------------------------------------------------
// 子函数, 完成顶点处理
// ---------------------------------------------------------
VS_OUTPUT VShade(VS_INPUT i, uniform int NumBones)
{
VS_OUTPUT o;
float3 Pos = 0.0f ;
float3 Normal = 0.0f ;
float sumWeight = 0.0f ;
float LastWeight = 0.0f ;
// 为Geforce3类型的显卡所做的补偿
int4 IndexVector = D3DCOLORtoUBYTE4(i.BlendIndices);
// 将骨骼权重向量和骨骼索引向量变换至数组
float BlendWeightsArray[ 4 ] = ( float [ 4 ])i.BlendWeights;
int IndexArray[ 4 ] = ( int [ 4 ])IndexVector;
// 计算前NumBones-1个骨骼对于该顶点位置及法向量的影响
for ( int iBone = 0 ; iBone < NumBones - 1 ; iBone ++ )
{
sumWeight = sumWeight + BlendWeightsArray[iBone];
Pos += mul(i.Pos, mWorldMatrixArray[IndexArray[iBone]]) * BlendWeightsArray[iBone];
Normal += mul(i.Normal, mWorldMatrixArray[IndexArray[iBone]]) * BlendWeightsArray[iBone];
}
LastWeight = 1.0f - sumWeight;
// 计算最后一个骨骼对于顶点位置及法向量的影响
Pos += (mul(i.Pos, mWorldMatrixArray[IndexArray[NumBones - 1 ]]) * LastWeight);
Normal += (mul(i.Normal, mWorldMatrixArray[IndexArray[NumBones - 1 ]]) * LastWeight);
o.Pos = mul(float4(Pos.xyz, 1.0f ), mProj);
Normal = normalize(Normal);
// 计算光照
o.Diffuse.xyz = MaterialAmbient.xyz + Diffuse(Normal) * MaterialDiffuse.xyz;
o.Diffuse.w = 1.0f ;
// 输出纹理坐标
o.Tex0 = i.Tex0.xy;
return o;
}
// ---------------------------------------------------------
// 顶点渲染器
// ---------------------------------------------------------
VertexShader vsArray[ 4 ] = {
compile vs_1_1 VShade( 1 ),
compile vs_1_1 VShade( 2 ),
compile vs_1_1 VShade( 3 ),
compile vs_1_1 VShade( 4 )
};
// ---------------------------------------------------------
// 技术与通道
// ---------------------------------------------------------
technique t0
{
pass p0
{
VertexShader = (vsArray[CurNumBones]);
}
}
//
=============================================================================
// Desc: 主程序源文件
// =============================================================================
#include " dxstdafx.h "
#include " resource.h "
#pragma warning(disable: 4995 )
// -----------------------------------------------------------------------------
// Desc: 继承自DXDXFRAME结构的结构
// -----------------------------------------------------------------------------
struct D3DXFRAME_DERIVED: public D3DXFRAME
{
D3DXMATRIXA16 CombinedTransformationMatrix;
};
// -----------------------------------------------------------------------------
// Desc: 继承自D3DXMESHCONTAINER结构的结构
// -----------------------------------------------------------------------------
struct D3DXMESHCONTAINER_DERIVED: public D3DXMESHCONTAINER
{
LPDIRECT3DTEXTURE9 * ppTextures; // 纹理数组
LPD3DXMESH pOrigMesh; // 原网格
DWORD NumAttributeGroups; // 骨骼数量
DWORD NumInfl; // 每个顶点最多可以影响多少骨骼
LPD3DXBUFFER pBoneCombinationBuf; // 骨骼结合表
D3DXMATRIX ** ppBoneMatrixPtrs; // 存放骨骼的组合变换矩阵
D3DXMATRIX * pBoneOffsetMatrices; // 存放骨骼的初始变换矩阵
DWORD NumPaletteEntries; // 有多少骨骼可以使用(上限)
bool UseSoftwareVP; // 标识是否使用软件顶点处理
};
// -----------------------------------------------------------------------------
// Desc: 该类用来从.X文件加载框架层次和网格模型数据
// -----------------------------------------------------------------------------
class CAllocateHierarchy: public ID3DXAllocateHierarchy
{
private :
HRESULT GenerateSkinnedMesh(IDirect3DDevice9 * pd3dDevice, D3DXMESHCONTAINER_DERIVED * pMeshContainer);
HRESULT AllocateName( LPCSTR Name, LPSTR * pNewName );
void RemovePathFromFileName(LPSTR fullPath, LPWSTR fileName);
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() {}
};
// -----------------------------------------------------------------------------
// 全局变量
// -----------------------------------------------------------------------------
ID3DXFont * g_pFont = NULL; // ID3DXFont字体对象
ID3DXSprite * g_pTextSprite = NULL; // ID3DXSprite文本精灵对象
bool g_bShowHelp = true ; // 标识是否显示简单说明文本
CDXUTDialogResourceManager g_DialogResourceManager; // 对话框资源管理器
CD3DSettingsDlg g_SettingsDlg; // Direct3D设备设置对话框
CDXUTDialog g_HUD; // 对话框
CDXUTDialog g_SampleUI; // 对话框
ID3DXEffect * g_pEffect = NULL;
LPD3DXFRAME g_pFrameRoot = NULL;
ID3DXAnimationController * g_pAnimController = NULL;
D3DXMATRIXA16 * g_pBoneMatrices = NULL;
UINT g_NumBoneMatricesMax = 0 ;
D3DXMATRIXA16 g_matWorld;
D3DXMATRIXA16 g_matView;
D3DXMATRIXA16 g_matProj;
// -----------------------------------------------------------------------------
// 控件ID
// -----------------------------------------------------------------------------
#define IDC_TOGGLEFULLSCREEN 1
#define IDC_TOGGLEREF 2
#define IDC_CHANGEDEVICE 3
// -----------------------------------------------------------------------------
// Desc: 函数声明
// ------------------------------------------------------------------------------
bool CALLBACK IsDeviceAcceptable( D3DCAPS9 * pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed, void * pUserContext );
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings * pDeviceSettings, const D3DCAPS9 * pCaps, void * pUserContext );
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9 * pd3dDevice, const D3DSURFACE_DESC * pBackBufferSurfaceDesc, void * pUserContext );
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9 * pd3dDevice, const D3DSURFACE_DESC * pBackBufferSurfaceDesc, void * pUserContext );
void CALLBACK OnFrameMove( IDirect3DDevice9 * pd3dDevice, double fTime, float fElapsedTime, void * pUserContext );
void CALLBACK OnFrameRender( IDirect3DDevice9 * pd3dDevice, double fTime, float fElapsedTime, void * pUserContext );
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool * pbNoFurtherProcessing, void * pUserContext );
void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown, void * pUserContext );
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl * pControl, void * pUserContext );
void CALLBACK OnLostDevice( void * pUserContext );
void CALLBACK OnDestroyDevice( void * pUserContext );
void InitApp();
void RenderText();
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 );
// -----------------------------------------------------------------------------
// Desc:
// -----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::AllocateName( LPCSTR Name, LPSTR * pNewName )
{
UINT cbLength;
if ( Name != NULL )
{
cbLength = (UINT)strlen(Name) + 1 ;
* pNewName = new CHAR[cbLength];
if ( * pNewName == NULL)
return E_OUTOFMEMORY;
memcpy( * pNewName, Name, cbLength * sizeof (CHAR) );
}
else
{
* pNewName = NULL;
}
return S_OK;
}
// -----------------------------------------------------------------------------
// Desc: 从绝对路径中提取文件名
// -----------------------------------------------------------------------------
void CAllocateHierarchy::RemovePathFromFileName(LPSTR fullPath, LPWSTR fileName)
{
// 先将fullPath的类型变换为LPWSTR
WCHAR wszBuf[MAX_PATH];
MultiByteToWideChar( CP_ACP, 0 , fullPath, - 1 , wszBuf, MAX_PATH );
wszBuf[MAX_PATH - 1 ] = L ' \0 ' ;
WCHAR * wszFullPath = wszBuf;
// 从绝对路径中提取文件名
LPWSTR pch = wcsrchr(wszFullPath, ' \\ ' );
if (pch)
lstrcpy(fileName, ++ pch);
else
lstrcpy(fileName, wszFullPath);
}
// -----------------------------------------------------------------------------
// Desc: 创建框架, 仅仅是分配内存和初始化,还没有对其成员赋予合适的值
// -----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::CreateFrame( LPCSTR Name, LPD3DXFRAME * ppNewFrame )
{
HRESULT hr = S_OK;
D3DXFRAME_DERIVED * pFrame;
* ppNewFrame = NULL;
pFrame = new D3DXFRAME_DERIVED; // 创建框架结构对象
if (pFrame == NULL)
{
return E_OUTOFMEMORY;
}
// 为框架指定名称
hr = AllocateName(Name, (LPSTR * ) & pFrame -> Name);
if (FAILED(hr))
{
delete pFrame;
return hr;
}
// 初始化D3DXFRAME_DERIVED结构其它成员变量
D3DXMatrixIdentity( & pFrame -> TransformationMatrix);
D3DXMatrixIdentity( & pFrame -> CombinedTransformationMatrix);
pFrame -> pMeshContainer = NULL;
pFrame -> pFrameSibling = NULL;
pFrame -> pFrameFirstChild = NULL;
* ppNewFrame = pFrame;
pFrame = NULL;
return hr;
}
// -----------------------------------------------------------------------------
// Desc: 在这里是调用了成员函数 GenerateSkinnedMesh(pMeshContainer);
// 是在这里加载了蒙皮信息
// -----------------------------------------------------------------------------
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 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_DERIVED;
if (pMeshContainer == NULL)
{
return E_OUTOFMEMORY;
}
memset(pMeshContainer, 0 , sizeof (D3DXMESHCONTAINER_DERIVED));
// 填充网格容器结构D3DXMESHCONTAINER_DERIVED的成员
// 为网格指定名称
hr = AllocateName(Name, & pMeshContainer -> Name);
if (FAILED(hr))
{
DestroyMeshContainer(pMeshContainer);
return hr;
}
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))
{
SAFE_RELEASE(pd3dDevice);
DestroyMeshContainer(pMeshContainer);
return hr;
}
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)
|| (pMeshContainer -> ppTextures == NULL))
{
hr = E_OUTOFMEMORY;
SAFE_RELEASE(pd3dDevice);
DestroyMeshContainer(pMeshContainer);
return hr;
}
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);
pMeshContainer -> pMaterials -> MatD3D.Ambient = pMeshContainer -> pMaterials -> MatD3D.Diffuse;
for (iMaterial = 0 ; iMaterial < NumMaterials; iMaterial ++ )
{
if (pMeshContainer -> pMaterials[iMaterial].pTextureFilename != NULL)
{
WCHAR strTexturePath[MAX_PATH];
WCHAR wszBuf[MAX_PATH];
// 从纹理文件路径提取纹理文件名
RemovePathFromFileName(pMeshContainer -> pMaterials[iMaterial].pTextureFilename, wszBuf);
// 根据纹理文件名从事先指定的路径查找纹理文件
DXUTFindDXSDKMediaFileCch( strTexturePath, MAX_PATH, wszBuf );
if ( FAILED( D3DXCreateTextureFromFile( pd3dDevice, strTexturePath,
& pMeshContainer -> ppTextures[iMaterial] ) ) )
pMeshContainer -> ppTextures[iMaterial] = 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;
DestroyMeshContainer(pMeshContainer);
return hr;
}
// 保存每块骨骼的初始变换矩阵
for (UINT iBone = 0 ; iBone < cBones; iBone ++ )
{
pMeshContainer -> pBoneOffsetMatrices[iBone] = * (pMeshContainer -> pSkinInfo -> GetBoneOffsetMatrix(iBone));
}
// 生成蒙皮网格模型
hr = GenerateSkinnedMesh(pd3dDevice, pMeshContainer);
if (FAILED(hr))
{
DestroyMeshContainer(pMeshContainer);
return hr;
}
}
* ppNewMeshContainer = pMeshContainer;
pMeshContainer = NULL;
SAFE_RELEASE(pd3dDevice);
return hr;
}
// -----------------------------------------------------------------------------
// Desc: 生成蒙皮网格模型(含有每个顶点的混合权重、索引和一个骨骼组合表)
// -----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::GenerateSkinnedMesh( IDirect3DDevice9 * pd3dDevice,
D3DXMESHCONTAINER_DERIVED * pMeshContainer )
{
HRESULT hr = S_OK;
if ( pMeshContainer -> pSkinInfo == NULL )
return hr;
SAFE_RELEASE( pMeshContainer -> MeshData.pMesh );
SAFE_RELEASE( pMeshContainer -> pBoneCombinationBuf );
// 获取当前设备的能力
D3DCAPS9 d3dCaps;
pd3dDevice -> GetDeviceCaps( & d3dCaps );
pMeshContainer -> NumPaletteEntries = min( 26 , pMeshContainer -> pSkinInfo -> GetNumBones());
DWORD Flags = D3DXMESHOPT_VERTEXCACHE;
if (d3dCaps.VertexShaderVersion >= D3DVS_VERSION( 1 , 1 ))
{
pMeshContainer -> UseSoftwareVP = false ;
Flags |= D3DXMESH_MANAGED;
}
else
{
pMeshContainer -> UseSoftwareVP = 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))
return hr;
// FVF has to match our declarator. Vertex shaders are not as forgiving as FF pipeline
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))
return hr;
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))
return hr;
// allocate a buffer for bone matrices,
if ( g_NumBoneMatricesMax < pMeshContainer -> pSkinInfo -> GetNumBones() )
{
g_NumBoneMatricesMax = pMeshContainer -> pSkinInfo -> GetNumBones();
// Allocate space for blend matrices
delete[] g_pBoneMatrices;
g_pBoneMatrices = new D3DXMATRIXA16[g_NumBoneMatricesMax];
if ( g_pBoneMatrices == NULL )
{
hr = E_OUTOFMEMORY;
return hr;
}
}
return hr;
}
// -----------------------------------------------------------------------------
// Desc: 释放框架
// -----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::DestroyFrame(LPD3DXFRAME pFrameToFree)
{
if (pFrameToFree != NULL)
{
SAFE_DELETE_ARRAY( pFrameToFree -> Name );
SAFE_DELETE( pFrameToFree );
}
return S_OK;
}
// -----------------------------------------------------------------------------
// Desc: 释放网格容器
// -----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER pMeshContainerBase)
{
if (pMeshContainerBase == NULL)
return S_OK;
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;
}
// -----------------------------------------------------------------------------
// Desc: 入口函数
// -----------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
// 为Debug配置启用运行时内存检查功能
#if defined(DEBUG) | defined(_DEBUG)
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
// 设置回调函数
DXUTSetCallbackDeviceCreated( OnCreateDevice );
DXUTSetCallbackDeviceReset( OnResetDevice );
DXUTSetCallbackDeviceLost( OnLostDevice );
DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
DXUTSetCallbackMsgProc( MsgProc );
DXUTSetCallbackKeyboard( KeyboardProc );
DXUTSetCallbackFrameRender( OnFrameRender );
DXUTSetCallbackFrameMove( OnFrameMove );
// 应用程序相关的初始化
InitApp();
// 初始化DXUT, 创建窗口, 创建Direct3D设备对象
DXUTInit( true , true , true );
DXUTSetCursorSettings( true , true );
DXUTCreateWindow( L " HLSLSkinMesh " );
DXUTCreateDevice( D3DADAPTER_DEFAULT, true , 640 , 480 ,
IsDeviceAcceptable, ModifyDeviceSettings );
// 进入消息循环和场景渲染
DXUTMainLoop();
// 在此进行应用程序相关的清除工作
delete[] g_pBoneMatrices;
return DXUTGetExitCode();
}
// -----------------------------------------------------------------------------
// Desc: 应用程序相关初始化
// -----------------------------------------------------------------------------
void InitApp()
{
// 初始化对话框
g_SettingsDlg.Init( & g_DialogResourceManager );
g_HUD.Init( & g_DialogResourceManager );
g_SampleUI.Init( & g_DialogResourceManager );
// 为g_HUD对话框设置消息处理函数,添加控件
g_HUD.SetCallback( OnGUIEvent ); int iY = 10 ;
g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L " Toggle full screen " , 35 , iY, 125 , 22 );
g_HUD.AddButton( IDC_TOGGLEREF, L " Toggle REF (F3) " , 35 , iY += 24 , 125 , 22 );
g_HUD.AddButton( IDC_CHANGEDEVICE, L " Change device (F2) " , 35 , iY += 24 , 125 , 22 , VK_F2 );
}
// -----------------------------------------------------------------------------
// Desc: 设备能力检查
// -----------------------------------------------------------------------------
bool CALLBACK IsDeviceAcceptable( D3DCAPS9 * pCaps, D3DFORMAT AdapterFormat,
D3DFORMAT BackBufferFormat, bool bWindowed,
void * pUserContext )
{
// 检查后台缓冲区格式是否支持Alpha混合等操作(post pixel blending operations)
IDirect3D9 * pD3D = DXUTGetD3DObject();
if ( FAILED( pD3D -> CheckDeviceFormat( pCaps -> AdapterOrdinal, pCaps -> DeviceType,
AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING,
D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
return false ;
// 检查当前设备支持顶点渲染器版本是否符合要求
if ( pCaps -> VertexShaderVersion < D3DVS_VERSION( 1 , 1 ) )
return FALSE;
return true ;
}
// -----------------------------------------------------------------------------
// Desc: 修改Direct3D渲染设备设置
// -----------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings * pDeviceSettings,
const D3DCAPS9 * pCaps, void * pUserContext )
{
// 如果不支持硬件顶点处理则使用软件顶点处理
if ( (pCaps -> DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 )
{
pDeviceSettings -> BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
// 如果使用纯硬件顶点处理模式则改为混合顶点处理模式
if ( pDeviceSettings -> BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING )
pDeviceSettings -> BehaviorFlags = D3DCREATE_MIXED_VERTEXPROCESSING;
// 调试顶点渲染器需要参考设备或软件顶点处理
#ifdef DEBUG_VS
if ( pDeviceSettings -> DeviceType != D3DDEVTYPE_REF )
{
pDeviceSettings -> BehaviorFlags &= ~ D3DCREATE_HARDWARE_VERTEXPROCESSING;
pDeviceSettings -> BehaviorFlags &= ~ D3DCREATE_PUREDEVICE;
pDeviceSettings -> BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
#endif
// 调试像素渲染器需要参考设备
#ifdef DEBUG_PS
pDeviceSettings -> DeviceType = D3DDEVTYPE_REF;
#endif
// 如果使用参考设备,则弹出警告对话框
static bool s_bFirstTime = true ;
if ( s_bFirstTime )
{
s_bFirstTime = false ;
if ( pDeviceSettings -> DeviceType == D3DDEVTYPE_REF )
DXUTDisplaySwitchingToREFWarning();
}
return true ;
}
// -----------------------------------------------------------------------------
// Desc: 在此创建管理内存资源对象
// -----------------------------------------------------------------------------
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9 * pd3dDevice,
const D3DSURFACE_DESC * pBackBufferSurfaceDesc,
void * pUserContext )
{
HRESULT hr;
V_RETURN( g_DialogResourceManager.OnCreateDevice( pd3dDevice ) );
V_RETURN( g_SettingsDlg.OnCreateDevice( pd3dDevice ) );
// 创建字体
V_RETURN( D3DXCreateFont( pd3dDevice, 15 , 0 , FW_BOLD, 1 , FALSE, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
L " Arial " , & g_pFont ) );
// 创建效果
DWORD dwShaderFlags = D3DXFX_NOT_CLONEABLE;
#ifdef DEBUG_VS
dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
#endif
#ifdef DEBUG_PS
dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
#endif
V_RETURN(D3DXCreateEffectFromFile( pd3dDevice, L " HLSLSkinMesh.fx " , NULL, NULL,
dwShaderFlags, NULL, & g_pEffect, NULL ));
// 创建网格模型
CAllocateHierarchy Alloc;
V_RETURN(D3DXLoadMeshHierarchyFromX( L " tiny.x " , D3DXMESH_MANAGED, pd3dDevice,
& Alloc, NULL, & g_pFrameRoot, & g_pAnimController ));
SetupBoneMatrixPointers( g_pFrameRoot );
return S_OK;
}
// -----------------------------------------------------------------------------
// Desc: 在此创建默认内存类型资源对象
// -----------------------------------------------------------------------------
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9 * pd3dDevice,
const D3DSURFACE_DESC * pBackBufferSurfaceDesc,
void * pUserContext )
{
HRESULT hr;
V_RETURN( g_DialogResourceManager.OnResetDevice() );
V_RETURN( g_SettingsDlg.OnResetDevice() );
// 设置对话框位置和尺寸
g_HUD.SetLocation( pBackBufferSurfaceDesc -> Width - 170 , 0 );
g_HUD.SetSize( 170 , 170 );
g_SampleUI.SetLocation( pBackBufferSurfaceDesc -> Width - 170 ,
pBackBufferSurfaceDesc -> Height - 350 );
g_SampleUI.SetSize( 170 , 300 );
// 恢复字体
if ( g_pFont )
V_RETURN( g_pFont -> OnResetDevice() );
// 创建ID3DXSprite接口对象
V_RETURN( D3DXCreateSprite( pd3dDevice, & g_pTextSprite ) );
// 恢复效果对象
if ( g_pEffect )
V_RETURN( g_pEffect -> OnResetDevice() );
// 构造世界矩阵
D3DXMatrixTranslation( & g_matWorld, 0 , 30 , - 100 );
// 构造观察矩阵
D3DXVECTOR3 vEye( 0 , 0 , - 1000 );
D3DXVECTOR3 vAt( 0 , 0 , 0 );
D3DXVECTOR3 vUp( 0 , 1 , 0 );
D3DXMatrixLookAtLH( & g_matView, & vEye, & vAt, & vUp);
// 构造投影矩阵
D3DXMATRIXA16 matProj;
float fAspectRatio = ( float )pBackBufferSurfaceDesc -> Width / pBackBufferSurfaceDesc -> Height;
D3DXMatrixPerspectiveFovLH( & matProj, D3DX_PI / 4 , fAspectRatio, 1.0f , 2000.0f );;
// 为效果设置影矩阵
V( g_pEffect -> SetMatrix( " mProj " , & matProj ) );
// 为效果设置灯光方向
D3DXVECTOR4 vLightDir( 0.0f , 1.0f , - 1.0f , 0.0f );
D3DXVec4Normalize( & vLightDir, & vLightDir );
V( g_pEffect -> SetVector( " lightDir " , & vLightDir) );
return S_OK;
}
// -----------------------------------------------------------------------------
// Desc: 更新场景
// -----------------------------------------------------------------------------
void CALLBACK OnFrameMove( IDirect3DDevice9 * pd3dDevice, double fTime,
float fElapsedTime, void * pUserContext )
{
}
// ------------------------------------------------------------------------------
// Desc: 渲染网格模型
// ------------------------------------------------------------------------------
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 iAttrib;
LPD3DXBONECOMBINATION pBoneComb;
UINT iMatrixIndex;
UINT iPaletteEntry;
D3DXMATRIXA16 matTemp;
D3DCAPS9 d3dCaps;
pd3dDevice -> GetDeviceCaps( & d3dCaps );
// 检查是否是蒙皮网格模型
if (pMeshContainer -> pSkinInfo != NULL)
{
if (pMeshContainer -> UseSoftwareVP)
{
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( 0.25 , 0.25 , 0.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) );
/// 设置纹理
V( pd3dDevice -> SetTexture( 0 , pMeshContainer -> ppTextures[pBoneComb[iAttrib].AttribId] ) );
// 设置当前骨骼数量
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) );
}
if (pMeshContainer -> UseSoftwareVP)
{
V( pd3dDevice -> SetSoftwareVertexProcessing(FALSE) );
}
}
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 );
}
}
// -----------------------------------------------------------------------------
// Desc: 渲染场景
// -----------------------------------------------------------------------------
void CALLBACK OnFrameRender( IDirect3DDevice9 * pd3dDevice, double fTime,
float fElapsedTime, void * pUserContext )
{
HRESULT hr;
// 如果正在利用Direct3D设备设置对话框进行设置, 则不渲染场景
if ( g_SettingsDlg.IsActive() )
{
g_SettingsDlg.OnRender( fElapsedTime );
return ;
}
// 清除后台颜色缓冲区和深度缓冲区
V( pd3dDevice -> Clear( 0 , NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
D3DCOLOR_ARGB( 0 , 45 , 50 , 170 ), 1.0f , 0 ) );
// 渲染场景
if ( SUCCEEDED( pd3dDevice -> BeginScene() ) )
{
// 渲染网格模型
if ( g_pAnimController != NULL )
g_pAnimController -> AdvanceTime( fElapsedTime, NULL );
UpdateFrameMatrices( g_pFrameRoot, & g_matWorld );
DrawFrame( pd3dDevice, g_pFrameRoot );
// 渲染文本和控件
DXUT_BeginPerfEvent( DXUT_PERFEVENTCOLOR, L " HUD / Stats " );
RenderText();
V( g_HUD.OnRender( fElapsedTime ) );
V( g_SampleUI.OnRender( fElapsedTime ) );
DXUT_EndPerfEvent();
V( pd3dDevice -> EndScene() );
}
}
// -----------------------------------------------------------------------------
// Desc: 渲染文本
// -----------------------------------------------------------------------------
void RenderText()
{
CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite, 15 );
// 显示当前Direct3D设备状态和渲染帧速率
txtHelper.Begin();
txtHelper.SetInsertionPos( 5 , 5 );
txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f , 1.0f , 0.0f , 1.0f ) );
txtHelper.DrawTextLine( DXUTGetFrameStats( true ) );
txtHelper.DrawTextLine( DXUTGetDeviceStats() );
// 显示其他简要信息
txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f , 1.0f , 1.0f , 1.0f ) );
txtHelper.DrawTextLine( L " 通过HLSL编程实现蒙皮骨骼动画 " );
// 显示简单帮助文本
const D3DSURFACE_DESC * pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc();
if ( g_bShowHelp )
{
txtHelper.SetInsertionPos( 10 , pd3dsdBackBuffer -> Height - 15 * 6 );
txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f , 0.75f , 0.0f , 1.0f ) );
txtHelper.DrawTextLine( L " Controls (F1 to hide): " );
txtHelper.SetInsertionPos( 40 , pd3dsdBackBuffer -> Height - 15 * 5 );
txtHelper.DrawTextLine( L " Quit: ESC " );
}
else
{
txtHelper.SetInsertionPos( 10 , pd3dsdBackBuffer -> Height - 15 * 2 );
txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f , 1.0f , 1.0f , 1.0f ) );
txtHelper.DrawTextLine( L " Press F1 for help " );
}
txtHelper.End();
}
// -----------------------------------------------------------------------------
// Desc: 消息处理
// -----------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
bool * pbNoFurtherProcessing, void * pUserContext )
{
* pbNoFurtherProcessing = g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam );
if ( * pbNoFurtherProcessing )
return 0 ;
if ( g_SettingsDlg.IsActive() )
{
g_SettingsDlg.MsgProc( hWnd, uMsg, wParam, lParam );
return 0 ;
}
* pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
if ( * pbNoFurtherProcessing )
return 0 ;
* pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
if ( * pbNoFurtherProcessing )
return 0 ;
return 0 ;
}
// -----------------------------------------------------------------------------
// Desc: 键盘消息处理
// -----------------------------------------------------------------------------
void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown, void * pUserContext )
{
if ( bKeyDown )
{
switch ( nChar )
{
case VK_F1: g_bShowHelp = ! g_bShowHelp; break ;
}
}
}
// -----------------------------------------------------------------------------
// Desc: 处理各种控件消息
// -----------------------------------------------------------------------------
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl * pControl,
void * pUserContext )
{
switch ( nControlID )
{
case IDC_TOGGLEFULLSCREEN:
DXUTToggleFullScreen();
break ;
case IDC_TOGGLEREF:
DXUTToggleREF();
break ;
case IDC_CHANGEDEVICE:
g_SettingsDlg.SetActive( ! g_SettingsDlg.IsActive() );
break ;
}
}
// -----------------------------------------------------------------------------
// Desc: 释放在OnResetDevice()中创建的资源
// -----------------------------------------------------------------------------
void CALLBACK OnLostDevice( void * pUserContext )
{
g_DialogResourceManager.OnLostDevice();
g_SettingsDlg.OnLostDevice();
if ( g_pFont )
g_pFont -> OnLostDevice();
SAFE_RELEASE( g_pTextSprite );
if ( g_pEffect )
g_pEffect -> OnLostDevice();
}
// ------------------------------------------------------------------------------
// Desc: 释放在OnCreateDevice()中创建的资源
// ------------------------------------------------------------------------------
void CALLBACK OnDestroyDevice( void * pUserContext )
{
g_DialogResourceManager.OnDestroyDevice();
g_SettingsDlg.OnDestroyDevice();
SAFE_RELEASE( g_pFont );
SAFE_RELEASE( g_pEffect );
CAllocateHierarchy Alloc;
D3DXFrameDestroy( g_pFrameRoot, & Alloc );
SAFE_RELEASE( g_pAnimController );
}
// --------------------------------------------------------------------------------------
// Desc: 设置骨骼矩阵
// --------------------------------------------------------------------------------------
HRESULT SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER pMeshContainerBase )
{
UINT iBone, cBones;
D3DXFRAME_DERIVED * pFrame;
D3DXMESHCONTAINER_DERIVED * pMeshContainer = (D3DXMESHCONTAINER_DERIVED * )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_DERIVED * )D3DXFrameFind( g_pFrameRoot,
pMeshContainer -> pSkinInfo -> GetBoneName(iBone) );
if (pFrame == NULL)
return E_FAIL;
pMeshContainer -> ppBoneMatrixPtrs[iBone] = & pFrame -> CombinedTransformationMatrix;
}
}
return S_OK;
}
// --------------------------------------------------------------------------------------
// Desc: 设置骨骼矩阵指针
// --------------------------------------------------------------------------------------
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;
}
// --------------------------------------------------------------------------------------
// update the frame matrices
// --------------------------------------------------------------------------------------
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);
}
}
// Desc: 主程序源文件
// =============================================================================
#include " dxstdafx.h "
#include " resource.h "
#pragma warning(disable: 4995 )
// -----------------------------------------------------------------------------
// Desc: 继承自DXDXFRAME结构的结构
// -----------------------------------------------------------------------------
struct D3DXFRAME_DERIVED: public D3DXFRAME
{
D3DXMATRIXA16 CombinedTransformationMatrix;
};
// -----------------------------------------------------------------------------
// Desc: 继承自D3DXMESHCONTAINER结构的结构
// -----------------------------------------------------------------------------
struct D3DXMESHCONTAINER_DERIVED: public D3DXMESHCONTAINER
{
LPDIRECT3DTEXTURE9 * ppTextures; // 纹理数组
LPD3DXMESH pOrigMesh; // 原网格
DWORD NumAttributeGroups; // 骨骼数量
DWORD NumInfl; // 每个顶点最多可以影响多少骨骼
LPD3DXBUFFER pBoneCombinationBuf; // 骨骼结合表
D3DXMATRIX ** ppBoneMatrixPtrs; // 存放骨骼的组合变换矩阵
D3DXMATRIX * pBoneOffsetMatrices; // 存放骨骼的初始变换矩阵
DWORD NumPaletteEntries; // 有多少骨骼可以使用(上限)
bool UseSoftwareVP; // 标识是否使用软件顶点处理
};
// -----------------------------------------------------------------------------
// Desc: 该类用来从.X文件加载框架层次和网格模型数据
// -----------------------------------------------------------------------------
class CAllocateHierarchy: public ID3DXAllocateHierarchy
{
private :
HRESULT GenerateSkinnedMesh(IDirect3DDevice9 * pd3dDevice, D3DXMESHCONTAINER_DERIVED * pMeshContainer);
HRESULT AllocateName( LPCSTR Name, LPSTR * pNewName );
void RemovePathFromFileName(LPSTR fullPath, LPWSTR fileName);
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() {}
};
// -----------------------------------------------------------------------------
// 全局变量
// -----------------------------------------------------------------------------
ID3DXFont * g_pFont = NULL; // ID3DXFont字体对象
ID3DXSprite * g_pTextSprite = NULL; // ID3DXSprite文本精灵对象
bool g_bShowHelp = true ; // 标识是否显示简单说明文本
CDXUTDialogResourceManager g_DialogResourceManager; // 对话框资源管理器
CD3DSettingsDlg g_SettingsDlg; // Direct3D设备设置对话框
CDXUTDialog g_HUD; // 对话框
CDXUTDialog g_SampleUI; // 对话框
ID3DXEffect * g_pEffect = NULL;
LPD3DXFRAME g_pFrameRoot = NULL;
ID3DXAnimationController * g_pAnimController = NULL;
D3DXMATRIXA16 * g_pBoneMatrices = NULL;
UINT g_NumBoneMatricesMax = 0 ;
D3DXMATRIXA16 g_matWorld;
D3DXMATRIXA16 g_matView;
D3DXMATRIXA16 g_matProj;
// -----------------------------------------------------------------------------
// 控件ID
// -----------------------------------------------------------------------------
#define IDC_TOGGLEFULLSCREEN 1
#define IDC_TOGGLEREF 2
#define IDC_CHANGEDEVICE 3
// -----------------------------------------------------------------------------
// Desc: 函数声明
// ------------------------------------------------------------------------------
bool CALLBACK IsDeviceAcceptable( D3DCAPS9 * pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed, void * pUserContext );
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings * pDeviceSettings, const D3DCAPS9 * pCaps, void * pUserContext );
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9 * pd3dDevice, const D3DSURFACE_DESC * pBackBufferSurfaceDesc, void * pUserContext );
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9 * pd3dDevice, const D3DSURFACE_DESC * pBackBufferSurfaceDesc, void * pUserContext );
void CALLBACK OnFrameMove( IDirect3DDevice9 * pd3dDevice, double fTime, float fElapsedTime, void * pUserContext );
void CALLBACK OnFrameRender( IDirect3DDevice9 * pd3dDevice, double fTime, float fElapsedTime, void * pUserContext );
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool * pbNoFurtherProcessing, void * pUserContext );
void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown, void * pUserContext );
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl * pControl, void * pUserContext );
void CALLBACK OnLostDevice( void * pUserContext );
void CALLBACK OnDestroyDevice( void * pUserContext );
void InitApp();
void RenderText();
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 );
// -----------------------------------------------------------------------------
// Desc:
// -----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::AllocateName( LPCSTR Name, LPSTR * pNewName )
{
UINT cbLength;
if ( Name != NULL )
{
cbLength = (UINT)strlen(Name) + 1 ;
* pNewName = new CHAR[cbLength];
if ( * pNewName == NULL)
return E_OUTOFMEMORY;
memcpy( * pNewName, Name, cbLength * sizeof (CHAR) );
}
else
{
* pNewName = NULL;
}
return S_OK;
}
// -----------------------------------------------------------------------------
// Desc: 从绝对路径中提取文件名
// -----------------------------------------------------------------------------
void CAllocateHierarchy::RemovePathFromFileName(LPSTR fullPath, LPWSTR fileName)
{
// 先将fullPath的类型变换为LPWSTR
WCHAR wszBuf[MAX_PATH];
MultiByteToWideChar( CP_ACP, 0 , fullPath, - 1 , wszBuf, MAX_PATH );
wszBuf[MAX_PATH - 1 ] = L ' \0 ' ;
WCHAR * wszFullPath = wszBuf;
// 从绝对路径中提取文件名
LPWSTR pch = wcsrchr(wszFullPath, ' \\ ' );
if (pch)
lstrcpy(fileName, ++ pch);
else
lstrcpy(fileName, wszFullPath);
}
// -----------------------------------------------------------------------------
// Desc: 创建框架, 仅仅是分配内存和初始化,还没有对其成员赋予合适的值
// -----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::CreateFrame( LPCSTR Name, LPD3DXFRAME * ppNewFrame )
{
HRESULT hr = S_OK;
D3DXFRAME_DERIVED * pFrame;
* ppNewFrame = NULL;
pFrame = new D3DXFRAME_DERIVED; // 创建框架结构对象
if (pFrame == NULL)
{
return E_OUTOFMEMORY;
}
// 为框架指定名称
hr = AllocateName(Name, (LPSTR * ) & pFrame -> Name);
if (FAILED(hr))
{
delete pFrame;
return hr;
}
// 初始化D3DXFRAME_DERIVED结构其它成员变量
D3DXMatrixIdentity( & pFrame -> TransformationMatrix);
D3DXMatrixIdentity( & pFrame -> CombinedTransformationMatrix);
pFrame -> pMeshContainer = NULL;
pFrame -> pFrameSibling = NULL;
pFrame -> pFrameFirstChild = NULL;
* ppNewFrame = pFrame;
pFrame = NULL;
return hr;
}
// -----------------------------------------------------------------------------
// Desc: 在这里是调用了成员函数 GenerateSkinnedMesh(pMeshContainer);
// 是在这里加载了蒙皮信息
// -----------------------------------------------------------------------------
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 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_DERIVED;
if (pMeshContainer == NULL)
{
return E_OUTOFMEMORY;
}
memset(pMeshContainer, 0 , sizeof (D3DXMESHCONTAINER_DERIVED));
// 填充网格容器结构D3DXMESHCONTAINER_DERIVED的成员
// 为网格指定名称
hr = AllocateName(Name, & pMeshContainer -> Name);
if (FAILED(hr))
{
DestroyMeshContainer(pMeshContainer);
return hr;
}
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))
{
SAFE_RELEASE(pd3dDevice);
DestroyMeshContainer(pMeshContainer);
return hr;
}
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)
|| (pMeshContainer -> ppTextures == NULL))
{
hr = E_OUTOFMEMORY;
SAFE_RELEASE(pd3dDevice);
DestroyMeshContainer(pMeshContainer);
return hr;
}
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);
pMeshContainer -> pMaterials -> MatD3D.Ambient = pMeshContainer -> pMaterials -> MatD3D.Diffuse;
for (iMaterial = 0 ; iMaterial < NumMaterials; iMaterial ++ )
{
if (pMeshContainer -> pMaterials[iMaterial].pTextureFilename != NULL)
{
WCHAR strTexturePath[MAX_PATH];
WCHAR wszBuf[MAX_PATH];
// 从纹理文件路径提取纹理文件名
RemovePathFromFileName(pMeshContainer -> pMaterials[iMaterial].pTextureFilename, wszBuf);
// 根据纹理文件名从事先指定的路径查找纹理文件
DXUTFindDXSDKMediaFileCch( strTexturePath, MAX_PATH, wszBuf );
if ( FAILED( D3DXCreateTextureFromFile( pd3dDevice, strTexturePath,
& pMeshContainer -> ppTextures[iMaterial] ) ) )
pMeshContainer -> ppTextures[iMaterial] = 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;
DestroyMeshContainer(pMeshContainer);
return hr;
}
// 保存每块骨骼的初始变换矩阵
for (UINT iBone = 0 ; iBone < cBones; iBone ++ )
{
pMeshContainer -> pBoneOffsetMatrices[iBone] = * (pMeshContainer -> pSkinInfo -> GetBoneOffsetMatrix(iBone));
}
// 生成蒙皮网格模型
hr = GenerateSkinnedMesh(pd3dDevice, pMeshContainer);
if (FAILED(hr))
{
DestroyMeshContainer(pMeshContainer);
return hr;
}
}
* ppNewMeshContainer = pMeshContainer;
pMeshContainer = NULL;
SAFE_RELEASE(pd3dDevice);
return hr;
}
// -----------------------------------------------------------------------------
// Desc: 生成蒙皮网格模型(含有每个顶点的混合权重、索引和一个骨骼组合表)
// -----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::GenerateSkinnedMesh( IDirect3DDevice9 * pd3dDevice,
D3DXMESHCONTAINER_DERIVED * pMeshContainer )
{
HRESULT hr = S_OK;
if ( pMeshContainer -> pSkinInfo == NULL )
return hr;
SAFE_RELEASE( pMeshContainer -> MeshData.pMesh );
SAFE_RELEASE( pMeshContainer -> pBoneCombinationBuf );
// 获取当前设备的能力
D3DCAPS9 d3dCaps;
pd3dDevice -> GetDeviceCaps( & d3dCaps );
pMeshContainer -> NumPaletteEntries = min( 26 , pMeshContainer -> pSkinInfo -> GetNumBones());
DWORD Flags = D3DXMESHOPT_VERTEXCACHE;
if (d3dCaps.VertexShaderVersion >= D3DVS_VERSION( 1 , 1 ))
{
pMeshContainer -> UseSoftwareVP = false ;
Flags |= D3DXMESH_MANAGED;
}
else
{
pMeshContainer -> UseSoftwareVP = 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))
return hr;
// FVF has to match our declarator. Vertex shaders are not as forgiving as FF pipeline
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))
return hr;
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))
return hr;
// allocate a buffer for bone matrices,
if ( g_NumBoneMatricesMax < pMeshContainer -> pSkinInfo -> GetNumBones() )
{
g_NumBoneMatricesMax = pMeshContainer -> pSkinInfo -> GetNumBones();
// Allocate space for blend matrices
delete[] g_pBoneMatrices;
g_pBoneMatrices = new D3DXMATRIXA16[g_NumBoneMatricesMax];
if ( g_pBoneMatrices == NULL )
{
hr = E_OUTOFMEMORY;
return hr;
}
}
return hr;
}
// -----------------------------------------------------------------------------
// Desc: 释放框架
// -----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::DestroyFrame(LPD3DXFRAME pFrameToFree)
{
if (pFrameToFree != NULL)
{
SAFE_DELETE_ARRAY( pFrameToFree -> Name );
SAFE_DELETE( pFrameToFree );
}
return S_OK;
}
// -----------------------------------------------------------------------------
// Desc: 释放网格容器
// -----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER pMeshContainerBase)
{
if (pMeshContainerBase == NULL)
return S_OK;
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;
}
// -----------------------------------------------------------------------------
// Desc: 入口函数
// -----------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
// 为Debug配置启用运行时内存检查功能
#if defined(DEBUG) | defined(_DEBUG)
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
// 设置回调函数
DXUTSetCallbackDeviceCreated( OnCreateDevice );
DXUTSetCallbackDeviceReset( OnResetDevice );
DXUTSetCallbackDeviceLost( OnLostDevice );
DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
DXUTSetCallbackMsgProc( MsgProc );
DXUTSetCallbackKeyboard( KeyboardProc );
DXUTSetCallbackFrameRender( OnFrameRender );
DXUTSetCallbackFrameMove( OnFrameMove );
// 应用程序相关的初始化
InitApp();
// 初始化DXUT, 创建窗口, 创建Direct3D设备对象
DXUTInit( true , true , true );
DXUTSetCursorSettings( true , true );
DXUTCreateWindow( L " HLSLSkinMesh " );
DXUTCreateDevice( D3DADAPTER_DEFAULT, true , 640 , 480 ,
IsDeviceAcceptable, ModifyDeviceSettings );
// 进入消息循环和场景渲染
DXUTMainLoop();
// 在此进行应用程序相关的清除工作
delete[] g_pBoneMatrices;
return DXUTGetExitCode();
}
// -----------------------------------------------------------------------------
// Desc: 应用程序相关初始化
// -----------------------------------------------------------------------------
void InitApp()
{
// 初始化对话框
g_SettingsDlg.Init( & g_DialogResourceManager );
g_HUD.Init( & g_DialogResourceManager );
g_SampleUI.Init( & g_DialogResourceManager );
// 为g_HUD对话框设置消息处理函数,添加控件
g_HUD.SetCallback( OnGUIEvent ); int iY = 10 ;
g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L " Toggle full screen " , 35 , iY, 125 , 22 );
g_HUD.AddButton( IDC_TOGGLEREF, L " Toggle REF (F3) " , 35 , iY += 24 , 125 , 22 );
g_HUD.AddButton( IDC_CHANGEDEVICE, L " Change device (F2) " , 35 , iY += 24 , 125 , 22 , VK_F2 );
}
// -----------------------------------------------------------------------------
// Desc: 设备能力检查
// -----------------------------------------------------------------------------
bool CALLBACK IsDeviceAcceptable( D3DCAPS9 * pCaps, D3DFORMAT AdapterFormat,
D3DFORMAT BackBufferFormat, bool bWindowed,
void * pUserContext )
{
// 检查后台缓冲区格式是否支持Alpha混合等操作(post pixel blending operations)
IDirect3D9 * pD3D = DXUTGetD3DObject();
if ( FAILED( pD3D -> CheckDeviceFormat( pCaps -> AdapterOrdinal, pCaps -> DeviceType,
AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING,
D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
return false ;
// 检查当前设备支持顶点渲染器版本是否符合要求
if ( pCaps -> VertexShaderVersion < D3DVS_VERSION( 1 , 1 ) )
return FALSE;
return true ;
}
// -----------------------------------------------------------------------------
// Desc: 修改Direct3D渲染设备设置
// -----------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings * pDeviceSettings,
const D3DCAPS9 * pCaps, void * pUserContext )
{
// 如果不支持硬件顶点处理则使用软件顶点处理
if ( (pCaps -> DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 )
{
pDeviceSettings -> BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
// 如果使用纯硬件顶点处理模式则改为混合顶点处理模式
if ( pDeviceSettings -> BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING )
pDeviceSettings -> BehaviorFlags = D3DCREATE_MIXED_VERTEXPROCESSING;
// 调试顶点渲染器需要参考设备或软件顶点处理
#ifdef DEBUG_VS
if ( pDeviceSettings -> DeviceType != D3DDEVTYPE_REF )
{
pDeviceSettings -> BehaviorFlags &= ~ D3DCREATE_HARDWARE_VERTEXPROCESSING;
pDeviceSettings -> BehaviorFlags &= ~ D3DCREATE_PUREDEVICE;
pDeviceSettings -> BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
#endif
// 调试像素渲染器需要参考设备
#ifdef DEBUG_PS
pDeviceSettings -> DeviceType = D3DDEVTYPE_REF;
#endif
// 如果使用参考设备,则弹出警告对话框
static bool s_bFirstTime = true ;
if ( s_bFirstTime )
{
s_bFirstTime = false ;
if ( pDeviceSettings -> DeviceType == D3DDEVTYPE_REF )
DXUTDisplaySwitchingToREFWarning();
}
return true ;
}
// -----------------------------------------------------------------------------
// Desc: 在此创建管理内存资源对象
// -----------------------------------------------------------------------------
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9 * pd3dDevice,
const D3DSURFACE_DESC * pBackBufferSurfaceDesc,
void * pUserContext )
{
HRESULT hr;
V_RETURN( g_DialogResourceManager.OnCreateDevice( pd3dDevice ) );
V_RETURN( g_SettingsDlg.OnCreateDevice( pd3dDevice ) );
// 创建字体
V_RETURN( D3DXCreateFont( pd3dDevice, 15 , 0 , FW_BOLD, 1 , FALSE, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
L " Arial " , & g_pFont ) );
// 创建效果
DWORD dwShaderFlags = D3DXFX_NOT_CLONEABLE;
#ifdef DEBUG_VS
dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
#endif
#ifdef DEBUG_PS
dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
#endif
V_RETURN(D3DXCreateEffectFromFile( pd3dDevice, L " HLSLSkinMesh.fx " , NULL, NULL,
dwShaderFlags, NULL, & g_pEffect, NULL ));
// 创建网格模型
CAllocateHierarchy Alloc;
V_RETURN(D3DXLoadMeshHierarchyFromX( L " tiny.x " , D3DXMESH_MANAGED, pd3dDevice,
& Alloc, NULL, & g_pFrameRoot, & g_pAnimController ));
SetupBoneMatrixPointers( g_pFrameRoot );
return S_OK;
}
// -----------------------------------------------------------------------------
// Desc: 在此创建默认内存类型资源对象
// -----------------------------------------------------------------------------
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9 * pd3dDevice,
const D3DSURFACE_DESC * pBackBufferSurfaceDesc,
void * pUserContext )
{
HRESULT hr;
V_RETURN( g_DialogResourceManager.OnResetDevice() );
V_RETURN( g_SettingsDlg.OnResetDevice() );
// 设置对话框位置和尺寸
g_HUD.SetLocation( pBackBufferSurfaceDesc -> Width - 170 , 0 );
g_HUD.SetSize( 170 , 170 );
g_SampleUI.SetLocation( pBackBufferSurfaceDesc -> Width - 170 ,
pBackBufferSurfaceDesc -> Height - 350 );
g_SampleUI.SetSize( 170 , 300 );
// 恢复字体
if ( g_pFont )
V_RETURN( g_pFont -> OnResetDevice() );
// 创建ID3DXSprite接口对象
V_RETURN( D3DXCreateSprite( pd3dDevice, & g_pTextSprite ) );
// 恢复效果对象
if ( g_pEffect )
V_RETURN( g_pEffect -> OnResetDevice() );
// 构造世界矩阵
D3DXMatrixTranslation( & g_matWorld, 0 , 30 , - 100 );
// 构造观察矩阵
D3DXVECTOR3 vEye( 0 , 0 , - 1000 );
D3DXVECTOR3 vAt( 0 , 0 , 0 );
D3DXVECTOR3 vUp( 0 , 1 , 0 );
D3DXMatrixLookAtLH( & g_matView, & vEye, & vAt, & vUp);
// 构造投影矩阵
D3DXMATRIXA16 matProj;
float fAspectRatio = ( float )pBackBufferSurfaceDesc -> Width / pBackBufferSurfaceDesc -> Height;
D3DXMatrixPerspectiveFovLH( & matProj, D3DX_PI / 4 , fAspectRatio, 1.0f , 2000.0f );;
// 为效果设置影矩阵
V( g_pEffect -> SetMatrix( " mProj " , & matProj ) );
// 为效果设置灯光方向
D3DXVECTOR4 vLightDir( 0.0f , 1.0f , - 1.0f , 0.0f );
D3DXVec4Normalize( & vLightDir, & vLightDir );
V( g_pEffect -> SetVector( " lightDir " , & vLightDir) );
return S_OK;
}
// -----------------------------------------------------------------------------
// Desc: 更新场景
// -----------------------------------------------------------------------------
void CALLBACK OnFrameMove( IDirect3DDevice9 * pd3dDevice, double fTime,
float fElapsedTime, void * pUserContext )
{
}
// ------------------------------------------------------------------------------
// Desc: 渲染网格模型
// ------------------------------------------------------------------------------
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 iAttrib;
LPD3DXBONECOMBINATION pBoneComb;
UINT iMatrixIndex;
UINT iPaletteEntry;
D3DXMATRIXA16 matTemp;
D3DCAPS9 d3dCaps;
pd3dDevice -> GetDeviceCaps( & d3dCaps );
// 检查是否是蒙皮网格模型
if (pMeshContainer -> pSkinInfo != NULL)
{
if (pMeshContainer -> UseSoftwareVP)
{
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( 0.25 , 0.25 , 0.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) );
/// 设置纹理
V( pd3dDevice -> SetTexture( 0 , pMeshContainer -> ppTextures[pBoneComb[iAttrib].AttribId] ) );
// 设置当前骨骼数量
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) );
}
if (pMeshContainer -> UseSoftwareVP)
{
V( pd3dDevice -> SetSoftwareVertexProcessing(FALSE) );
}
}
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 );
}
}
// -----------------------------------------------------------------------------
// Desc: 渲染场景
// -----------------------------------------------------------------------------
void CALLBACK OnFrameRender( IDirect3DDevice9 * pd3dDevice, double fTime,
float fElapsedTime, void * pUserContext )
{
HRESULT hr;
// 如果正在利用Direct3D设备设置对话框进行设置, 则不渲染场景
if ( g_SettingsDlg.IsActive() )
{
g_SettingsDlg.OnRender( fElapsedTime );
return ;
}
// 清除后台颜色缓冲区和深度缓冲区
V( pd3dDevice -> Clear( 0 , NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
D3DCOLOR_ARGB( 0 , 45 , 50 , 170 ), 1.0f , 0 ) );
// 渲染场景
if ( SUCCEEDED( pd3dDevice -> BeginScene() ) )
{
// 渲染网格模型
if ( g_pAnimController != NULL )
g_pAnimController -> AdvanceTime( fElapsedTime, NULL );
UpdateFrameMatrices( g_pFrameRoot, & g_matWorld );
DrawFrame( pd3dDevice, g_pFrameRoot );
// 渲染文本和控件
DXUT_BeginPerfEvent( DXUT_PERFEVENTCOLOR, L " HUD / Stats " );
RenderText();
V( g_HUD.OnRender( fElapsedTime ) );
V( g_SampleUI.OnRender( fElapsedTime ) );
DXUT_EndPerfEvent();
V( pd3dDevice -> EndScene() );
}
}
// -----------------------------------------------------------------------------
// Desc: 渲染文本
// -----------------------------------------------------------------------------
void RenderText()
{
CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite, 15 );
// 显示当前Direct3D设备状态和渲染帧速率
txtHelper.Begin();
txtHelper.SetInsertionPos( 5 , 5 );
txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f , 1.0f , 0.0f , 1.0f ) );
txtHelper.DrawTextLine( DXUTGetFrameStats( true ) );
txtHelper.DrawTextLine( DXUTGetDeviceStats() );
// 显示其他简要信息
txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f , 1.0f , 1.0f , 1.0f ) );
txtHelper.DrawTextLine( L " 通过HLSL编程实现蒙皮骨骼动画 " );
// 显示简单帮助文本
const D3DSURFACE_DESC * pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc();
if ( g_bShowHelp )
{
txtHelper.SetInsertionPos( 10 , pd3dsdBackBuffer -> Height - 15 * 6 );
txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f , 0.75f , 0.0f , 1.0f ) );
txtHelper.DrawTextLine( L " Controls (F1 to hide): " );
txtHelper.SetInsertionPos( 40 , pd3dsdBackBuffer -> Height - 15 * 5 );
txtHelper.DrawTextLine( L " Quit: ESC " );
}
else
{
txtHelper.SetInsertionPos( 10 , pd3dsdBackBuffer -> Height - 15 * 2 );
txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f , 1.0f , 1.0f , 1.0f ) );
txtHelper.DrawTextLine( L " Press F1 for help " );
}
txtHelper.End();
}
// -----------------------------------------------------------------------------
// Desc: 消息处理
// -----------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
bool * pbNoFurtherProcessing, void * pUserContext )
{
* pbNoFurtherProcessing = g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam );
if ( * pbNoFurtherProcessing )
return 0 ;
if ( g_SettingsDlg.IsActive() )
{
g_SettingsDlg.MsgProc( hWnd, uMsg, wParam, lParam );
return 0 ;
}
* pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
if ( * pbNoFurtherProcessing )
return 0 ;
* pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
if ( * pbNoFurtherProcessing )
return 0 ;
return 0 ;
}
// -----------------------------------------------------------------------------
// Desc: 键盘消息处理
// -----------------------------------------------------------------------------
void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown, void * pUserContext )
{
if ( bKeyDown )
{
switch ( nChar )
{
case VK_F1: g_bShowHelp = ! g_bShowHelp; break ;
}
}
}
// -----------------------------------------------------------------------------
// Desc: 处理各种控件消息
// -----------------------------------------------------------------------------
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl * pControl,
void * pUserContext )
{
switch ( nControlID )
{
case IDC_TOGGLEFULLSCREEN:
DXUTToggleFullScreen();
break ;
case IDC_TOGGLEREF:
DXUTToggleREF();
break ;
case IDC_CHANGEDEVICE:
g_SettingsDlg.SetActive( ! g_SettingsDlg.IsActive() );
break ;
}
}
// -----------------------------------------------------------------------------
// Desc: 释放在OnResetDevice()中创建的资源
// -----------------------------------------------------------------------------
void CALLBACK OnLostDevice( void * pUserContext )
{
g_DialogResourceManager.OnLostDevice();
g_SettingsDlg.OnLostDevice();
if ( g_pFont )
g_pFont -> OnLostDevice();
SAFE_RELEASE( g_pTextSprite );
if ( g_pEffect )
g_pEffect -> OnLostDevice();
}
// ------------------------------------------------------------------------------
// Desc: 释放在OnCreateDevice()中创建的资源
// ------------------------------------------------------------------------------
void CALLBACK OnDestroyDevice( void * pUserContext )
{
g_DialogResourceManager.OnDestroyDevice();
g_SettingsDlg.OnDestroyDevice();
SAFE_RELEASE( g_pFont );
SAFE_RELEASE( g_pEffect );
CAllocateHierarchy Alloc;
D3DXFrameDestroy( g_pFrameRoot, & Alloc );
SAFE_RELEASE( g_pAnimController );
}
// --------------------------------------------------------------------------------------
// Desc: 设置骨骼矩阵
// --------------------------------------------------------------------------------------
HRESULT SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER pMeshContainerBase )
{
UINT iBone, cBones;
D3DXFRAME_DERIVED * pFrame;
D3DXMESHCONTAINER_DERIVED * pMeshContainer = (D3DXMESHCONTAINER_DERIVED * )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_DERIVED * )D3DXFrameFind( g_pFrameRoot,
pMeshContainer -> pSkinInfo -> GetBoneName(iBone) );
if (pFrame == NULL)
return E_FAIL;
pMeshContainer -> ppBoneMatrixPtrs[iBone] = & pFrame -> CombinedTransformationMatrix;
}
}
return S_OK;
}
// --------------------------------------------------------------------------------------
// Desc: 设置骨骼矩阵指针
// --------------------------------------------------------------------------------------
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;
}
// --------------------------------------------------------------------------------------
// update the frame matrices
// --------------------------------------------------------------------------------------
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);
}
}