Skinned Meshes
April 10, 2022About 2 min
Skinned Meshes
Basics of bone hierarchies
在DX9中使用LPD3DXFRAME作为基础的节点数据结构,内容有:
struct D3DXFRAME {
LPSTR Name; //Name of bone
D3DXMATRIX TransformationMatrix; //Local bone pos, rot & sca
LPD3DXMESHCONTAINER pMeshContainer; //Mesh connected to bone
D3DXFRAME* pFrameSibling; //Sibling bone pointer
D3DXFRAME* pFrameFirstChild; //First child bone
};

值得注意的是这里节点是有同层级的,以下是输出节点的测试代码:
void PrintHierarchy(D3DXFRAME *bone)
{
//Print Bone Name
cout << bone->Name;
//Traverse Siblings
if(bone->pFrameSibling != NULL)
PrintHierarchy(bone->pFrameSibling);
//Traverse Children
if(bone->pFrameFirstChild != NULL)
PrintHierarchy(bone->pFrameSibling);
}
Loading bone hierarchies from an .x file
使用 D3DXLoadMeshHierarchyFromX 方法加载骨骼数据,方法如下:
HRESULT D3DXLoadMeshHierarchyFromX(
LPCSTR Filename,
DWORD MeshOptions,
LPDIRECT3DDEVICE9 pDevice,
LPD3DXALLOCATEHIERARCHY pAlloc,
LPD3DXLOADUSERDATA pUserDataLoader,
LPD3DXFRAME* ppFrameHierarchy,
LPD3DXANIMATIONCONTROLLER* ppAnimController
);
其中需要自定义实现以下ID3DXAllocateHierarchy接口,其中有四个方法需要实现:
HRESULT CreateFrame(LPCSTR Name, LPD3DXFRAME* ppNewFrame) override;
HRESULT CreateMeshContainer(THIS_
LPCSTR Name,
CONST D3DXMESHDATA* pMeshData,
CONST D3DXMATERIAL* pMaterials,
CONST D3DXEFFECTINSTANCE* pEffectInstances,
DWORD NumMaterials,
CONST DWORD* pAdjacency,
LPD3DXSKININFO pSkinInfo,
LPD3DXMESHCONTAINER* ppNewMeshContainer) override;
HRESULT DestroyFrame(LPD3DXFRAME pFrameToFree)override;
HRESULT DestroyMeshContainer(LPD3DXMESHCONTAINER pMeshContainerBase)override;
这个功能主要让我们自定义初始化骨骼节点数据,具体的结构功能如下:
HRESULT BoneHierarchyLoader::CreateMeshContainer(...)
{
//Create new Bone Mesh
...
//Get mesh data here
...
//Copy materials and load textures (like with a static mesh)
...
if(pSkinInfo != NULL)
{
//Store Skin Info and convert mesh to Index Blended Mesh
...
}
//Set ppNewMeshContainer to newly created boneMesh container
...
}
Software skinning
主要的步骤:
- Overload
D3DXFRAM
- Overload
D3DXMESHCONTAINER
- Implement the
ID3DXAllocateHierarchy
interface - Load a bone hierarhy and associated meshes, skinning information, erc, with the
D3DXLoadMeshHierachyFromX()
function - For each frame, update the skeleton pose (i.e. the SkinnedMesh::UpdateMatrices() function)
- Update the target mesh using ID3DXSkinInfo::UpdateSkinnedMesh()
- Render the target mesh as a common static mesh
CPU蒙皮不需要我们自己处理权重计算,应该是boneMesh->pSkinInfo->UpdateSkinnedMesh(boneMesh->currentBoneMatrices, NULL, src, dest);
这个方法里面计算。
Hardware skinning
主要的步骤:
- Overload
D3DXFRAM
- Overload
D3DXMESHCONTAINER
- Implement the
ID3DXAllocateHierarchy
interface - Load a bone hierarhy and associated meshes, skinning information, erc, with the
D3DXLoadMeshHierachyFromX()
function - For each frame, update the skeleton pose (i.e. the SkinnedMesh::UpdateMatrices() function)
- Upload the Matrix Palette (bone matrices) to the vertex shader
- Render the Index Blended Mesh using the vertex shader
GPU蒙皮需要自己在shader中处理权重混合,一个顶点受四根骨骼影响,如下图:

Rendering static meshes in a bone hierarchy
静态mesh还是有骨骼,所以前几个步骤是一样:
- Overload
D3DXFRAM
- Overload
D3DXMESHCONTAINER
- Implement the
ID3DXAllocateHierarchy
interface - Load a bone hierarhy and associated meshes, skinning information, erc, with the
D3DXLoadMeshHierachyFromX()
function - Set bone world transform to the static mesh, in order to animate static with bone
- Render static mesh with
boneMesh->OriginalMesh->DrawSubset(i);