四叉树平面剔除

来源:互联网 发布:软件推广下载 编辑:程序博客网 时间:2024/04/29 18:25

  

四叉树平面剔除文档
       首是这是做平面剔除,当然,如果是空间中的场景管理那就得用八叉树了,四叉树剔除主要的原理如下:
如下图,
首先构造四叉树,对整个需要剔除的区域首先分成四等分( 用粗实线分开 ),即为该节点的四个子节点( 左下子节点,右下子节点,左下子节点,右上子节点等 ),然后再对四个子节点再分成四等分,依此下去,一直分到足够细为止,
       第二步,将判断图元在那个子节点中,比如面1,先检测它可以被四叉树的根节点(整个图)的任一子节点全部包含,如果是则继续判断是否能被其包括面1的那个子节点的任一子节点包含,如果不是则被该节点包含,如果是则依次下去,直到叶子节点,则面1就属于该叶子节点,如果不是则被该节点包含.面1是被根节点的右上子节点的右上子节点包含.
       第三步:视锥剔除:对检测根结果是否在视区内,如果在,则渲染属于根节点的所有图元,下面的话则渲染面3,然后再检测其四个子节点是否可见,因为左上和左下两个子节点完成不可见则直接跳过,因为其左下节点可见,则渲染属于左下子节点的所有图元,再检测左下子节点的四个子节点,有两个子节点可见渲染属于它的所有图元,依此下去,其渲染有3个图元:面3,面2和面1.当然,如果能将图元分散成属于每个子节点就更好,不用可见一点点却要将整个图元全部渲染.

线1
线2
面1
面2
面3

根据以下的思想的代码如下:
四叉树类如下:
class CQuadTree
{
public:
    CQuadTree(void);
public:
    ~CQuadTree(void);
    CQuadTree( enumAttribute attribute );
 
    enumVisible Frustum2D( );
 
    // 渲染所有的图元
    void RenderAllPrimitive( IDirect3DDevice9* pd3dDevice, CCameraPerspective * pCurCamera , float fElapsedTime, D3DVIEWPORT9 * pVP, int nAcross, int nErect );
 
    // 四个子节点
    CQuadTree *pLeftDownChild;
    CQuadTree *pRightDownChild;
    CQuadTree *pLeftUpChild;
    CQuadTree *pRightUpChild;
   
    // 该四叉树的基本范围中最小点
    D3DXVECTOR2 m_Min;
    // 该四叉树的基本范围中最大点
    D3DXVECTOR2 m_Max;
 
    // 对图元进行的判断,判断该图元是否在四叉树的某个子节点内
    bool IsIn( long ID, enumPrimitive primitivetype, D3DXVECTOR2 min, D3DXVECTOR2 max );
    // 构造四叉树
    bool SubDivide( D3DXVECTOR2 min, D3DXVECTOR2 max, int levelsize );
    // 点图元
    std::vector< long > m_vecPoint;
    // 线图元
    std::vector< long > m_vecLine;
    // 面图元
    std::vector< long > m_vecArea;
   
    // 属性类型
    enumAttribute attributetype;
    // 渲染四叉树
    void RenderQuadTree( bool bFrustum, IDirect3DDevice9* pd3dDevice, CCameraPerspective * pCurCamera , float fElapsedTime, D3DVIEWPORT9 * pVP, int nAcross, int nErect );
   
};
第一步:
bool CQuadTree::SubDivide( D3DXVECTOR2 min, D3DXVECTOR2 max, int levelsize )
{
    // 该子节点的区域赋值
    m_Min = min;
    m_Max = max;
   
    // 是否不能再分,如果不能再分则返回
    if( m_Max.x - m_Min.x <= ::MuseREGetTerrain()->GetWidth() / GRIDNUM || levelsize <= 1)
    {
       return false;
    }
   
    // 得到用于子节点的七个点(两个已知),求去求知的五个
    // 下面的中间
    D3DXVECTOR2 DownMid = D3DXVECTOR2( min.x + ::MuseREGetTerrain()->GetWidth() * ( levelsize / 2) /GRIDNUM, min.y    );
    // 中间的左面
    D3DXVECTOR2   MidLeft = D3DXVECTOR2( min.x, min.y + ::MuseREGetTerrain()->GetWidth() * ( levelsize / 2) /GRIDNUM );
 
 
    // 中心
    D3DXVECTOR2 center = D3DXVECTOR2( min.x + ::MuseREGetTerrain()->GetWidth() * ( levelsize / 2) /GRIDNUM,
                                 min.y + ::MuseREGetTerrain()->GetWidth() * ( levelsize / 2) /GRIDNUM );
 
    // 中间的右面
    D3DXVECTOR2 MidRight = D3DXVECTOR2( m_Max.x, min.y + ::MuseREGetTerrain()->GetWidth() * ( levelsize / 2) /GRIDNUM );
    // 上面的中间
    D3DXVECTOR2 UpMid = D3DXVECTOR2( min.x + ::MuseREGetTerrain()->GetWidth() * ( levelsize / 2) /GRIDNUM, m_Max.y);
 
    // 分左下子节点
    pLeftDownChild = new CQuadTree( attributetype );
    pLeftDownChild->SubDivide( m_Min, center, levelsize / 2 );
 
    // 分右下子节点
    pRightDownChild = new CQuadTree( attributetype );
    pRightDownChild->SubDivide( DownMid, MidRight, levelsize / 2 );
 
    // 分左上子节点
    pLeftUpChild = new CQuadTree( attributetype );
    pLeftUpChild->SubDivide( MidLeft, UpMid, levelsize / 2 );
 
    // 分右上子节点
    pRightUpChild = new CQuadTree( attributetype );
    pRightUpChild->SubDivide( center, m_Max, levelsize / 2);
 
    return true;
}
 
第二步,对所有图元做判断.
// 检测当前的图元是否在节点中
bool CQuadTree::IsIn(long ID, enumPrimitive primitivetype, D3DXVECTOR2 min, D3DXVECTOR2 max )
{
    // 是否包含该项图元
    if( min.x > m_Min.x && max.x < m_Max.x && min.y > m_Min.y && max.y < m_Max.y )
    {
       bool bResultLD;
       bool bResultRD;
       bool bResultLU;
       bool bResultRU;
       // 判断该节点是否是叶子节点
       if( pLeftDownChild != NULL || pRightDownChild != NULL || pLeftUpChild != NULL || pRightUpChild != NULL )
       {
           // 是否包含在该子节点中
           bResultLD = pLeftDownChild->IsIn( ID, primitivetype, min, max ) ;
           if( bResultLD )
              return true;
           bResultRD = pRightDownChild->IsIn(ID, primitivetype, min, max );
           if( bResultRD )
              return true;
 
           bResultLU = pLeftUpChild->IsIn( ID, primitivetype, min, max );
           if( bResultLU )
              return true;
 
           bResultRU = pRightUpChild->IsIn( ID, primitivetype, min, max );
           if( bResultRU )
              return true;
       }
       // 如果不属性任一一个子节点加在该节点中
       switch( primitivetype )
       {
       case POINTTYPE:
           m_vecPoint.push_back( ID );
           break;
       case LINETYPE:
           m_vecLine.push_back( ID );
           break;
 
       case AREATYPE:
           m_vecArea.push_back( ID );
           break;
       default:
           break;
       }
 
       return true;
    }
    return false;
 
   
}
第三步,渲染四叉树:
void CQuadTree::RenderQuadTree( bool bFrustum, IDirect3DDevice9* pd3dDevice, CCameraPerspective * pCurCamera , float fElapsedTime, D3DVIEWPORT9 * pVP, int nAcross, int nErect )
{
 
    // 默认是完全可见
    enumVisible visible = TOTALSIGHT;
    // 视锥剔除
    if( bFrustum )
       visible = Frustum2D();  
    // 如果不是完全不可见
    if( visible != TOTALSIGHTLESS )
    {  
       // 渲染所有的图元
       RenderAllPrimitive( pd3dDevice, pCurCamera , fElapsedTime, pVP, nAcross, nErect );
       // 如果是叶子节点
       if( pLeftDownChild == NULL || pRightDownChild == NULL || pLeftUpChild == NULL || pRightUpChild == NULL )
       {
           return;
       }
   
       // 全部可见或该结点的父节点全部可见,bFrustum为false时,不用再做锥除,因为其父节点已经完全可见
       if( !bFrustum || visible == TOTALSIGHT )
       {
           // 渲染所有的子节点且不用再做D的视锥剔除
           pLeftDownChild->RenderQuadTree( false, pd3dDevice, pCurCamera , fElapsedTime, pVP, nAcross, nErect );
           pRightDownChild->RenderQuadTree( false, pd3dDevice, pCurCamera , fElapsedTime, pVP, nAcross, nErect );
           pLeftUpChild->RenderQuadTree( false, pd3dDevice, pCurCamera , fElapsedTime, pVP , nAcross, nErect);
           pRightUpChild->RenderQuadTree( false, pd3dDevice, pCurCamera , fElapsedTime, pVP, nAcross, nErect);
           //
       }
       else
       {
           // 部分可见
           if( visible == PARTILYSIGHT )
           {
              // 渲染所有的子节点且要做D的视锥剔除
              pLeftDownChild->RenderQuadTree( true, pd3dDevice, pCurCamera , fElapsedTime, pVP, nAcross, nErect );
              pRightDownChild->RenderQuadTree( true, pd3dDevice, pCurCamera , fElapsedTime, pVP, nAcross, nErect );
              pLeftUpChild->RenderQuadTree( true , pd3dDevice, pCurCamera , fElapsedTime, pVP, nAcross, nErect);
             pRightUpChild->RenderQuadTree( true, pd3dDevice, pCurCamera , fElapsedTime, pVP, nAcross, nErect);
           }
       }
    }
}
 
原创粉丝点击