定義上、N次元超平面は空間を2つの部分に二分するため、BSPツリーは任意のN次元空間に抽象化できます。言い換えると、N次元空間の特定の点については、超平面上にあるか、超平面がN次元空間に作成する二等分された空間の1つにある必要があります。
2Dの場合、BSPツリーは、線を描画し、その線のどちら側にポイントがあるかをテストすることによって作成されます。これは、線が2D空間を二等分するためです。3Dの場合、平面が必要になります。平面は通常、テストとして使用しているポリゴンサーフェスの法線から形成されます。
したがって、アルゴリズムは次のようになります。
- 立方体のすべてのポリゴンを含むキューを作成します。ある順序ではなく、ランダムにポリゴンをキューに追加するのが最善です。
- キューの先頭からポリゴンをポップします...これをBSPツリーの「ルート」にします。
- そのポリから法線を作成します
- キューから別のポリゴンをポップします
- そのポリゴン内のすべてのポイントが、ルートから作成された法線の前または後ろにあるかどうかをテストします。
- それらがすべて前面にある場合は、そのポリゴンをルートの右の子にします。それらがすべて遅れている場合は、そのポリをルートの左子にします。
- ポリゴン内のすべてのポイントが、ルートポリゴンの法線によって定義された平面の前または後ろにない場合は、平面の前と後ろの部分について、ポリゴンを2つの部分に分割する必要があります。この分割から作成された2つの新しいポリゴンについて、それらをキューの最後に追加し、手順4から繰り返します。
- キューから別のポリゴンをポップします。
- このポリをルートに対してテストします。ルートには子があるため、ポリゴンがルートの前にあるか後ろにあるかをテストしたら(分割が必要になる可能性があるステップ#7に注意してください)、右側にある子ノードに対してポリをテストします。 -前、または後ろにある場合は左側の子ノード。子ノードがない場合は、ツリー内の移動を停止し、その子としてツリーにポリゴンを追加できます。
- 現在のポリゴンが前または後ろにない子ノードに遭遇した場合は、手順7で分割を実行してから、手順4に戻る必要があります。
- キューが空になるまで、このプロセスを繰り返します。
このアルゴリズムのコードは、概念的には次のようになります。
struct bsp_node
{
std::vector<poly_t> polys;
bsp_node* rchild;
bsp_node* lchild;
bsp_node(const poly_t& input): rchild(NULL), lchild(NULL)
{
polys.push_back(input);
}
};
std::queue<poly_t> poly_queue;
//...add all the polygons in the scene randomly to the queue
bsp_node* bsp_root = new bsp_node(poly_queue.front());
poly_queue.pop();
while(!poly_queue.empty())
{
//grab a poly from the queue
poly_t current_poly = poly_queue.front();
poly_queue.pop();
//search the binary tree
bsp_node* current_node = bsp_root;
bsp_node* prev_node = NULL;
bool stop_search = false;
while(current_node != NULL && !stop_search)
{
//use a plane defined by the current_node to test current_poly
int result = test(current_poly, current_node);
switch(result)
{
case COINCIDENT:
stop_search = true;
current_node->polys.push_back(current_poly);
break;
case IN_FRONT:
prev_node = current_node;
current_node = current_node->rchild;
break;
case BEHIND:
prev_node = current_node;
current_node = current_node->lchild;
break;
//split the poly and add the newly created polygons back to the queue
case SPLIT:
stop_search = true;
split_current_poly(current_poly, poly_queue);
break;
}
}
//if we reached a NULL child, that means we can add the poly to the tree
if (!current_node)
{
if (prev_node->rchild == NULL)
prev_node->rchild = new bsp_node(current_poly);
else
prev_node->lchild = new bsp_node(current_poly);
}
}
ツリーの作成が完了したら、ツリーを順番に検索して、ポリゴンを後ろから前に並べ替えることができます。オブジェクトが透明であるかどうかは関係ありません。これは、マテリアルのプロパティではなく、ポリゴン自体に基づいて並べ替えているためです。