空间数据结构可以应用于的另一个几何问题是确定变化视点场景中物体的可见性顺序。

如果我们正在制作由平面多边形组成的固定场景的许多图像,从不同的角度(通常是游戏等应用程序的情况),我们可以使用与前一节讨论的光线相交方法密切相关的二进制空间划分方案。不同之处在于,对于可见性排序,我们使用非轴对齐的分割平面,因此可以使平面与多边形一致。这导致了一种优雅的算法,称为BSP树算法,从前到后对表面进行排序。BSP树的关键方面是它使用预处理来创建一个对任何视点都有用的数据结构。因此,当视点改变时,使用相同的数据结构而不改变。

12.4.1 Overview of BSP Tree Algorithm

BSP树算法是画家算法的一个例子。画师的算法从后往前绘制每个对象,每个新的多边形可能会遮挡之前的多边形,如图12.35所示。它可以实现如下:

截屏2023-03-14 上午10.52.08.png

sort objects back to front relative to viewpoint
for each object do
	draw object on screen

第一步(排序)的问题是,多个对象的相对顺序并不总是定义得很好,即使每一对对象的顺序都是。这个问题如图12.36所示,其中三个三角形形成一个循环。BSP树算法适用于任何由多边形组成的场景,其中没有任何多边形穿过任何其他多边形定义的平面。然后通过预处理步骤放宽这个限制。在接下来的讨论中,假定三角形是唯一的原始元素,但是这个概念可以扩展到任意多边形。

BSP树的基本思想可以用两个三角形T1和T2来说明。我们首先回顾(见第2.7.3节)包含T1的平面的隐式平面方程:f1(p)=0。我们希望利用隐式平面的关键性质是,对于平面一侧的所有点p+, f1(p+) >0;对于平面另一侧的所有点p -, f1(p -)<0。利用这个性质,我们可以求出T2在平面的哪一边。同样,这假设T2的三个顶点都在平面的同一侧。为了便于讨论,假设T2在平面的f1(p)<0边。然后,我们可以对任意眼点e,以正确的顺序画出T1和T2:

if (f1(e) < 0) then
	draw T1
	draw T2
else
	draw T2
	draw T1

截屏2023-03-14 下午1.43.04.png

这样做的原因是,如果T2和e在含有Ti的平面的同一侧,从e上看,T2没有办法被Ti完全或部分阻挡,所以先画Ti是安全的。如果e和T2在含Ti平面的相对两侧,则T2不能完全或部分阻挡T1,相反的绘制顺序是安全的(图12.37)。

这个观察结果可以推广到许多对象,只要没有一个对象跨越T1定义的平面。如果我们使用一个以Ti为根的二叉树数据结构,树的负分支包含所有顶点具有fi(p) <0,树的正分支包含所有顶点为fi(p) >0. 我们可以按照正确的顺序画如下:

截屏2023-03-14 下午1.45.41.png

这段代码的好处是,它将适用于任何视点e,因此可以预先计算树。请注意,如果每个子树本身就是一棵树,根三角形相对于包含它的平面将其他三角形分为两组,代码将按原样工作。通过将递归调用终止在更高的级别上,可以稍微提高效率,但代码仍然很简单。图12.38显示了说明这段代码的树。如2.7.5节所述,在包含三个非共线点a, b, c的平面上,点p的隐式方程为:

截屏2023-03-14 下午1.56.35.png

通过存储(A,B,C,D)可以加快隐函数的计算:

$$ f(x,y,z)=Ax+By+Cz+D=0 $$

向量n=(A,B,C)是平面的法线,也就是:

截屏2023-03-14 下午2.01.10.png

我们通过平面内任意一点a来求D的值: