博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

模型的LOD原理

Posted on 2011-06-01 22:00  +石头+  阅读(2630)  评论(0)    收藏  举报

游戏中的场景以及物体在渲染时不是按照一个规格渲染,当距离较远时会渲染较为粗略的模型,这就用到了模型的LOD(Level of Detail)。

LOD功能也就是减少模型的顶点数,主要是用ID3DXPMesh的SetNumVertices方法来设置顶点数。减少的顶点根据顶点的权重来判断。

函数D3DXGeneratePMesh(

LPD3DXMESH pMesh,

CONST DWORD* pAdjacency,

CONST D3DXATTRIBUTEWEIGHTS *pVertexAttributeWeights,

CONST FLOAT *pVertexWeights,

DWORD MinValue,

DWORD Options,


					LPD3DXPMESH* ppPMesh);来从ID3DXMesh转为ID3DXPMesh
					

在转换之前有三个步骤清理,焊接,检查是否有效。我们把每个物体类分为若干个不同顶点数的ID3DXMesh。保存为:
					

typedef struct MeshNodeForLOD

{

    LPD3DXMESH GenMesh;

    LPD3DXMESH LODMeshs[MAXLODLEVEL];

    MeshNodeForLOD(){GenMesh=NULL;ZeroMemory(LODMeshs,MAXLODLEVEL*sizeof(LPD3DXMESH));};

}*LPMESHNODEFORLOD;

我们封装一个函数从ID3DXMesh转为ID3DXPMesh,然后保存多个ID3DXMesh存储在MeshNodeForLOD中。返回MeshNodeForLOD结构体。
						

HRESULT MakeMeshLOD( LPDIRECT3DDEVICE9 DVC,LPD3DXMESH pMesh,DWORD* pAdj,LPMESHNODEFORLOD pMeshNode )

{

    HRESULT hr;

    if ((pMesh==NULL) || (pAdj==NULL) )

    {

        return S_FALSE;

    }

    LPD3DXMESH pTempMesh =NULL; //临时网格模型变量

    //清理

    hr = D3DXCleanMesh( D3DXCLEAN_SIMPLIFICATION, pMesh,pAdj,&pTempMesh,pAdj, NULL ) ;

    if (FAILED(hr)) return hr;

    pMesh->Release();

    pMesh = pTempMesh;

 

    //焊接

    D3DXWELDEPSILONS Epsilons;

    ZeroMemory( &Epsilons, sizeof(D3DXWELDEPSILONS) );

    Epsilons.Normal=0.01;

    Epsilons.Position=0.1;

 

    hr = D3DXWeldVertices( pMesh,D3DXWELDEPSILONS_WELDPARTIALMATCHES,

        &Epsilons,pAdj,pAdj, NULL, NULL );

    if (FAILED(hr)) return hr;

    

    //检查对原始网格模型进行整理、简化之后,还需要检查处理后的网格模型是否有效

    hr = D3DXValidMesh( pMesh, pAdj, NULL );

    if (FAILED(hr)) return hr;

 

    DWORD MaxVetex=pMesh->GetNumVertices();

    LPD3DXPMESH ppMesh=NULL;

    hr = D3DXGeneratePMesh( pMesh, pAdj,NULL, NULL, 1, D3DXMESHSIMP_VERTEX, &ppMesh );

    if (FAILED(hr)) return hr;

 

    MaxVetex=pMesh->GetNumVertices();

 

    for (int i=0;i<MAXLODLEVEL;i++)

    {

        ppMesh->SetNumVertices(MaxVetex*0.8);

        hr=ppMesh->CloneMeshFVF(ppMesh->GetOptions(),ppMesh->GetFVF(),DVC,&pMeshNode->LODMeshs[i]);

        if (FAILED(hr)) return hr;

        MaxVetex=pMeshNode->LODMeshs[i]->GetNumVertices();

        MaxVetex=ppMesh->GetNumVertices();

 

        if( !(pMeshNode->LODMeshs[i]->GetFVF() & D3DFVF_NORMAL) )

        {

            ID3DXMesh* pTempMesh;

            hr=pMeshNode->LODMeshs[i]->CloneMeshFVF( pMeshNode->LODMeshs[i]->GetOptions(),

                pMeshNode->LODMeshs[i]->GetFVF() | D3DFVF_NORMAL,

                DVC, &pTempMesh ) ;

            SAFE_RELEASE( pMeshNode->LODMeshs[i] );

            pMeshNode->LODMeshs[i] = pTempMesh;

        }

        hr=D3DXComputeNormals( pMeshNode->LODMeshs[i], NULL ) ;

    }

 

 

    pMeshNode->GenMesh=pMesh;

 

    SAFE_RELEASE(ppMesh);

    return S_OK;

}

在渲染时,可以选择任意的某个进行渲染。