DirectX9 SDK Samples(15) OptimizedMesh Sample

时间:2022-10-24 17:01:40

优化网格,主要是将triangle list优化成triangle strip。

主要用到的API有:ID3DX10Mesh::Optimize,D3DXConvertMeshSubsetToSingleStrip,D3DXConvertMeshSubsetToStrips

而渲染的时候对应用到的函数有:IDirect3DDevice9::SetStreamSource,IDirect3DDevice9::SetIndices,IDirect3DDevice9::DrawIndexedPrimitive

struct SStripData
{
    LPDIRECT3DINDEXBUFFER9 m_pStrips;          // strip indices (single strip)
    LPDIRECT3DINDEXBUFFER9 m_pStripsMany;      // strip indices (many strips)

    DWORD m_cStripIndices;
    DWORD* m_rgcStripLengths;
    DWORD m_cStrips;
//省略构造函数
};


struct SMeshData
{
    LPD3DXMESH m_pMeshSysMem;      // System memory copy of mesh

    LPD3DXMESH m_pMesh;            // Local version of mesh, copied on resize
    LPDIRECT3DVERTEXBUFFER9 m_pVertexBuffer;    // vertex buffer of mesh

    SStripData* m_rgStripData;      // strip indices split by attribute
    DWORD m_cStripDatas;
//省略析构构造函数
};
上面是两个这次例子定义的结构体。

1OnCreateDevice

    // Load mesh
    hr = LoadMeshData( pd3dDevice, MESHFILENAME, &pMeshSysMem, &pAdjacencyBuffer );
    if( SUCCEEDED( hr ) )
    {
        hr = OptimizeMeshData( pMeshSysMem, pAdjacencyBuffer, D3DXMESHOPT_ATTRSORT, &g_MeshAttrSorted );
        if( SUCCEEDED( hr ) )
            hr = OptimizeMeshData( pMeshSysMem, pAdjacencyBuffer, D3DXMESHOPT_STRIPREORDER, &g_MeshStripReordered );

        if( SUCCEEDED( hr ) )
            hr = OptimizeMeshData( pMeshSysMem, pAdjacencyBuffer,
                                   D3DXMESHOPT_VERTEXCACHE, &g_MeshVertexCacheOptimized );
    //省略
这里用到了自定义函数LoadMeshData,没什么特别,就是载入网格、材质和纹理。

然后分别进行了3种优化,根据属性排序、strip顺序和顶点缓存。


2OptimizeMeshData

    // Attribute sort - the un-optimized mesh option
    // remember the adjacency for the vertex cache optimization
    hr = pMeshSysMem->Optimize( dwOptFlags | D3DXMESH_SYSTEMMEM,
                                ( DWORD* )pAdjacencyBuffer->GetBufferPointer(),
                                NULL, NULL, NULL, &pMeshData->m_pMeshSysMem );
第一种优化,优化效果见注释

    pMeshData->m_cStripDatas = g_dwNumMaterials;
    pMeshData->m_rgStripData = new SStripData[ pMeshData->m_cStripDatas ];
    if( pMeshData->m_rgStripData == NULL )
    {
        hr = E_OUTOFMEMORY;
        goto End;
    }

    g_bCantDoSingleStrip = false;
    for( DWORD iMaterial = 0; iMaterial < g_dwNumMaterials; iMaterial++ )
    {
        hr = D3DXConvertMeshSubsetToSingleStrip( pMeshData->m_pMeshSysMem, iMaterial,
                                                 D3DXMESH_IB_MANAGED, &pMeshData->m_rgStripData[iMaterial].m_pStrips,
                                                 &pMeshData->m_rgStripData[iMaterial].m_cStripIndices );
//检查strip个数是否超出设备支持范围
对每一种材质先进行单个strip优化。
        hr = D3DXConvertMeshSubsetToStrips( pMeshData->m_pMeshSysMem, iMaterial,
                                            D3DXMESH_IB_MANAGED, &pMeshData->m_rgStripData[iMaterial].m_pStripsMany,
                                            NULL, &pbufTemp, &pMeshData->m_rgStripData[iMaterial].m_cStrips );
        pMeshData->m_rgStripData[iMaterial].m_rgcStripLengths = new
            DWORD[pMeshData->m_rgStripData[iMaterial].m_cStrips];
        memcpy( pMeshData->m_rgStripData[iMaterial].m_rgcStripLengths,
                pbufTemp->GetBufferPointer(),
                sizeof( DWORD ) * pMeshData->m_rgStripData[iMaterial].m_cStrips );
然后进行多strip优化。注意,这里pbufTemp返回了各个strip的长度,相当于一个DWORD数组(这里用的DWORD)。

3DrawMeshData

在OnFrameRender中调用。

        for( DWORD iMaterial = 0; iMaterial < g_dwNumMaterials; iMaterial++ )
        {
            if( !g_bShowStrips && !g_bShowSingleStrip )
            {
                V( pMeshData->m_pMesh->DrawSubset( iMaterial ) );
            }
            else  // drawing strips
            {
//省略
                V( pd3dDevice->SetFVF( dwFVF ) );
                V( pd3dDevice->SetStreamSource( 0, pMeshData->m_pVertexBuffer, 0, cBytesPerVertex ) );

                if( g_bShowSingleStrip )
                {
                    if( !g_bCantDoSingleStrip )
                    {
                        V( pd3dDevice->SetIndices( pMeshData->m_rgStripData[iMaterial].m_pStrips ) );

                        V( pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLESTRIP, 0,
                                                             0, pMeshData->m_pMesh->GetNumVertices(),
                                                             0, pMeshData->m_rgStripData[iMaterial].m_cStripIndices -
                                                             2 ) );
                    }
                }
                else
                {
                    V( pd3dDevice->SetIndices( pMeshData->m_rgStripData[iMaterial].m_pStripsMany ) );

                    iCurFace = 0;
                    for( iStrip = 0; iStrip < pMeshData->m_rgStripData[iMaterial].m_cStrips; iStrip++ )
                    {
                        V( pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLESTRIP, 0,
                                                             0, pMeshData->m_pMesh->GetNumVertices(),
                                                             iCurFace,
                                                             pMeshData->m_rgStripData[iMaterial].m_rgcStripLengths[iStrip] ) );

                        iCurFace += 2 + pMeshData->m_rgStripData[iMaterial].m_rgcStripLengths[iStrip];
                    }
                }
            }
        }
其中iCurFace是本次渲染的起始顶点的索引,CurrentFace,其实这名字有歧义,不是Face,而是Vertex。