zoukankan      html  css  js  c++  java
  • 几种空间分割算法研究之bsp

    BSP:

    二叉分割树,是一种分割场景的方法,下面代码是BSP树一种实现可运行:

    运行例子中,将定义的16个空间面,分割为一个深度是3的BSP树,上图显示的是运行结果:

    #include "stdafx.h"

    #include <map>

    #include <vector>

    #include <iostream>

    using namespace std;

    //定义空间的点结构

    struct point

    {

         float x,y,z;

         point():x(0.0f),y(0.0f),z(0.0f){};

         point(float a,float b,float c):x(a),y(b),z(c){}

         void operator += (int n)

         {

             x += n;

             y += n;

             z += n;

         }

         void operator = (point& p)

         {

             memcpy(this,(void*)&p,sizeof(*this));

         }

    };

    //定义空间的面结构

    struct face

    {

         point P[3];

         void operator +=(int n)

         {

             P[0] += n;

             P[1] += n;

             P[2] += n;

         }

    };

    //定义包围盒结构

    struct BBox

    {

         point Min;

         point Max;

         BBox():Min(),Max(){}

    };

    enum EAxis

    {//沿的轴枚举

         Axis_X,

         Axis_Y,

         Axis_Z,

    };

    //树节点的定义

    struct TreeNode

    {

         TreeNode():box(),nDepth(0),pLChild(NULL),pRChild(NULL),Axis(Axis_X),Split(0.0f){vFaceId.reserve(16);}

         int nDepth;

         TreeNode* pLChild;

         TreeNode* pRChild;

         std::vector<int> vFaceId;

         int Axis;

         BBox box;

         float Split;

    };

    //存储空间的面

    std::map<int,face> m_mFace;

    //通过面ID获取面的地址

    face* GetFaceByID(int nID)

    {

         std::map<int,face>::iterator itr = m_mFace.find(nID);

         if (itr != m_mFace.end() )

         {

             return &(m_mFace[nID]);

         }

         return NULL;

    }

    //BSP类的定义实现

    class BspTree

    {

    public:

         BspTree():m_pRoot(NULL){};

         ~BspTree()

         {

             if (m_pRoot)

             {

                  DeleteNode(m_pRoot);

             }

         }

         //初始化树根

         void InitTreeRoot(TreeNode *pNode);

         //释放整个树的资源

         void DeleteNode(TreeNode * pNode);

         //生成AABB包围盒

         void BuildAABB(TreeNode * pNode);

         //切分整个空间

         void SplitSpace(TreeNode* pRoot,int nAxis,int ndepth);

         //切分面

         void SplitFace( int nFaceId, float fSplit, int nAxis, int* pLeftNum, int* pRightNum, int* pBothNum );

         //遍历整个树

         void ErgodicTree(TreeNode * pNode);

    protected:

    private:

         TreeNode *m_pRoot;

    };

    void BspTree::InitTreeRoot(TreeNode *pNode)

    {

         if (pNode == NULL)

             return;

         m_pRoot = pNode;

    }

    void BspTree::DeleteNode(TreeNode * pNode)

    {

         if (pNode == NULL)

             return;

         DeleteNode(pNode->pLChild);

         DeleteNode(pNode->pRChild);

         delete pNode;

    }

    //遍历整个树

    void BspTree::ErgodicTree(TreeNode * pNode)

    {

         if (pNode == NULL)

             return;

     

         ErgodicTree(pNode->pLChild);

         cout<<"节点深度: "<<pNode->nDepth<<"含有多少个面: "<<pNode->vFaceId.size();

         switch (pNode->Axis)

         {

         case Axis_X:

             {

                  cout<<" 沿X轴分割"<<"分割点是: x ="<<pNode->Split<<endl;

                  break;

             }

         case Axis_Y:

             {

                  cout<<" 沿Y轴分割"<<"分割点是: y ="<<pNode->Split<<endl;

                  break;

             }

         case Axis_Z:

             {

                  cout<<" 沿Z轴分割"<<"分割点是: z ="<<pNode->Split<<endl;

                  break;

             }

         }

         ErgodicTree(pNode->pRChild);

        

    }

    void BspTree::BuildAABB(TreeNode * pNode)

    {

         if(!pNode)

             return;

         point Min(1000000,1000000,1000000);

         point Max(-1000000,-1000000,-1000000);

         for(int n = 0; n < pNode->vFaceId.size(); ++n)

         {

             face *pFa = GetFaceByID(n);

             if (pFa == NULL)

                  continue;

             for(int m = 0; m < 3; ++m)

             {

                  if (pFa->P[m].x > Max.x)

                        Max.x = pFa->P[m].x;

                  if (pFa->P[m].y > Max.y)

                       Max.y = pFa->P[m].y;

                  if (pFa->P[m].z > Max.z)

                       Max.z = pFa->P[m].z;

     

                  if (pFa->P[m].x < Min.x)

                       Min.x = pFa->P[m].x;

                  if (pFa->P[m].y < Min.y)

                       Min.y = pFa->P[m].y;

                  if (pFa->P[m].z < Min.z)

                       Min.z = pFa->P[m].z;

             }

         }

         pNode->box.Max = Max;

         pNode->box.Min = Min;

    }

     

    int CompareFloat(float a,float b,float fOff)

    {

         if (abs(a - b) < fOff)

             return 0;

         if ( a > b)

             return 1;

         else

             return -1;

            

    }

    void BspTree::SplitFace( int nFaceId, float fSplit, int nAxis, int* pLeftNum, int* pRightNum, int* pBothNum )

    {

         face* pFace = GetFaceByID(nFaceId);

     

         int nLeftCount = 0;

         int nRightCount = 0;

         int nBothCount = 0;

         float t[3];

         switch( nAxis )

         {

         case Axis_X:

             t[0] = pFace->P[0].x;

             t[1] = pFace->P[1].x;

             t[2] = pFace->P[2].x;

             break;

         case Axis_Y:

             t[0] = pFace->P[0].y;

             t[1] = pFace->P[1].y;

             t[2] = pFace->P[2].y;

             break;

         case Axis_Z:

             t[0] = pFace->P[0].z;

             t[1] = pFace->P[1].z;

             t[2] = pFace->P[2].z;

             break;

         }

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

         {

             int c = CompareFloat( t[i], fSplit ,0.001f);

     

             if( c < 0 )            // 左边

                  nLeftCount++;

             else if( c > 0 )   // 右边

                  nRightCount++;

             else               // 正中间

                  nBothCount++;

         }

         *pLeftNum = nLeftCount;

         *pRightNum = nRightCount;

         *pBothNum = nBothCount;

     

    }

     

    void BspTree::SplitSpace(TreeNode* pRoot,int nAxis,int ndepth)

    {

         if(!pRoot)

             return;

         pRoot->nDepth = ndepth;

         pRoot->Axis = nAxis;

         if (pRoot->vFaceId.size() < 3 || ndepth > 2)

         {

             pRoot->pLChild = NULL;

             pRoot->pRChild = NULL;

             return;

         }

         pRoot->pLChild = new TreeNode;

         pRoot->pRChild = new TreeNode;

     

         pRoot->pLChild->box.Max = pRoot->box.Max;

         pRoot->pLChild->box.Min = pRoot->box.Min;

     

         pRoot->pRChild->box.Max = pRoot->box.Max;

         pRoot->pRChild->box.Min = pRoot->box.Min;

     

     

         nAxis = (int)Axis_X;

         float XLength = pRoot->box.Max.x - pRoot->box.Min.x;

         float YLength = pRoot->box.Max.y - pRoot->box.Min.y;

         float ZLength = pRoot->box.Max.z - pRoot->box.Min.z;

         if (YLength > XLength)

         {

             nAxis = Axis_Y;

             XLength = YLength;

         }

         if (ZLength > XLength)

         {

             nAxis = Axis_Z;

         }

         float fslit = 0.0f;

         switch (nAxis)

         {

         case Axis_X:

             {

                  fslit = (pRoot->box.Max.x + pRoot->box.Min.x)/2.0;

                  pRoot->pLChild->box.Max.x = fslit;

                  pRoot->pRChild->box.Min.x = fslit;

     

             }break;

         case Axis_Y:

             {

                  fslit = (pRoot->box.Max.y + pRoot->box.Min.y)/2.0;

                  pRoot->pLChild->box.Max.y = fslit;

                  pRoot->pRChild->box.Min.y = fslit;

             }break;

         case Axis_Z:

             {

                  fslit = (pRoot->box.Max.z + pRoot->box.Min.z)/2.0;

                  pRoot->pLChild->box.Max.z = fslit;

                  pRoot->pRChild->box.Min.z = fslit;

             }break;

         }

         pRoot->Split = fslit;

     

         int nSize = pRoot->vFaceId.size();

     

         int nLeftCount,nRightCount,nBothCount;

         for (int n = 0; n < nSize; ++n)

         {

             SplitFace(pRoot->vFaceId.at(n),fslit,nAxis,&nLeftCount,&nRightCount,&nBothCount);

             // 如果左边有

             if( nLeftCount > 0 || nBothCount > 0 )

                  pRoot->pLChild->vFaceId.push_back( pRoot->vFaceId.at(n) );

             if( nRightCount > 0 || nBothCount > 0 )

                  pRoot->pRChild->vFaceId.push_back( pRoot->vFaceId.at(n) );

         }

         pRoot->vFaceId.clear();

         // 递归

         SplitSpace( pRoot->pLChild, nAxis , ndepth+1);

         SplitSpace( pRoot->pRChild, nAxis , ndepth+1);

    }

    int _tmain(int argc, _TCHAR* argv[])

    {

         BspTree bspTree;

         TreeNode *pRoot = new TreeNode;

         face fa;

         fa.P[0].x = -10;fa.P[0].y = -10;fa.P[0].z = -10;

         fa.P[1].x = 2;fa.P[1].y = 2;fa.P[1].z = 2;

         fa.P[2].x = 5;fa.P[2].y = 5;fa.P[2].z = 5;

         for (int n = 0; n < 16; ++n)

         {

             if (n % 5 == 0)

                  fa += 2*(-n);

             else

                  fa += 2*n;

             m_mFace[n] = fa;

             pRoot->vFaceId.push_back(n);

         }

         bspTree.InitTreeRoot(pRoot);

         bspTree.BuildAABB(pRoot);

         bspTree.SplitSpace(pRoot,0,0);

         bspTree.ErgodicTree(pRoot);

     

         getchar();

         return 0;}

  • 相关阅读:
    fiddler的使用
    redis pipeline
    redis hash map
    redis队列的实现
    PHP-redis中文文档-命令
    websocket
    c++之socket,阻塞模式
    Django上传文件和修改date格式
    通过字符串导入模块
    'CSRFCheck' object has no attribute 'process_request' 报错
  • 原文地址:https://www.cnblogs.com/chunlinge/p/3768573.html
Copyright © 2011-2022 走看看