一、D3DXFRAME接口
这里的frame不是帧keyFrame,而是动画子网格和变换的节点Node
有包含了本节点的静态变换,节点关联的网格容器(一个或多个网格),frame网格节点名字,拓展D3DXFRAME_EX中还包含了
Combined matrix 框架节点中的组合变换(累积变换,包括从原始数据(模型坐标系)TransformationMatrix变换开始),
Combined matrix 框架节点中的组合变换(累积变换,包括从原始变换开始)。D3DXFRAME虽然管理了D3DXMESHCONTAINER,但是
更加细化的变换(例如骨骼变换)却是在D3DXMESHCONTAINER中进行的,然后将蒙皮附加到骨骼节点中。
//----------------------------------------------------------------------------
// D3DXFRAME:
// ----------
// This struct is the encapsulates a transform frame in a transformation frame
// hierarchy. The app can derive from this structure to add other app specific
// data to this
//----------------------------------------------------------------------------
typedef struct _D3DXFRAME
{
LPSTR Name;
D3DXMATRIX TransformationMatrix; // 静态的变换,用于赋值给D3DXFRAME_EX的matOriginal
LPD3DXMESHCONTAINER pMeshContainer;
struct _D3DXFRAME *pFrameSibling; // 兄弟节点(包括了变换和网格)
struct _D3DXFRAME *pFrameFirstChild; // 子节点((包括了变换和网格)
} D3DXFRAME, *LPD3DXFRAME;
// 实现了递归查找 和 递归更新frame节点。
struct D3DXFRAME_EX : D3DXFRAME
{
D3DXMATRIX matCombined; // Combined matrix 框架节点中的组合变换(累积变换,包括从原始变换开始)
D3DXMATRIX matOriginal; // Original transformation from .X 框架节点的原始变换
}
二、D3DXMESHCONTAINER接口
网格经常是和材质,效果,纹理一起使用;分开处理各个对象是一件烦恼的事情,能不能合并到一起处理呢,
D3DXMESHCONTAINER就是为了这个目的,设计就是有时候要分离,但是有时候又要结合,此时结合是更好的解耦对于整个引擎来说
。直接用D3DXMESHCONTAINER有网格容器名字,网格数据(普通/LOD/Patch网格),材质信息,邻接信息链表,蒙皮数据,shader
效果文件,下一个网格指针,非常强大。D3DXMESHCONTAINER_EX 还封装了网格的纹理对象(不仅仅是静态材质),皮肤网格,骨
骼原来和变换后的矩阵。
其中:
// data to this.
//----------------------------------------------------------------------------
typedef struct _D3DXMESHCONTAINER
{
LPSTR Name;
D3DXMESHDATA MeshData;
LPD3DXMATERIAL pMaterials;
LPD3DXEFFECTINSTANCE pEffects;
DWORD NumMaterials;
DWORD *pAdjacency;
LPD3DXSKININFO pSkinInfo;
struct _D3DXMESHCONTAINER *pNextMeshContainer;//下一个网格容器(其实就是一个网格链表)
} D3DXMESHCONTAINER, *LPD3DXMESHCONTAINER;
typedef struct _D3DXMESHDATA
{
D3DXMESHDATATYPE Type;
// current mesh data interface
union
{
LPD3DXMESH pMesh;
LPD3DXPMESH pPMesh;
LPD3DXPATCHMESH pPatchMesh;
};
} D3DXMESHDATA, *LPD3DXMESHDATA;
且网格数据的网格对象,还存储了设备指针,绘制时候可以从网格处获取设备指针。
// Get the device interface
pMesh->MeshData.pMesh->GetDevice(&pD3DDevice);
// Setup pointer for mesh to draw, either regular or skinned
ID3DXMesh *pDrawMesh = (!pMesh->pSkinMesh) ? pMesh->MeshData.pMesh : pMesh->pSkinMesh;
struct D3DXMESHCONTAINER_EX : D3DXMESHCONTAINER
{
IDirect3DTexture9 **pTextures;
ID3DXMesh *pSkinMesh;
D3DXMATRIX **ppFrameMatrices;// mesh节点代表的组合变换结果,即mesh容器中的D3DXMATRIX matCombined;
// 骨骼节点相对于mesh节点的偏移基础上,在进行mesh节点偏移(如果有)那么就是世界坐标系了
D3DXMATRIX *pBoneMatrices;
}
三、网格对象和读取网格不同方式
.X模型文件,不支持顶点法向量,通过指定新的顶点格式:D3DFVF_XYZ | D3DFVF_UV | D3DFVF_NORMAL。
可以重新计算顶点缓存,生成新的网格对象,网格对象封装了顶点缓存,索引缓存,属性缓存;创建时候可以获取邻接信息。
材质信息,网格优化时候,可以优化D3DXMESHOPT_ATTRSORT产生属性表提高渲染效率。网格对象可以优化和直接绘制。
可以获取邻接信息关系,可以拷贝生成新的网格/可以生成渐进网格PMesh,可以计算顶点法向量,可以生成球形和BOX包围盒等。
ID3DXBuffer是Void类型指针,声明时传入,使用时候需要强转为指定类型,在网格邻接信息(网格优化/拷贝/LOD网格等)和网格
材质信息(读取材质信息)中使用最多,还有ppEffectInstance也是该类型。
if (FAILED(hr = D3DXLoadMeshFromX(Filename, TempLoadFlags,
pDevice, &AdjacencyBuffer,
&MaterialBuffer, NULL,
&NumMaterials, &pLoadMesh)))
return hr;
// 与D3DXCreateMeshFromXFile不同是用ID3DXFileData作为传入,且获得了ID3DXSkinInfo蒙皮和骨骼权重关联信息数据
// 其实这里都是可以获取效果数据对象的ppEffectInstance。
if (FAILED(hr = D3DXLoadSkinMeshFromXof(pDataObj, TempLoadFlags,
pDevice, &AdjacencyBuffer,
&MaterialBuffer, NULL,
&NumMaterials, &pSkin,
&pLoadMesh)))
return hr;
四、网格对象除了用DrawSubset还可以获取顶点和索引缓存进行渲染,在使用着色器框架中需要这样操作
// Get mesh buffer pointers
IDirect3DVertexBuffer9 *pVB = NULL;
IDirect3DIndexBuffer9 *pIB = NULL;
pMesh->MeshData.pMesh->GetVertexBuffer(&pVB);
pMesh->MeshData.pMesh->GetIndexBuffer(&pIB);
// Get attribute table
DWORD NumAttributes;
D3DXATTRIBUTERANGE *pAttributes = NULL;
pMesh->MeshData.pMesh->GetAttributeTable(NULL, &NumAttributes);
pAttributes = new D3DXATTRIBUTERANGE[NumAttributes];
pMesh->MeshData.pMesh->GetAttributeTable(pAttributes, &NumAttributes);
// Use the vertex shader interface passed
pD3DDevice->SetFVF(NULL);
pD3DDevice->SetVertexShader(pShader);
pD3DDevice->SetVertexDeclaration(pDecl);
// Set stream sources
pD3DDevice->SetStreamSource(0, pVB, 0, D3DXGetFVFVertexSize(pMesh->MeshData.pMesh->GetFVF()));
pD3DDevice->SetIndices(pIB);
// Go through each attribute group and render
for (DWORD i = 0; i < NumAttributes; i++) {
if (pAttributes[i].FaceCount) {
// Get material number
DWORD MatNum = pAttributes[i].AttribId;
// Set texture
pD3DDevice->SetTexture(0, pMesh->pTextures[MatNum]);
// Enable or disable alpha blending per material
if (pMesh->pMaterials[i].MatD3D.Diffuse.a != 1.0f) {
if (LastState != TRUE) {
LastState = TRUE;
pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
pD3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);//SRCCOLOR);
pD3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_DESTCOLOR);
}
}
else {
if (LastState != FALSE) {
LastState = FALSE;
pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
}
}
// Draw the mesh subset
pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0,
pAttributes[i].VertexStart,
pAttributes[i].VertexCount,
pAttributes[i].FaceStart * 3,
pAttributes[i].FaceCount);
}
}