Binary Space Partitioning is a fundamental spatial data structure used to recursively divide a 3D (or 2D) space into convex sets using hyperplanes. It was popularized by games like DOOM and Quake for rendering and collision detection.
At its core, a BSP tree is a binary tree where each node represents a “partitioning plane.”
The process is recursive:
struct Node {
Plane partition;
Node *front, *back;
std::vector<Polygon> polygons;
};
Node* BuildBSPTree(std::vector<Polygon> polygons) {
if (polygons.empty()) return nullptr;
Plane plane = PickBestPlane(polygons);
Node* node = new Node(plane);
std::vector<Polygon> frontList, backList;
for (auto& poly : polygons) {
Side side = Classify(plane, poly);
if (side == Side::FRONT) frontList.push_back(poly);
else if (side == Side::BACK) backList.push_back(poly);
else {
auto [f, b] = SplitPolygon(plane, poly);
frontList.push_back(f);
backList.push_back(b);
}
}
node->front = BuildBSPTree(frontList);
node->back = BuildBSPTree(backList);
return node;
}
BSP trees allow you to render polygons in a perfect back-to-front order without a Z-buffer (Painter’s Algorithm). This is how older engines achieved depth sorting.
To check if a point is in “solid” space:
This is extremely fast because it reduces a complex 3D check into a series of simple dot products ( dot(Point, PlaneNormal) - PlaneDistance ).