- 下面介绍一种简单易用的分割方法:分割步骤:一、将空间中的所有的面,加入的根部节点。二、遍历根部节点的所有面,分别找到x、y、z的最大最小值,给根节点指定一个合适的包围空间。三、在这个节点的包围空间里找到最长轴、并按这个最长轴的中间点做为新的分割点,遍历该节点的所有面将其分在其左右子节点中。四、返回第2步,直到达到一定限制条件,结束,此时空间已经被分开了。当然闲话不说,贴上实现模拟代码:
- #include<map>
- #include<vector>
- #include<iostream>
- usingnamespacestd;
- structpoint
- {
- floatx,y,z;
- point():x(0.0f),y(0.0f),z(0.0f){};
- point(floata,floatb,floatc):x(a),y(b),z(c){}
- voidoperator+=(intn)
- {
- x+=n;
- y+=n;
- z+=n;
- }
- voidoperator=(point&p)
- {
- memcpy(this,(void*)&p,sizeof(*this));
- }
- };
- structface
- {
- pointP[3];
- voidoperator+=(intn)
- {
- P[0]+=n;
- P[1]+=n;
- P[2]+=n;
- }
- };
- structBBox
- {
- pointMin;
- pointMax;
- BBox():Min(),Max(){}
- };
- enumEAxis
- {
- Axis_X,
- Axis_Y,
- Axis_Z,
- };
- structTreeNode
- {
- TreeNode():box(),nDepth(0),pLChild(NULL),pRChild(NULL),Axis(Axis_X),Split(0.0f){vFaceId.reserve(16);}
- intnDepth;
- TreeNode*pLChild;
- TreeNode*pRChild;
- std::vector<int>vFaceId;
- intAxis;
- BBoxbox;
- floatSplit;
- };
- std::map<int,face>m_mFace;
- face*GetFaceByID(intnID)
- {
- std::map<int,face>::iteratoritr=m_mFace.find(nID);
- if(itr!=m_mFace.end())
- {
- return&(m_mFace[nID]);
- }
- returnNULL;
- }
- classBspTree
- {
- public:
- BspTree():m_pRoot(NULL){};
- ~BspTree()
- {
- if(m_pRoot)
- {
- DeleteNode(m_pRoot);
- }
- }
- //初始化树根
- voidInitTreeRoot(TreeNode*pNode);
- //释放整个树的资源
- voidDeleteNode(TreeNode*pNode);
- //生成AABB包围盒
- voidBuildAABB(TreeNode*pNode);
- //切分整个空间
- voidSplitSpace(TreeNode*pRoot,intnAxis,intndepth);
- //切分面
- voidSplitFace(intnFaceId,floatfSplit,intnAxis,int*pLeftNum,int*pRightNum,int*pBothNum);
- //遍历整个树
- voidErgodicTree(TreeNode*pNode);
- protected:
- private:
- TreeNode*m_pRoot;
- };
- voidBspTree::InitTreeRoot(TreeNode*pNode)
- {
- if(pNode==NULL)
- return;
- m_pRoot=pNode;
- }
- voidBspTree::DeleteNode(TreeNode*pNode)
- {
- if(pNode==NULL)
- return;
- DeleteNode(pNode->pLChild);
- DeleteNode(pNode->pRChild);
- deletepNode;
- }
- //遍历整个树
- voidBspTree::ErgodicTree(TreeNode*pNode)
- {
- if(pNode==NULL)
- return;
- ErgodicTree(pNode->pLChild);
- cout<<"节点深度:"<<pNode->nDepth<<"含有多少个面:"<<pNode->vFaceId.size();
- switch(pNode->Axis)
- {
- caseAxis_X:
- {
- cout<<"沿X轴分割"<<"分割点是:x="<<pNode->Split<<endl;
- break;
- }
- caseAxis_Y:
- {
- cout<<"沿Y轴分割"<<"分割点是:y="<<pNode->Split<<endl;
- break;
- }
- caseAxis_Z:
- {
- cout<<"沿Z轴分割"<<"分割点是:z="<<pNode->Split<<endl;
- break;
- }
- }
- ErgodicTree(pNode->pRChild);
- }
- voidBspTree::BuildAABB(TreeNode*pNode)
- {
- if(!pNode)
- return;
- pointMin(1000000,1000000,1000000);
- pointMax(-1000000,-1000000,-1000000);
- for(intn=0;n<pNode->vFaceId.size();++n)
- {
- face*pFa=GetFaceByID(n);
- if(pFa==NULL)
- continue;
- for(intm=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;
- }
- intCompareFloat(floata,floatb,floatfOff)
- {
- if(abs(a-b)<fOff)
- return0;
- if(a>b)
- return1;
- else
- return-1;
- }
- voidBspTree::SplitFace(intnFaceId,floatfSplit,intnAxis,int*pLeftNum,int*pRightNum,int*pBothNum)
- {
- face*pFace=GetFaceByID(nFaceId);
- intnLeftCount=0;
- intnRightCount=0;
- intnBothCount=0;
- floatt[3];
- switch(nAxis)
- {
- caseAxis_X:
- t[0]=pFace->P[0].x;
- t[1]=pFace->P[1].x;
- t[2]=pFace->P[2].x;
- break;
- caseAxis_Y:
- t[0]=pFace->P[0].y;
- t[1]=pFace->P[1].y;
- t[2]=pFace->P[2].y;
- break;
- caseAxis_Z:
- t[0]=pFace->P[0].z;
- t[1]=pFace->P[1].z;
- t[2]=pFace->P[2].z;
- break;
- }
- for(inti=0;i<3;i++)
- {
- intc=CompareFloat(t[i],fSplit,0.001f);
- if(c<0)//左边
- nLeftCount++;
- elseif(c>0)//右边
- nRightCount++;
- else//正中间
- nBothCount++;
- }
- *pLeftNum=nLeftCount;
- *pRightNum=nRightCount;
- *pBothNum=nBothCount;
- }
- voidBspTree::SplitSpace(TreeNode*pRoot,intnAxis,intndepth)
- {
- 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=newTreeNode;
- pRoot->pRChild=newTreeNode;
- 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;
- floatXLength=pRoot->box.Max.x-pRoot->box.Min.x;
- floatYLength=pRoot->box.Max.y-pRoot->box.Min.y;
- floatZLength=pRoot->box.Max.z-pRoot->box.Min.z;
- if(YLength>XLength)
- {
- nAxis=Axis_Y;
- XLength=YLength;
- }
- if(ZLength>XLength)
- {
- nAxis=Axis_Z;
- }
- floatfslit=0.0f;
- switch(nAxis)
- {
- caseAxis_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;
- caseAxis_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;
- caseAxis_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;
- intnSize=pRoot->vFaceId.size();
- intnLeftCount,nRightCount,nBothCount;
- for(intn=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(intargc,_TCHAR*argv[])
- {
- BspTreebspTree;
- TreeNode*pRoot=newTreeNode;
- facefa;
- 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(intn=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();
- return0;
- }