[Graphics] Simplified BSP tree

Source: Internet
Author: User


Brief introduction

BSP tree is a kind of spatial partition tree, which is mainly used for scene management in games, especially for indoor scene management.

Its essence is a two-fork tree, that is, to divide the space into two parts with one face, the split space continues to be separated by polygons, and so on, until the specific recursion depth is reached, or there is no longer an object in space or only one object (convex/convex multipatch) is left.

Finally, the leaf nodes correspond to the objects in the scene, and the internal nodes store the segmented faces. Objects are "stored" in each bounding box.


Application


There are two main applications of BSP tree:

(1) Determine the occlusion relationship of the object, and visualize the process.

(2) The broad stage of collision detection.


First, make it clear that the BSP tree is the tree that is automatically generated when the map is designed, which is then saved to disk, which is pre-preprocessed. When loading the scene, we read directly into the BSP file instead of rebuilding it.

This also means that, as a preprocessing technique, the BSP tree can only handle static scenes.


The structure of the BSP tree itself is very simple, but it does not mean that the programming of the BSP tree is very easy. Its complexity is mainly reflected in:

(1) The BSP tree does not exist independently, and it needs to be combined with the previous map editor and later scene culling/collision detection. And both of these are very complex projects.

(2) Select the appropriate partition surface, make the tree as balanced as possible, and can stop the segmentation at the right time.


In the case of scene culling, the emphasis is on judging the relationship between the object, and this spatial topological relationship has been clearly embodied in the BSP tree. We start from the root node, according to the location of the camera and the split plane to compare, it is easy to determine the node of the two sub-space and the point of view of the relationship. We think with the viewpoint on the same side as the front, on the different sides for the back.

For collision detection, the collision detection of all objects 22 is very time-consuming, we can first preliminary investigation of the object, if not in the same leaf node (bounding box), then there will be no collision, through a simple traversal of the tree to avoid tedious calculations.


Specific implementation


The programming of the BSP tree is more complex, and the BSP tree is most simplified here. The following code is used only as a practice to better master the BSP tree.

If you want to learn the BSP tree available for the commercial engine, refer to the Quake3 map editor.

The main reference is a BSP structure given in the book "Real-Time rendering", as follows:

Simplified section:

(1) Use two-dimensional, not three-dimensional.

(2) Manually enter the bounding box instead of automatically generated. The bounding box is a aabb bounding box (axial), not supported in concave polygons.

(3) A data structure is shared between the leaf node and the internal node. The inner node stores the direction (horizontal or vertical) and the split line, and the leaf node stores whether the corresponding scene is solid or hollow.

(4) The boundary of the bounding box is segmented (as shown in the figure), and the method of selecting the split line is relatively simple:

1. Select the optimal dividing line in horizontal and vertical direction respectively. (Judging criteria: the closest bounding box boundary line to the Space Center)

2. If the optimal horizontal split line intersects with the object in the scene, and the optimal vertical split line and the object in the scene do not intersect, then the optimal vertical split line is preferred and vice versa.

If all intersect or do not intersect, then preference is closer to the center point (calculated in relative proportion)

If the selected split line intersects the bounding box, the bounding box is split into two bounding boxes according to the split line.

(5) Exit conditions (to achieve one):

1. Reach the maximum number of split layers, directly generate two leaf nodes, return.

2. There is no object in the space, return to the empty leaf node.

3. There is only one object left in the space, returning to the full-leaf node.


The details are already reflected in the code comments.


node Data structure


Sample Example


Blue Line: First Division; Purple Line: Second Division; Yellow Line: Third Division

Bounding box:

(4,10,4,16)

(10,24,4,9)

(7,19,23,27)

(22,28,13,24)


BSP Tree



Code

Bsp.h

#pragma once#include<vector>class bsptree{private:struct bspnode {bspnode* left;bspnode* right;bool isLeaf;// Whether the leaf node bool issolid;//whether the solid bool ishori;//is horizontal float data;//Split line};//node data structure struct box_t {float xmin;float xmax;float ymin; float ymax;box_t (); void set (float x1, float x2, float y1, float y2);};/ /bounding box data structure bspnode* root;//root node std::vector<box_t>box;//bounding box container float xmin, xmax, ymin, ymax;//the entire scene of the axial bounding box int boxnum;// The number of bounding boxes int layer;//the maximum depth int layer_count;//records the current number of layers bspnode* createemptynode ();//Generate Empty leaf nodes bspnode* createsolidnode ();// Generate non-empty leaf node void split (float& data_x, float& data_y, float& dis_x, float& dis_y,float xmin, float xmax, float y Min, float ymax);//Find the optimal split line bspnode* Gennode (bool isfull_1, bool isfull_2, int layer_count,float xmin, float xmax, float Ymi N, float ymax, float data,bool ishori);//Generate New node bspnode* build (int layer_count, float xmin, float xmax,float ymin, float ym AX);//Create new node bool Isintersect (float xmin, float xmax, float ymin, float ymax, float data, bool ISHORI,STD::vector<int>& id,int& num);//Whether a split line in a space intersects void traversal (bspnode* t) with a bounding box in space;//Pre-order traverse bool InBox ( Float x1, float x2, float y1, float y2, int id);//bounding box ID is completely in a space void Checkisfull (bool& isfull_x_1, bool& Isfull_ X_2, bool& isfull_y_1, bool& isfull_y_2,float xmin, float xmax, float ymin, float ymax, float data_x, float data_y );//detects if the two regions are divided by the full/empty bool Isintersect (float x1, float x2, float y1, float y2, int id), or whether the bounding box ID is intersected with a space public:bsptree ( Float x1, float x2, float y1, float y2, int l);//construction//First four parameters for scene bounding box, L for maximum recursive depth void add (float x1, float x2, float y1, float y2); Add bounding box void build ();//create BSP tree void print ();//pre-sequence traversal output void Levelorder ();//level traversal output};


Bsp.cpp

#include "bsp.h" #include <algorithm> #include <queue>bsptree::box_t::box_t () {}void Bsptree::box_t::set ( Float x1, float x2, float y1, float y2) {xmin = X1;xmax = X2;ymin = Y1;ymax = y2;}  Bsptree::bsptree (float x1, float x2, float y1, float y2, int l) {xmin = X1;xmax = X2;ymin = Y1;ymax = Y2;layer = L;boxnum = 0;layer_count = 0;root = nullptr;} void Bsptree::add (float x1, float x2, float y1, float y2) {box_t b;boxnum++;b.set (x1, x2, y1, y2); Box.push_back (b);} Whether the dividing line in a space intersects with a bounding box in space bool Bsptree::isintersect (float xmin,float xmax,float ymin,float ymax,float data, bool Ishori  , std::vector<int>& id,int& num) {BOOL flag = false;//Record whether the presence of a cross//split line is horizontal if (Ishori) {//Traverse all bounding boxes for (int i = 0; i < Boxnum;  i++) {//If the bounding box is completely in space if (InBox (xmin, Xmax, ymin, ymax, i)) {num++;//record bounding box number +1if (Data > Box[i].xmin && Data <  Box[i].xmax) {//presence of id.push_back (i);//record bounding box Idflag = true;//existence intersection True}}}}//Split line is vertical else if (!ishori) {//Traverse all bounding box for (int i = 0; i < Boxnum; i++) {//If the bounding box is completely in spaceif (InBox (xmin, Xmax, ymin, ymax, i)) {num++;//record bounding box number +1if (Data > Box[i].ymin&&data < Box[i].ymax) {//Existence of cross ID . push_back (i);//record bounding box Idflag = true;//present in true}}}}return flag;} Whether the bounding box ID is completely in a space bool Bsptree::inbox (float x1, float x2, float y1, float y2,int id) {return box[id].xmin >= x1 &&am P box[id].xmax<=x2 &&box[id].ymin>=y1 && box[id].ymax <= y2;} Find the best split line void Bsptree::split (float& data_x, float& data_y, float& dis_x, float& dis_y,float xmin, float x Max, float ymin, float ymax) {float d = 10000;//First calculates the vertical direction//traverse all bounding boxes for (int i = 0; i < Boxnum; i++) {//If the bounding box is completely in space if (Inbo X (Xmin,xmax,ymin,ymax,i)) {//Calculate bounding box boundary line to center distance d = box[i].xmin-((xmax-xmin)/2 + xmin); if (d < 0) d =-d;//If there is a smaller distance, update the distance Off and split lines if (D < dis_x) {dis_x = d;data_x = Box[i].xmin;} Calculate bounding box boundary lines to center distance d = Box[i].xmax-((xmax-xmin)/2 + xmin); if (d < 0) d =-d;//If there is a smaller distance, update distance and split line if (D < dis_x) {di s_x = d;data_x = Box[i].xmax;}}} Calculate horizontal direction//traverse all bounding box for (int i =0; i < Boxnum;  i++) {//If the bounding box is completely in space if (InBox (xmin, Xmax, ymin, ymax, i)) {//Calculate bounding box boundary line to center distance d = box[i].ymin-((ymax-ymin)/2 + ymin); (d < 0) d =-d;//If there is a smaller distance, update the distance and split line if (D < dis_y) {dis_y = D;data_y = Box[i].ymin;} Calculate bounding box boundary lines to center distance d = Box[i].ymax-((ymax-ymin)/2 + ymin); if (d < 0) d =-d;//If there is a smaller distance, update distance and split line if (D < dis_y) {dis _y = d;d ata_y = Box[i].ymax;}}} Calculates the relative distance dis_x/= xmax-xmin;dis_y/= ymax-ymin;} Create an empty leaf node bsptree::bspnode* bsptree::createemptynode () {bspnode* node = new Bspnode (); node->left = nullptr;node-> right = Nullptr;node->isleaf = True;node->issolid = False;node->data = 0.0f;return node;} Create a non-empty leaf node bsptree::bspnode* bsptree::createsolidnode () {bspnode* node = new Bspnode (); node->left = nullptr;node-> right = Nullptr;node->isleaf = True;node->issolid = True;node->data = 0.0f;return node;} Generate node bsptree::bspnode* bsptree::gennode (bool isfull_1,bool isfull_2,int layer_count,float xmin,float xmax,float ymin , Float ymax,float Data, bool Ishori) {bspnode* node = new Bspnode ();//apply if (!root) {//Specify root = node;} If you do not reach the maximum depth if (layer! = Layer_count) {//If zone 1 is full if (isfull_1) {///recursively creates if (Ishori) Node->left = Build (Layer_count + 1, Xmin, xmax,ymin,data); Else Node->left = Build (Layer_count + 1, xmin, data, ymin, ymax);} If zone 1 is empty else {//create empty leaf nodes directly, do not continue recursion Node->left = Createemptynode ();} If zone 2 is full if (isfull_2) {///recursively creates if (Ishori) Node->right = Build (Layer_count + 1, xmin, Xmax,data,ymax); else node-> right = Build (Layer_count + 1, data, xmax, ymin, ymax);} If zone 2 is empty else {//create empty leaf nodes directly, do not continue recursion node->right = Createemptynode ();}} If the maximum depth is reached else if (layer ==layer_count) {///If the area 1 is full if (isfull_1) {//Creates a full leaf node directly, does not continue recursively node->left = Createsolidnode ();} If zone 1 is empty else {//create empty leaf nodes directly, do not continue recursion Node->left = Createemptynode ();} If the area 2 is full if (isfull_2) {//Creates a full leaf node directly, does not continue recursively node->right = Createsolidnode ();} If zone 2 is empty else {//create empty leaf nodes directly, do not continue recursion node->right = Createemptynode ();}} Set node basic information node->isleaf = False;node->ishori = Ishori;node->datA = Data;return node;} Whether the bounding box ID has an intersection with a space bool Bsptree::isintersect (float x1, float x2, float y1, float y2, int id) {//Two cases://1. Horizontal, vertical direction each has at least one boundary line falling Within the area (excluding exactly falling on the area boundary)//2. Horizontal direction two boundary lines all fall on the regional boundary, or the vertical direction two boundary lines all fall on the regional boundary return ((Box[id].xmin > x1 && box[id].xmin<x2 | | Box[id].xmax>x1 && box[id].xmax<x2| | Box[id].xmin = = x1 && box[id].xmax==x2) && (Box[id].ymin>y1&&box[id].ymin<y2 | | Box[id].ymax>y1&&box[id].ymax < y2) | | BOX[ID].YMIN==Y1&AMP;&AMP;BOX[ID].YMAX==Y2);} Detects if the divided two regions are full/empty void Bsptree::checkisfull (bool& isfull_x_1, bool& isfull_x_2, bool& isfull_y_1, BOOL & Isfull_y_2,float xmin, float xmax, float ymin, float ymax,float data_x,float data_y) {//Traverse all bounding boxes, if there is a bounding box with the space there is an intersection, Then this space is full for (int i = 0; i < Boxnum; i++) {if (!isfull_x_1 && isintersect (xmin, data_x, ymin, ymax,i)) {Isfull _x_1 = true;} if (!isfull_x_2 && isintersect (data_x, Xmax, ymin, ymax, i)) {isfull_x_2 = true;} if (!isfull_y_1 && IsINtersect (xmin, Xmax, ymin, data_y, i)) {isfull_y_1 = true;} if (!isfull_y_2 && isintersect (xmin, Xmax, data_y, ymax, i)) {isfull_y_2 = true;}} return;} Create BSP Tree bsptree::bspnode* bsptree::build (int layer_count, float xmin, float xmax,float ymin, float ymax) {//printf ("%f%f %f%f\n ", Xmin, Xmax, ymin, ymax);//Return to Nullif with recursion depth (Layer_count = = layer + 1) return nullptr;bspnode* node = nullptr;//Initial Some variables: distance, split line, whether intersect, subspace empty/full state, intersect bounding box ID, number of bounding box in space float dis_x = 10000;float dis_y = 10000;float data_x = -1;float data_y = -1;b Ool isintersect_x;bool Isintersect_y;bool isfull_x_1 = False;bool Isfull_x_2 = False;bool isFull_y_1 = False;bool isFull_y _2 = False;std::vector<int>id_x;std::vector<int>id_y;int num_x = 0;int num_y = 0;split (data_x, data_y, dis_x , Dis_y, Xmin, Xmax, ymin, ymax);//Find the optimal split Line//Both unassigned, indicating there is no choice of bounding box, that is, the space is empty, directly return to the empty leaf node if (data_x = =-1 && data_y = =- 1) {return Createemptynode ();} Determine if the optimal split line intersects the bounding box isintersect_x = Isintersect (xmin,xmax,ymin,ymax,data_x, True,id_x,num_x); isintersect_y = Isintersect (xmin,xmax,ymin,ymax,data_y, false,id_y,num_y);//Determine split subspace is empty/full Checkisfull (IsFull_  X_1, Isfull_x_2, Isfull_y_1, Isfull_y_2, xmin, Xmax, ymin, Ymax, data_x, data_y);//There is only one object in the space, directly returning to the full-leaf node if (num_x = = 1) return Createsolidnode ();//Vertical split lines intersect, horizontal split lines do not intersect, select horizontal Divider if (isintersect_x &&!isintersect_y) {node = Gennode (Isfull_y_1, Isfull_y_2, Layer_count, xmin, Xmax, ymin, ymax, data_y,true);} Vertical split lines do not intersect, horizontal split lines intersect, select vertical divider else if (!isintersect_x && isintersect_y) {node = Gennode (Isfull_x_1, Isfull_x_2, Layer_count, Xmin, Xmax, ymin, ymax, data_x,false);} All intersect or do not intersect, select the nearest else {//vertical closer to the center (Dis_x < dis_y) {//If there is a intersect, the split bounding box if (isintersect_x) {for (int i = 0; i < id_x.size ( ); i++) {Float X1 = box[id_x[i]].xmin;float x2 = box[id_x[i]].xmax;float y1 = box[id_x[i]].ymin;float y2 = Box[id_x[i]].ymax; Boxnum++;box[id_x[i]].set (x1, data_x, y1, y2); box_t b;b.set (data_x, x2, y1, y2); Box.push_back (b);} Id_x.clear ();} node = Gennode (Isfull_x_1, Isfull_x_2, Layer_count, Xmin, Xmax, ymin, ymax, data_x,false);}  Level more near else {//If present intersect, split bounding box if (isintersect_y) {for (int i = 0; i < id_y.size (); i++) {Float X1 = box[id_y[i]].xmin;float x2 = box[id_y[i]].xmax;float Y1 = box[id_y[i]].ymin;float y2 = box[id_y[i]].ymax;boxnum++;box[id_y[i]].set (x1, x2, y1, da ta_y); box_t b;b.set (x1, x2, data_y, y2); Box.push_back (b);} Id_y.clear ();} node = Gennode (Isfull_y_1, Isfull_y_2, Layer_count, xmin, Xmax, ymin, ymax, data_y,true);}} return node;} Create entry void Bsptree::build () {build (1, xmin, Xmax, ymin, ymax);} Pre-order output void Bsptree::p rint () {traversal (root);} The pre-order void Bsptree::traversal (Bspnode* t) {if (!t) return;if (T->data! = 0) printf ("%f", T->data), Else printf ("leaf:% D ", T->issolid), if (T->ishori) printf (" h\n "), Else printf (" v\n "); traversal (t->left); traversal (t->right) ;} sequence void Bsptree::levelorder () {Std::queue<bspnode*>q;q.push (root); while (!q.empty ()) {bspnode* t = Q.front (); if (t->data!=0) printf ("%f", T->data), Else printf ("leaf:%d", t->issolid); if (T-> ishori) printf ("h\n"), Else printf ("v\n"); Q.pop (); if (t->left! = nullptr) Q.push (t->left); if (t->right! = nullptr) Q.push (t->right);} return;}

Main.cpp

#include "Bsp.h" #include <stdlib.h>int main () {bsptree* t = new Bsptree (1,33,1,33,3); T->add (4, 4, +);t-> Add (Ten, 4, 9), T->add (7, N, Max), T->add (+, +), T->build (), T->print ();p rintf ("\ nthe");t-> Levelorder (); System ("Pause");}



[Graphics] Simplified BSP tree

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.