我有一个项目,它拍摄地形图并将其作为3D对象。 当我绘制对象的3D矩形时,它的工作速度非常慢。我读过关于BSP树的内容,但我并不是很了解它。有人可以解释如何在3D中使用BSP(也许举个例子)?以及如何在我的情况下使用它,当地图中的某些山峰覆盖其他部分时,我需要组织矩形以便很好地绘制它们?
答案 0 :(得分:6)
在n-D中,BSP树是一种空间分区数据结构,它使用分裂n-D超平面(甚至是n-D超曲面)递归地将空间分割成单元格。
在2D中,整个空间用2D线递归分割(成(可能是无限的)凸多边形)。
在3D中,整个空间以3D平面递归分割(进入(可能是无限的)凸多边形)。
如何在3D中构建BSP树(来自模型)
模型由基元列表组成(三角形或四边形,我相信你所谓的矩形)。
从BSP树中的初始根节点开始,该节点表示覆盖整个3D空间的单元格,并且最初保存模型的所有基元。
计算所考虑基元的最佳分裂平面。
此步骤的目标是找到一个平面,将基元拆分为两组大小相同的基元(相同的空间范围或相同的基元数)。
一个简单的分裂策略可能是选择随机方向(这将是你的平面的法线)进行分裂。然后沿着这个轴在空间上对所有基元进行排序。并遍历排序的基元列表以找到将基元分成两组大致相等的位置(即,这只是沿着该轴找到基元的中间位置)。通过此方向和此位置,可以定义分割平面。
然而,一种常用的拆分策略是:
计算所有考虑过的原语的centroid。
计算所有考虑过的原语的covariance matrix。
质心给出了分裂平面的位置。
协方差矩阵的最大特征值的特征向量给出了分裂平面的法线,这是基元传播最多的方向(当前单元应该被分割的位置)。
拆分当前节点,创建两个子节点并为每个节点或当前节点分配基元。
在1中找到合适的分裂平面后,现在可以将3D空间划分为两个半空间:一个正面,由平面法线指向,一个负面(在分割平面的另一侧) 。这一步的目标是通过将基元分配到它们所属的半空间来减少一半所考虑的基元。
根据分割平面测试当前节点的每个基元,并将其分配给左子节点或右子节点,具体取决于它是在正半空间还是在负半空间中。
一些基元可能与分裂平面相交。它们可以被平面剪切成较小的基元(并且也可能是三角形的),使得这些较小的基元完全位于半空间之一内,并且仅属于与子节点对应的一个单元。另一种选择是简单地将重叠的基元附加到当前节点。
将此拆分策略递归应用于创建的子节点(及其各自的子节点),直到满足一些停止拆分的标准(通常在当前节点中没有足够的基元)。
如何在3D中使用BSP树
在所有用例中,BSP树的层次结构用于丢弃查询模型的不相关部分。
找到一个点
使用您的查询点遍历BSP树。在每个节点,根据查询点所在的位置向左或向右移动w.r.t.到节点的分裂平面。
计算光线/模型交叉点
要查找与光线相交的模型的所有三角形(您可能需要这样做以选择地图),请执行类似于1的操作。使用查询光线遍历BSP树。在每个节点处,计算光线与分裂平面的交点。还要检查存储在节点(如果有)的基元,并报告与光线相交的基元。继续遍历此单元格与其光线相交的节点的子节点。
丢弃不可见数据
另一种可能的用途是丢弃模型中位于相机视锥外的部分(这可能是您对此感兴趣的部分)。视锥体完全由六个平面限定,并具有6个四边形面。与1.和2.中一样,您可以遍历BSP树,递归检查哪个单元格与视锥体重叠,并完全丢弃不存在的单元格(以及模型的相应部分)。对于平面/视锥台相交测试,您可以检查视锥体的6个四边形中的任何一个是否与平面相交,或者您可以使用边界体积保守地近似视锥体(球体/轴对齐边界框/定向边界框) )或者甚至两者兼而有之。
话虽如此,您的慢速渲染问题的解决方案可能在其他地方(您可能无法使用3D BSP树为您的模型丢弃大量数据):
62K正方形不是那么大:如果你正在使用OpenGL,你应该不单独绘制这些正方形或连续地将几何体流式传输到GPU。您可以将所有顶点放在一个静态顶点缓冲区中,并通过准备一个静态索引缓冲区来绘制四边形,该缓冲区包含带有三角形或(更好)三角形条形图的正方形的索引列表,以在单个绘制调用中绘制相应的正方形
您的数据高度结构化(具有高程的常规网格)。如果您碰巧有多个更大的数据集(甚至不再适合内存),那么您不仅需要空间分区(利用数据的2.5D结构及其规律性) ,像quadtree),但也许是LOD技术(用更便宜的代表替换你的数据,而不是简单地丢弃数据)。然后,您应该研究地形渲染的LOD技术。 This page列出了一些资源(论文+实施)。简化的Chunked LOD可以作为起点。