D3D动画相关接口理解

一、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);
        }
    }

你可能感兴趣的:(D3D动画相关接口理解)