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