您的位置:首页 > 理论基础

[OpenGL]计算机图形学:二叉空间分割(BSP)树

2012-12-24 20:38 483 查看
今天来和大家研究一下BSP树的应用。

首先简单介绍一下BSP树的相关内容。

BSP (Binary Space Partition)表示二叉空间分割。

使用这种方法可以使我们在运行时使用一个预先计算好的树来得到多边形从后向前的列表,它的复杂度为O(n)。

它的基本思想是基于这样一个事实:任何平面都可以将空间分割成两个半空间。

所有位于这个平面的一侧的点定义了一个半空间,位于另一侧的点定义了另一个半空间:



此外,如果我们在任何半空间中有一个平面,它会进一步将此半空间分割为更小的两个子空间。

我们可以使用多边形列表将这一过程一直进行下去,将子空间分割得越来越小,直到构造成一个二叉树。

在这个树中,一个进行分割的多边形被存储在树的节点,所有位于子空间中的多边形都在相应的子树上。

当然,这一规则使用于树中每一个节点。

为了简单起见,我们选择一个这样一个平面投影,在它上面,所有多边形都能映射为直线段。

下面我们从二维平面来解析一下BSP树的应用。首先从多边形B(图中线段B)开始构造一个BSP树。



多边形B所在的平面将空间分割为两个部分,使得多边形D和E位于同一个半空间中,多边形C在另一个半空间中。



在这个例子中, 多边形A穿越了两个半空间,这样,它就不能十分明确的被分配到任何一个半空间中。

但是,如果我们将这个多边形从它与分割平面相交的地方分为两个部分一个命名为A1,

另一个命名为A2,这样,A1就和D、E在同一个半空间中,A2和C在同一个半空间中。

下图表述了这一过程。



我们现在已经将问题分成了两个子问题。我们可以在子树中再次使用上述算法。

例如,我们在左边子树中选择E作为分割多边形,在右边子树中选择A2作为分割多边形。

这样,我们将建立下面的结构树。



必须注意,任何给定的BSP树都不是唯一的。

我们可以对同样的多边形找到多个有效的二叉分割。依靠我们选择来进行分割的多边形的顺序,可以得到不同的树。

例如,在下图中,我们可以看到另一个树,它也建立在前面我们讨论的多边形上。



我们检查观察者的位置和位于树顶部的多边形之间的关系。

很明显,当这个多边形将空间分割为两个部分时,观察者必须位于其中的一个半空间中。

当然,位于同一半空间中的多边形要比另一半空间中的多边形离观察者更近。

基于这样的事实,如果我们首先将较远处半空间中的多边形放置在最终的列表中,

然后放置根多边形,再放置与观察者在同一半空间中的多边形,这样就很容易得到多边形从后向前的顺序了。

我们对每一个子树都重复同样的过程,在每一个级别中选择相应的顺序,最终,就会得到正确的多边型的顺序。

这一算法的一个优点就是无论观察者位于场景中的什么位置,

无论观察者的朝向如何,它都可以很好的进行工作。

例如,在上图中,倘若摄像机在D点和E点,那么他们的生成BSP树的顺序就是不一样的。

但是他们对于各自的情况都是正确的。

这样,如果我们预先为一个多边形模型计算一个BSP树,那么在运行时,

我们只需要根据观察者的位置调用这个树,执行树遍历过程,就可以产生用于隐面消除的画家算法所需的从后向前的多边形顺序。

  

在这个算法中,在树的每一个节点处所作的判定,都依赖于观察者位于该节点多边形所产生的哪一个半空间中。

利用我们所讨论过的事实,我们可以看到,如果将观察者位置的坐标代入给定多边形的平面方程式中,

结果数值的符号如果是正号,就表示观察者位于该多边形的法向量所指向的半空间中,

负号表示位于另一个半空间中, 0值表示他位于这个多边形所在的平面上。

最后一种情况,对于遍历整个BSP树的意图来说,意味着半空间在屏幕上的投影不相交,

并且我们可以在这一阶段的遍历过程中选择任何子树的顺序。

  

相同的计算也要在预先计算一个BSP树时使用到。我们需要决定不同的多边形应该被放置在哪个子树中。

从可实现性的观点出发,预先计算一个BSP树的过程可以被描述成下面的形式:对多边形集合,我们选择一个多边形。

进一步计算该多边形的平面方程式。对剩余的多边形,我们用所说的方程式检查它们的所有顶点。如果所有顶点都是负值,

那么多边形就放置在一个子树中;如果都是正值,那么多边形就放置在另一个子树中;

如果结果有正有负,那么多边形就被分为两部分,分别放置在两个子树中。

一旦我们将所有多边形分配到了正确的半空间中,我们就可以对子树进一步调用同样的方法来进行处理,

直到当前的子表只包含一个多边形为止。

  

一个多边形被任何平面所分割的问题可以当作一个裁剪问题来处理。

解决这一问题的算法只与我们在裁剪问题时所讨论的算法又很小的差别。

唯一明显的差别就是在二进制搜索边缘裁剪过程中,我们将使用分割多边形的平面方程式来找到边的中点的位置。

 

我们考查了树的创建和遍历之后,仍然有一些问题需要解决。

当我们构建一个树时,我们可以选择剩余多边形中的任何一个来分割空间。

选择不同的多边形会导致不同的树的结构。因此,我们就应该考虑选择哪个多边形有助于算法的效率。

  

有些多边形会导致剩余多边形更多的分割。

每一个多边形在通过渲染管道时都有一定的系统消耗,因此多边形越少,性能就越好。

我们可以利用判据来选择有较少分割的多边形。

  

使用判据来平衡BSP树,并不需要每一级中的子树中的多边形的数量都相同,

因为它不会影响运行时间。树的遍历总是假设至少每次都取一个多边形,因此平衡不会影响性能——我们仍然不得不每次取每一个多边形。

另一方面,一个平衡的树可以以较少的迭代调用来执行遍历。我们可以将平衡作为第二判据来使用。

  

总之,使用BSP树来进行从后向前排序的最大优点就是算法运行的复杂性较低 。

这种方法也解决了多边形的多重交叠和多边形穿越问题。但是,通过使用一个预计算结构,我们已经失去了一定的灵活性。

如果多边形的排列在运行时发生了改变, BSP树就必须发生相应的改变。由于计算量非常巨大,我们不能这样做。

因此,这种算法对于场景在运行时发生改变的情况就不能使用了。

  

应该注意,只有当多边形经历不同的变换设置时树才会受到影响。如果所有的多边形都使用同样的变换,

那么分割仍然是正确的,树也将不会受到影响。这样,场景中的一个动态物体,它在世界中移动或者是旋转,

仍然可以使用同样的BSP树。如果物体中的一部分相对于其他物体发生了移动,那我们就要使用其它的算法了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: