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: 主程序源文件
//=============================================================================
#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);
}
}
posted on 2008-04-16 11:01
七星重劍 閱讀(1304)
評論(0) 編輯 收藏 引用 所屬分類:
Game Graphics