我根据Wald和Havran的论文On building fast kd-Trees for Ray Tracing, and on doing that in O(N log N)实现了一个SAH kd-tree。注意我最后没有完成拼接和合并建议,以加快树的构建,只是SAH部分。
我正在使用轴对齐的立方体测试算法,其中每个面被分成两个三角形,所以我总共有N = 12
个三角形。左下角的顶点(即最靠近轴的顶点)实际上位于原点。
Face Triangle
----------------
Front: 0, 1
Left: 6, 7
Right: 2, 3
Top: 4, 5
Bottom: 10, 11
Back: 8, 9
假设节点遍历成本Ct = 1.0
和交叉点成本Ci = 10.0
。我们首先发现不分裂的成本是Cns = N * Ci = 12 * 10.0 = 120.0
。
现在我们依次遍历每个轴并对候选分割平面进行增量扫描,以查看分割成本是否更便宜。第一个分割平面是p = <x,0>
。我们有Nl = 0
,Np = 2
和Nr = 10
(即左侧,平面和平面右侧的三角形数)。平面中的两个三角形是数字6和7(左面)。所有其他人都在右边。
现在执行SAH(p,V,Nl,Nr,Np)
功能。这将分割平面,体素V
分割,以及左/右/平面三角形的数量。它计算击中左(平)体素的概率为Pl = SA(Vl)/SA(V) = 50/150 = 1/3
,右概率为Pr = SA(Vr)/SA(V) = 150/150 = 1
。现在它运行两次成本函数;首先使用左侧的平面三角形,然后使用右侧的平面三角形分别获得Cl
和Cr
。
费用函数C(Pl,Pr,Nl,Nr)
返回bias * (Ct + Ci(Pl * Nl + Pr * Nr))
Cl
:左侧是平面三角形的成本(Nl = 2
,Nr = 10
) bias = 1
我们没有偏见,因为左右体素都不是空的
Cl = 1 * (1 + 10(1/3 * 2 + 1 * 10)) = 107.666
Cr
:右侧有平面三角形(Nl = 0
,Nr = 12
) bias = 0.8
空单元格偏见发挥作用
Cr = 0.8 * (1 + 10(1/3 * 0 + 1 * 12)) = 96.8
该算法确定Cr = 96.8
优于将两个三角形分割成平坦的单元格Cl = 107.666
,并且优于不在全部Cns = 120.0
分割体素。没有其他候选人分裂被发现更便宜。因此,我们分成一个空的左子,一个包含所有三角形的右子。当我们递归到正确的孩子继续树木建造时,我们执行与上面完全相同的步骤。这只是因为最大深度终止标准,这不会导致堆栈溢出。结果树非常深。
该论文声称已经考虑过这种事情:
剪裁期间,必须特别注意正确处理 特殊情况,如“扁平”(即零体积)细胞,或其中的情况 可能发生数值不准确(例如,对于非常薄的细胞) 与三角形的大小相比)。例如,我们必须确保 不要“夹住”位于扁平单元格中的三角形。请注意这样 案件不是罕见的例外,但实际上是由SAH鼓励的, 因为它们通常会产生最低的预期成本。
这种局部近似很容易陷入局部最小值:As 当地贪婪的SAH高估了CV(p),它可能会停止细分 即使正确的成本表明进一步细分。在 特别是,局部近似可能导致提前终止 对于需要在侧面分开扁平细胞的体素:很多 场景(特别是建筑场景)包含几何 轴对齐盒子的形式(灯具,桌腿或桌面, 。 。 。 ),在这种情况下,双方必须“剃掉”,直到 空的内部暴露。对于错误选择的参数,或何时 使用与我们使用的成本函数不同的成本函数(特别是 在叶估计中加入常数成本的那些, 递归可以提前终止。虽然这是一个成熟的退出 也可以以硬编码的方式避免 - 例如,只执行 非扁平电池的自动终止测试 - 我们建议遵循我们的 公式,在这种情况下不会发生过早退出。
我做错了吗?我怎么能纠正这个?