优化网格,主要是将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。