蒙皮骨骼動畫網格模型接口是對上一節骨骼動畫網格模型接口的擴展,添加了處理蒙皮信息的功能。
進一步擴展結構體D3DXMESHCONTAINER
為了在網格模型中包含蒙皮信息,需要進一步擴展D3DXMESHCONTAINER_DERIVEED,其定義如下:
struct D3DXMESHCONTAINER_DERIVED : public D3DXMESHCONTAINER
{
IDirect3DTexture9** ppTextures;
ID3DXMesh* pOrgMesh;
DWORD MaxBonesInflPerVertex;
DWORD NumAttrGroups;
ID3DXBuffer* pBoneCombBuffer;
D3DXMATRIX** ppBoneMatrices;
D3DXMATRIX** ppBoneOffsetMatrices;
DWORD NumMatrixPalettes;
bool UseSoftwareVP;
};
當加載原網格模型并由此生成一個蒙皮網格時,會用D3DXMESHCONTAINER::MeshData::pMesh存儲所生成的蒙皮網格模型,這時需要將初始網格模型保存下來,這就是pOrgMesh的作用。變量MaxBonesInflPerVertex表示每個頂點最多受多少骨骼的影響,指針變量pBoneCombBuffer指向骨骼結合表,骨骼結合表中的數據按屬性組結構體D3DXBONECOMBINATION組織起來,該結構體定義如下:
Describes a subset of the mesh that has the same
attribute and bone combination.
typedef struct D3DXBONECOMBINATION {
DWORD AttribId;
DWORD FaceStart;
DWORD FaceCount;
DWORD VertexStart;
DWORD VertexCount;
DWORD * BoneId;
} D3DXBONECOMBINATION, *LPD3DXBONECOMBINATION;
Members
- AttribId
- Attribute table identifier.
- FaceStart
- Starting face.
- FaceCount
- Face count.
- VertexStart
- Starting vertex.
- VertexCount
- Vertex count.
- BoneId
Pointer to an array of values that identify each of
the bones that can be drawn in a single drawing call. Note that the array
can be of variable length to accommodate variable length bone combinations
of ID3DXSkinInfo::ConvertToIndexedBlendedMesh.
- The size of the array varies based on the type of
mesh generated. A non-indexed mesh array size is equal to the number of
weights per vertex (pMaxVertexInfl in ID3DXSkinInfo::ConvertToBlendedMesh).
An indexed mesh array size is equal to the number of bone matrix palette
entries (paletteSize in ID3DXSkinInfo::ConvertToIndexedBlendedMesh).
Remarks
The subset of the mesh described by
D3DXBONECOMBINATION can be rendered in a single drawing call.
結構體D3DXBONECOMBINATION用來描述網格中具有同樣屬性的部分,也就是網格模型的一個子集,這個網格模型子集也稱為屬性組。屬性組實際上是用來標識網格模型中被指定的骨骼矩陣所影響的子網格,不同屬性組所標識的子網格需要用不同的紋理、材質進行渲染,該子網格可以通過調用函數DrawIndexedPrimitive()或者DrawSubset()進行繪制。
成員變量BoneId指向一個數組,該數組表示的是在單獨的一次繪制中,即一次DrawSubset()函數調用中所用到的全部骨骼矩陣,該數組的大小與將要生成的蒙皮網格類型有關,在索引頂點混合蒙皮網格中,它的大小等于函數ConvertToIndexedBlendedMesh()中的輸入參數paletteSize,也就是結構體D3DXMESHCONTAINER_DERIVEED的成員變量NumMatrixPalettes。變量NumMatrixPalettes表示進行索引頂點混合時所需要的矩陣調色板的容量,它的數值需要根據硬件設備能力進行相應的設置。
cAllocateHierarchy類的設計實現
蒙皮骨骼動畫網格模型接口中cAllocateHierarchy類和骨骼動畫網格模型接口中的cAllocateHierarchy類基本相同,區別較大的是CreateMeshContainer()函數中增加了對蒙皮信息的處理:
// generate skin mesh
if(skin_info != NULL)
{
new_mesh_container->pSkinInfo = skin_info;
skin_info->AddRef();
new_mesh_container->pOrgMesh = mesh_ptr;
mesh_ptr->AddRef();
UINT num_bones = skin_info->GetNumBones();
new_mesh_container->ppBoneOffsetMatrices = new D3DXMATRIX*[num_bones];
if(new_mesh_container->ppBoneOffsetMatrices == NULL)
{
DestroyMeshContainer(new_mesh_container);
return E_OUTOFMEMORY;
}
for(UINT i = 0; i < num_bones; i++)
new_mesh_container->ppBoneOffsetMatrices[i] = new_mesh_container->pSkinInfo->GetBoneOffsetMatrix(i);
hr = GenerateSkinnedMesh(new_mesh_container);
if(FAILED(hr))
{
DestroyMeshContainer(new_mesh_container);
return hr;
}
}
CreateMeshContainer()函數中處理蒙皮信息的關鍵是調用自定義函數GenerateSkinnedMesh()來生成蒙皮網格模型,其定義如下:
HRESULT cAllocateHierarchy::GenerateSkinnedMesh(D3DXMESHCONTAINER_DERIVED* mesh_container)
{
ID3DXSkinInfo* skin_info = mesh_container->pSkinInfo;
if(skin_info == NULL)
return S_OK;
release_com(mesh_container->MeshData.pMesh);
release_com(mesh_container->pBoneCombBuffer);
HRESULT hr;
IDirect3DIndexBuffer9* index_buffer;
if(FAILED(hr = mesh_container->pOrgMesh->GetIndexBuffer(&index_buffer)))
return hr;
DWORD max_faces_infl_per_triangle;
hr = skin_info->GetMaxFaceInfluences(index_buffer, mesh_container->pOrgMesh->GetNumFaces(),
&max_faces_infl_per_triangle);
index_buffer->Release();
if(FAILED(hr))
return hr;
max_faces_infl_per_triangle = min(max_faces_infl_per_triangle, 12);
IDirect3DDevice9* device = DXUTGetD3DDevice();
D3DCAPS9 caps;
device->GetDeviceCaps(&caps);
if((caps.MaxVertexBlendMatrixIndex+1)/2 < max_faces_infl_per_triangle)
{
// use software vertex processing
mesh_container->NumMatrixPalettes = min(256, skin_info->GetNumBones());
mesh_container->UseSoftwareVP = true;
}
else
{
// use hardware verterx processing
mesh_container->NumMatrixPalettes = min((caps.MaxVertexBlendMatrixIndex+1)/2, skin_info->GetNumBones());
mesh_container->UseSoftwareVP = false;
}
hr = skin_info->ConvertToIndexedBlendedMesh(mesh_container->pOrgMesh, 0, mesh_container->NumMatrixPalettes,
mesh_container->pAdjacency, NULL, NULL, NULL, &mesh_container->MaxBonesInflPerVertex,
&mesh_container->NumAttrGroups, &mesh_container->pBoneCombBuffer, &mesh_container->MeshData.pMesh);
return hr;
}
函數GenerateSkinnedMesh()判斷當前網格容器是否包含蒙皮信息,如果當前網格模型中不包含蒙皮信息,則直接退出該函數。接下來確定所需要的矩陣調色板的容量,最后調用函數ConvertToIndexedBlendedMesh()根據初始網格模型提供的相應參數生成索引蒙皮網格模型。函數ConvertToIndexedBlendedMesh()的聲明如下:
Takes a mesh and returns a new mesh with per-vertex blend
weights, indices, and a bone combination table. The table describes which bone
palettes affect which subsets of the mesh.
HRESULT ConvertToIndexedBlendedMesh(
LPD3DXMESH pMesh,
DWORD Options,
DWORD paletteSize,
CONST DWORD * pAdjacencyIn,
LPDWORD pAdjacencyOut,
DWORD * pFaceRemap,
LPD3DXBUFFER * ppVertexRemap,
DWORD * pMaxVertexInfl,
DWORD * pNumBoneCombinations,
LPD3DXBUFFER * ppBoneCombinationTable,
LPD3DXMESH * ppMesh
);
Parameters
- pMesh
- [in] The input mesh.
- Options
- [in] Currently unused.
- paletteSize
- [in] Number of bone matrices available for matrix
palette skinning.
- pAdjacencyIn
- [in] Input mesh adjacency information.
- pAdjacencyOut
- [in] Output mesh adjacency information.
- pFaceRemap
- [out] An array of DWORDs, one per face, that
identifies the original mesh face that corresponds to each face in the
blended mesh. If the value supplied for this argument is NULL, face remap
data is not returned.
- ppVertexRemap
- [out] Address of a pointer to an ID3DXBuffer
interface, which contains a DWORD for each vertex that specifies how the new
vertices map to the old vertices. This remap is useful if you need to alter
external data based on the new vertex mapping. This parameter is optional;
NULL may be used.
- pMaxVertexInfl
- [out] Pointer to a DWORD that will contain the
maximum number of bone influences required per vertex for this skinning
method.
- pNumBoneCombinations
- [out] Pointer to the number of bones in the bone
combination table.
- ppBoneCombinationTable
- [out] Pointer to the bone combination table. The
data is organized in a D3DXBONECOMBINATION structure.
- ppMesh
- [out] Pointer to the new mesh.
Return Values
If the method succeeds, the return value is D3D_OK. If
the method fails, the return value can be D3DERR_INVALIDCALL.
Remarks
Each element in the remap arrays specifies the previous
index for that position. For example, if a vertex was in position 3 but has been
remapped to position 5, then the fifth element of pVertexRemap will contain 3.
This method does not run on hardware that does not
support fixed-function vertex blending.