场景管理:BSP算法C++实现(https://download.csdn.net/download/wondeful18/3549437)

转载:https://blog.csdn.net/u012234115/article/details/47156463

简单的实现了下BSP树

代码结构:

 

face.hpp 被管理的模型面片类
bsp_tree.hpp BSP树类
main.cpp程序入口
 

face.hpp

#pragma once
/*
//被管理的对象类
*/

//点结构
template <typename T>
struct Point
{
    T x;
    T y;
    T z;
    Point(){} //要声明这个空构造函数,否则下面的类编译出错
    Point(T _x,T _y,T _z):x(_x),y(_y),z(_z){}
    Point(const Point<T> &point)
    {
        x=point.x;
        y=point.y;
        z=point.z;
    }
    Point &operator+=(const T &n)
    {
        x+=n;
        y+=n;
        z+=n;
        return *this;
    }
};

//面结构,带三个顶点
template <typename T>
struct Face
{
    Point<T> point[3];
    void operator+=(const T &offset)
    {
        for(int i=0;i<3;++i)
            point[i]+=offset;
    }
};

bsp_tree.hpp

#pragma once
/*
//BSP树
//按照AABB包围盒分隔,按照最长边切分轴,然后把场景面片递归地划分到两个子节点,一开始就划分完毕,主要是作为静态场景管理
*/
#include <vector>
#include "face.hpp"

enum Axis
{
    AXIS_X,
    AXIS_Y,
    AXIS_Z
};


template <typename T>
struct BspTreeNode
{
    std::vector<Face<T>> faces;
    Axis axis;
    int depth;
    T splitter; //某个方向的分隔值
    Point<T> minPoint; //节点的包围盒顶点
    Point<T> maxPoint;
    BspTreeNode *lChild;
    BspTreeNode *rChild;
    BspTreeNode():lChild(nullptr),rChild(nullptr){}
};


template <typename T>
class BspTree
{
public:
    BspTree();
    ~BspTree();
public:
    //构造树根以及整体AABB包围盒,由min和max两个点来设置
    void InitBspTree(std::vector<Face<T>> &_faces,Point<T> min_point,Point<T> max_point,int max_depth);
    void DeleteBspTree();
    void TraverseBspTree() const;
private:
    void cutFace(const Face<T> &face,Axis axis,const T &splitter,int &leftCount,int &rightCount,int &bothCount);
    void splitSpace(BspTreeNode<T> *node,Axis axis,int depth);
    void traverse(BspTreeNode<T> *node) const;
    void deleteTree(BspTreeNode<T> *root);
private:
    BspTreeNode<T> *root; //根节点
    int maxDepth; //最大递归深度,防止堆栈溢出

};

template <typename T>
BspTree<T>::BspTree()
{

}

template <typename T>
BspTree<T>::~BspTree()
{
}

template <typename T>
void BspTree<T>::InitBspTree(std::vector<Face<T>> &_faces,Point<T> min_point,Point<T> max_point,int max_depth)
{
    maxDepth=max_depth;
    root=new BspTreeNode<T>;
    root->depth=1;
    root->faces=_faces;
    root->lChild=nullptr;
    root->rChild=nullptr;

    root->maxPoint=max_point;
    root->minPoint=min_point;

    //初始化后就开始分割所有场景
    splitSpace(root,AXIS_X,1);
}

template <typename T>
void BspTree<T>::deleteTree(BspTreeNode<T> *root)
{
    if(root)
    {
        deleteTree(root->lChild);
        deleteTree(root->rChild);
        delete root;
        root=nullptr;
    }
}

template <typename T>
void BspTree<T>::DeleteBspTree()
{
    deleteTree(root);
}

template <typename T>
void BspTree<T>::cutFace(const Face<T> &face,Axis axis,const T &splitter,int &leftCount,int &rightCount,int &bothCount)
{
    T p[3]; //记录某个方向的点分量
    switch(axis)
    {
    case AXIS_X:
        p[0]=face.point[0].x;
        p[1]=face.point[1].x;
        p[2]=face.point[2].x;
        break;
    case AXIS_Y:
        p[0]=face.point[0].y;
        p[1]=face.point[1].y;
        p[2]=face.point[2].y;
        break;
    case AXIS_Z:
        p[0]=face.point[0].z;
        p[1]=face.point[1].z;
        p[2]=face.point[2].z;
        break;
    }
    //对分隔到两边的顶点计数
    for(int i=0;i<3;++i)
    {
        if(p[i]<splitter)
            leftCount++;
        else if(p[i]>splitter)
            rightCount++;
        else if(fabs(p[i]-splitter)<1e-6)
            bothCount++;
    }
}

template <typename T>
void BspTree<T>::splitSpace(BspTreeNode<T> *node,Axis axis,int depth)
{
    //在当前层节点做分割处理,为下层子节点数据做填充

    if(!node) 
        return;
    node->axis=axis;
    node->depth=depth;
    if(depth==maxDepth)
        return;
    if(node->faces.size()<2) //上层节点拥有的面片数太少就不再划分
        return;

    node->lChild=new BspTreeNode<T>;
    node->rChild=new BspTreeNode<T>;
    //先给子节点包围盒赋值
    node->lChild->maxPoint=node->maxPoint;
    node->lChild->minPoint=node->minPoint;
    node->rChild->maxPoint=node->maxPoint;
    node->rChild->minPoint=node->minPoint;

    T xLen=node->maxPoint.x-node->minPoint.x;
    T yLen=node->maxPoint.y-node->minPoint.y;
    T zLen=node->maxPoint.z-node->minPoint.z;
    //设置该节点的划分点
    Axis mAxis=AXIS_X;
    if(yLen>xLen&&yLen>zLen)
        mAxis=AXIS_Y;
    if(zLen>xLen&&zLen>yLen)
        mAxis=AXIS_Z;
    switch(mAxis)
    {
    case AXIS_X:
        node->splitter=(node->maxPoint.x+node->minPoint.x)/2; //取中间值
        //修改子节点的包围盒值
        node->lChild->maxPoint.x=node->splitter;
        node->rChild->minPoint.x=node->splitter;
        break;
    case AXIS_Y:
        node->splitter=(node->maxPoint.y+node->minPoint.y)/2;
        node->lChild->maxPoint.y=node->splitter;
        node->rChild->minPoint.y=node->splitter;
        break;
    case AXIS_Z:
        node->splitter=(node->maxPoint.z+node->minPoint.z)/2;
        node->lChild->maxPoint.z=node->splitter;
        node->rChild->minPoint.z=node->splitter;
        break;
    }

    
    for(int i=0;i<node->faces.size();++i)
    {
            // 重置计数
            int leftCount=0;
        int rightCount=0;
        int bothCount=0;

        //对每个面做切分到子节点
        cutFace(node->faces[i],mAxis,node->splitter,leftCount,rightCount,bothCount);
        if(leftCount||bothCount)
        node->lChild->faces.push_back(node->faces[i]);
        if(rightCount||bothCount)
        node->rChild->faces.push_back(node->faces[i]);
    }

    //关键的一步,分割完了之后,把当前层节点的面片清空
    node->faces.clear(); 

    //递归
    splitSpace(node->lChild,mAxis,depth+1);
    splitSpace(node->rChild,mAxis,depth+1);
    
}

template <typename T>
void BspTree<T>::traverse(BspTreeNode<T> *node) const
{
    if(!node)
        return;
    traverse(node->lChild);
    //中序遍历
    std::cout<<"节点深度 "<<node->depth<<" 面片数 "<<node->faces.size()<<std::endl;
    switch(node->axis)
    {
    case AXIS_X:
        std::cout<<"沿X轴分割 "<<"分割点x "<<node->splitter<<std::endl;
        break;
    case AXIS_Y:
        std::cout<<"沿Y轴分割 "<<"分割点y "<<node->splitter<<std::endl;
        break;
    case AXIS_Z:
        std::cout<<"沿Z轴分割 "<<"分割点z "<<node->splitter<<std::endl;
        break;
    }
    traverse(node->rChild);
}

template <typename T>
void BspTree<T>::TraverseBspTree() const
{
    //封装一层再遍历
    traverse(root);
}

main.cpp

#include <iostream>
#include <vector>
#include <time.h>
#include "bsp_tree.hpp"
using namespace std;

int main()
{
    BspTree<float> bspTree;

    //创造一些面片
    vector<Face<float>> face_vec;
    srand(time(0));
    for(int i=0;i<16;++i)
    {
        Face<float> face;
        for(int j=0;j<3;++j)
            face.point[j]=Point<float>(-200+rand()%400,-200+rand()%400,-200+rand()%400);
        face_vec.push_back(face);
    }    
    //初始化bsp树并遍历
    bspTree.InitBspTree(face_vec,Point<float>(-200,-200,-200),Point<float>(200,200,200),5);
    bspTree.TraverseBspTree();
    bspTree.DeleteBspTree();

    system("pause");
    return 0;
}
--------------------- 
作者:踏莎行hyx 
来源:CSDN 
原文:https://blog.csdn.net/u012234115/article/details/47156463 
版权声明:本文为博主原创文章,转载请附上博文链接!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值