Bsp 空间分割模拟实现

Bsp:二叉分割树,在游戏中用来分割局部空间,方便碰撞检测等的实现。
  1. 下面介绍一种简单易用的分割方法:分割步骤:一、将空间中的所有的面,加入的根部节点。二、遍历根部节点的所有面,分别找到x、y、z的最大最小值,给根节点指定一个合适的包围空间。三、在这个节点的包围空间里找到最长轴、并按这个最长轴的中间点做为新的分割点,遍历该节点的所有面将其分在其左右子节点中。四、返回第2步,直到达到一定限制条件,结束,此时空间已经被分开了。当然闲话不说,贴上实现模拟代码: 
#include "stdafx.h"  
  1.   
  2. #include <map>  
  3. #include <vector>  
  4. #include <iostream>  
  5.   
  6. using namespace std;  
  7. struct point  
  8. {  
  9.     float x,y,z;  
  10.     point():x(0.0f),y(0.0f),z(0.0f){};  
  11.     point(float a,float b,float c):x(a),y(b),z(c){}  
  12.     void operator += (int n)  
  13.     {  
  14.         x += n;  
  15.         y += n;  
  16.         z += n;  
  17.     }  
  18.     void operator = (point& p)  
  19.     {  
  20.         memcpy(this,(void*)&p,sizeof(*this));  
  21.     }  
  22. };  
  23. struct face  
  24. {  
  25.     point P[3];  
  26.     void operator +=(int n)  
  27.     {  
  28.         P[0] += n;  
  29.         P[1] += n;  
  30.         P[2] += n;  
  31.     }  
  32. };  
  33. struct BBox  
  34. {  
  35.     point Min;  
  36.     point Max;  
  37.     BBox():Min(),Max(){}  
  38. };  
  39. enum EAxis  
  40. {  
  41.     Axis_X,  
  42.     Axis_Y,  
  43.     Axis_Z,  
  44. };  
  45. struct TreeNode   
  46. {  
  47.     TreeNode():box(),nDepth(0),pLChild(NULL),pRChild(NULL),Axis(Axis_X),Split(0.0f){vFaceId.reserve(16);}  
  48.     int nDepth;  
  49.     TreeNode* pLChild;  
  50.     TreeNode* pRChild;  
  51.     std::vector<int> vFaceId;  
  52.     int Axis;  
  53.     BBox box;  
  54.     float Split;  
  55. };  
  56. std::map<int,face> m_mFace;  
  57. face* GetFaceByID(int nID)  
  58. {  
  59.     std::map<int,face>::iterator itr = m_mFace.find(nID);  
  60.     if (itr != m_mFace.end() )  
  61.     {  
  62.         return &(m_mFace[nID]);  
  63.     }  
  64.     return NULL;  
  65. }  
  66. class BspTree  
  67. {  
  68. public:  
  69.     BspTree():m_pRoot(NULL){};  
  70.     ~BspTree()  
  71.     {  
  72.         if (m_pRoot)  
  73.         {  
  74.             DeleteNode(m_pRoot);  
  75.         }  
  76.     }  
  77.     //初始化树根  
  78.     void InitTreeRoot(TreeNode *pNode);  
  79.     //释放整个树的资源  
  80.     void DeleteNode(TreeNode * pNode);  
  81.     //生成AABB包围盒  
  82.     void BuildAABB(TreeNode * pNode);  
  83.     //切分整个空间  
  84.     void SplitSpace(TreeNode* pRoot,int nAxis,int ndepth);  
  85.     //切分面  
  86.     void SplitFace( int nFaceId, float fSplit, int nAxis, int* pLeftNum, int* pRightNum, int* pBothNum );  
  87.     //遍历整个树  
  88.     void ErgodicTree(TreeNode * pNode);  
  89. protected:  
  90. private:  
  91.     TreeNode *m_pRoot;  
  92. };  
  93. void BspTree::InitTreeRoot(TreeNode *pNode)  
  94. {  
  95.     if (pNode == NULL)  
  96.         return;  
  97.     m_pRoot = pNode;  
  98. }  
  99. void BspTree::DeleteNode(TreeNode * pNode)  
  100. {  
  101.     if (pNode == NULL)  
  102.         return;  
  103.     DeleteNode(pNode->pLChild);  
  104.     DeleteNode(pNode->pRChild);  
  105.     delete pNode;  
  106. }  
  107. //遍历整个树  
  108. void BspTree::ErgodicTree(TreeNode * pNode)  
  109. {  
  110.     if (pNode == NULL)  
  111.         return;  
  112.   
  113.     ErgodicTree(pNode->pLChild);  
  114.     cout<<"节点深度: "<<pNode->nDepth<<"含有多少个面: "<<pNode->vFaceId.size();  
  115.     switch (pNode->Axis)  
  116.     {  
  117.     case Axis_X:  
  118.         {  
  119.             cout<<" 沿 X轴 分割 "<<"分割点是: x ="<<pNode->Split<<endl;  
  120.             break;  
  121.         }  
  122.     case Axis_Y:  
  123.         {  
  124.             cout<<" 沿 Y轴 分割 "<<"分割点是: y ="<<pNode->Split<<endl;  
  125.             break;  
  126.         }  
  127.     case Axis_Z:  
  128.         {  
  129.             cout<<" 沿 Z轴 分割 "<<"分割点是: z ="<<pNode->Split<<endl;  
  130.             break;  
  131.         }  
  132.     }  
  133.     ErgodicTree(pNode->pRChild);  
  134.       
  135. }  
  136. void BspTree::BuildAABB(TreeNode * pNode)  
  137. {  
  138.     if(!pNode)  
  139.         return;  
  140.     point Min(1000000,1000000,1000000);  
  141.     point Max(-1000000,-1000000,-1000000);  
  142.     for(int n = 0; n < pNode->vFaceId.size(); ++n)  
  143.     {  
  144.         face *pFa = GetFaceByID(n);  
  145.         if (pFa == NULL)  
  146.             continue;  
  147.         for(int m = 0; m < 3; ++m)  
  148.         {  
  149.             if (pFa->P[m].x > Max.x)  
  150.                  Max.x = pFa->P[m].x;  
  151.             if (pFa->P[m].y > Max.y)  
  152.                 Max.y = pFa->P[m].y;  
  153.             if (pFa->P[m].z > Max.z)  
  154.                 Max.z = pFa->P[m].z;  
  155.   
  156.             if (pFa->P[m].x < Min.x)  
  157.                 Min.x = pFa->P[m].x;  
  158.             if (pFa->P[m].y < Min.y)  
  159.                 Min.y = pFa->P[m].y;  
  160.             if (pFa->P[m].z < Min.z)  
  161.                 Min.z = pFa->P[m].z;  
  162.         }  
  163.     }  
  164.     pNode->box.Max = Max;  
  165.     pNode->box.Min = Min;  
  166. }  
  167.   
  168. int CompareFloat(float a,float b,float fOff)  
  169. {  
  170.     if (abs(a - b) < fOff)  
  171.         return 0;  
  172.     if ( a > b)  
  173.         return 1;  
  174.     else  
  175.         return -1;  
  176.           
  177. }  
  178. void BspTree::SplitFace( int nFaceId, float fSplit, int nAxis, int* pLeftNum, int* pRightNum, int* pBothNum )  
  179. {  
  180.     face* pFace = GetFaceByID(nFaceId);  
  181.   
  182.     int nLeftCount = 0;  
  183.     int nRightCount = 0;  
  184.     int nBothCount = 0;  
  185.     float t[3];  
  186.     switch( nAxis )  
  187.     {  
  188.     case Axis_X:  
  189.         t[0] = pFace->P[0].x;  
  190.         t[1] = pFace->P[1].x;  
  191.         t[2] = pFace->P[2].x;  
  192.         break;  
  193.     case Axis_Y:  
  194.         t[0] = pFace->P[0].y;  
  195.         t[1] = pFace->P[1].y;  
  196.         t[2] = pFace->P[2].y;  
  197.         break;  
  198.     case Axis_Z:  
  199.         t[0] = pFace->P[0].z;  
  200.         t[1] = pFace->P[1].z;  
  201.         t[2] = pFace->P[2].z;  
  202.         break;  
  203.     }  
  204.     forint i = 0; i < 3; i++ )  
  205.     {  
  206.         int c = CompareFloat( t[i], fSplit ,0.001f);  
  207.   
  208.         if( c < 0 )          // 左边  
  209.             nLeftCount++;  
  210.         else if( c > 0 ) // 右边  
  211.             nRightCount++;  
  212.         else                // 正中间  
  213.             nBothCount++;  
  214.     }  
  215.     *pLeftNum = nLeftCount;  
  216.     *pRightNum = nRightCount;  
  217.     *pBothNum = nBothCount;  
  218.   
  219. }  
  220.   
  221. void BspTree::SplitSpace(TreeNode* pRoot,int nAxis,int ndepth)  
  222. {  
  223.     if(!pRoot)  
  224.         return;  
  225.     pRoot->nDepth = ndepth;  
  226.     pRoot->Axis = nAxis;  
  227.     if (pRoot->vFaceId.size() < 3 || ndepth > 2)  
  228.     {  
  229.         pRoot->pLChild = NULL;  
  230.         pRoot->pRChild = NULL;  
  231.         return;  
  232.     }  
  233.     pRoot->pLChild = new TreeNode;  
  234.     pRoot->pRChild = new TreeNode;  
  235.   
  236.     pRoot->pLChild->box.Max = pRoot->box.Max;  
  237.     pRoot->pLChild->box.Min = pRoot->box.Min;  
  238.   
  239.     pRoot->pRChild->box.Max = pRoot->box.Max;  
  240.     pRoot->pRChild->box.Min = pRoot->box.Min;  
  241.   
  242.   
  243.     nAxis = (int)Axis_X;  
  244.     float XLength = pRoot->box.Max.x - pRoot->box.Min.x;  
  245.     float YLength = pRoot->box.Max.y - pRoot->box.Min.y;  
  246.     float ZLength = pRoot->box.Max.z - pRoot->box.Min.z;  
  247.     if (YLength > XLength)  
  248.     {  
  249.         nAxis = Axis_Y;  
  250.         XLength = YLength;  
  251.     }  
  252.     if (ZLength > XLength)  
  253.     {  
  254.         nAxis = Axis_Z;  
  255.     }  
  256.     float fslit = 0.0f;  
  257.     switch (nAxis)  
  258.     {  
  259.     case Axis_X:  
  260.         {  
  261.             fslit = (pRoot->box.Max.x + pRoot->box.Min.x)/2.0;  
  262.             pRoot->pLChild->box.Max.x = fslit;  
  263.             pRoot->pRChild->box.Min.x = fslit;  
  264.   
  265.         }break;  
  266.     case Axis_Y:  
  267.         {  
  268.             fslit = (pRoot->box.Max.y + pRoot->box.Min.y)/2.0;  
  269.             pRoot->pLChild->box.Max.y = fslit;  
  270.             pRoot->pRChild->box.Min.y = fslit;  
  271.         }break;  
  272.     case Axis_Z:  
  273.         {  
  274.             fslit = (pRoot->box.Max.z + pRoot->box.Min.z)/2.0;  
  275.             pRoot->pLChild->box.Max.z = fslit;  
  276.             pRoot->pRChild->box.Min.z = fslit;  
  277.         }break;  
  278.     }  
  279.     pRoot->Split = fslit;  
  280.   
  281.     int nSize = pRoot->vFaceId.size();  
  282.   
  283.     int nLeftCount,nRightCount,nBothCount;  
  284.     for (int n = 0; n < nSize; ++n)  
  285.     {  
  286.         SplitFace(pRoot->vFaceId.at(n),fslit,nAxis,&nLeftCount,&nRightCount,&nBothCount);  
  287.   
  288.         // 如果左边有  
  289.         if( nLeftCount > 0 || nBothCount > 0 )  
  290.             pRoot->pLChild->vFaceId.push_back( pRoot->vFaceId.at(n) );  
  291.         if( nRightCount > 0 || nBothCount > 0 )  
  292.             pRoot->pRChild->vFaceId.push_back( pRoot->vFaceId.at(n) );  
  293.     }  
  294.   
  295.     pRoot->vFaceId.clear();  
  296.   
  297.     // 递归  
  298.     SplitSpace( pRoot->pLChild, nAxis , ndepth+1);  
  299.     SplitSpace( pRoot->pRChild, nAxis , ndepth+1);  
  300. }  
  301. int _tmain(int argc, _TCHAR* argv[])  
  302. {  
  303.     BspTree bspTree;  
  304.     TreeNode *pRoot = new TreeNode;  
  305.     face fa;  
  306.     fa.P[0].x = -10;fa.P[0].y = -10;fa.P[0].z = -10;  
  307.     fa.P[1].x = 2;fa.P[1].y = 2;fa.P[1].z = 2;  
  308.     fa.P[2].x = 5;fa.P[2].y = 5;fa.P[2].z = 5;  
  309.     for (int n = 0; n < 16; ++n)  
  310.     {  
  311.         if (n % 5 == 0)  
  312.             fa += 2*(-n);  
  313.         else  
  314.             fa += 2*n;  
  315.         m_mFace[n] = fa;  
  316.         pRoot->vFaceId.push_back(n);  
  317.     }  
  318.     bspTree.InitTreeRoot(pRoot);  
  319.     bspTree.BuildAABB(pRoot);  
  320.     bspTree.SplitSpace(pRoot,0,0);  
  321.     bspTree.ErgodicTree(pRoot);  
  322.   
  323.     getchar();  
  324.     return 0;  
  325. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值