Bsp 空间分割模拟实现

Bsp:二叉分割树,在游戏中用来分割局部空间,方便碰撞检测等的实现。

下面介绍一种简单易用的分割方法:

分割步骤:

一、将空间中的所有的面,加入的根部节点。

二、遍历根部节点的所有面,分别找到x、y、z的最大最小值,给根节点指定一个合适的包围空间。

三、在这个节点的包围空间里找到最长轴、并按这个最长轴的中间点做为新的分割点,遍历该节点的所有面将其分在其左右子节点中。

四、返回第2步,直到达到一定限制条件,结束,此时空间已经被分开了。

当然闲话不说,贴上实现模拟代码:

// StBSPTree.cpp : Defines the entry point for the console application. // #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; 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; } 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; }


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
unity中的BSP(Binary Space Partitioning)是一种在游戏开发中常见的空间分割技术。其核心思想是将游戏场景或大型模型划分成一系列的二叉空间分割面,从而方便场景的渲染、碰撞检测、光照计算等。 BSP的基本原理是通过建立一棵二叉树来表示3D空间分割结构。在建树过程中,将空间按照分隔面进行分割,并为每个分割面设置相应的隐式函数。这些分割面可以是平面、球体或其他形状,用于将空间划分为两个子空间,通常分为正面和背面。这样,树的叶子节点将是游戏中的实际几何物体。 使用BSP的优点之一是可以快速进行一些特殊效果的渲染,例如阴影计算和可视化剔除。通过判断相机是否位于BSP的一个子空间中,可以剔除掉不需要渲染的物体,提高渲染性能。另外,BSP也可以用于进行碰撞检测,例如判断一个物体是否与某个子空间相交。 然而,BSP也存在一些限制和挑战。当场景非常复杂时,BSP的构建和维护可能会变得非常耗时,并且需要大量的存储空间。此外,由于BSP是静态的,对于动态场景的更新和改变支持不够灵活。因此,对于大型地图或需要动态变化的场景,可能需要使用其他的空间分割技术。 综上所述,BSP是一种在unity游戏开发中常见的二叉空间分割技术。它通过建立二叉树来表示3D空间分割结构,提高了渲染、碰撞检测和光照计算等方面的效率。然而,BSP也有其局限性,适用性受到场景复杂性和动态性的限制。通过合理的选择和应用,BSP可以为游戏开发带来很大的好处。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值