如何在二叉树中搜索(可能是多个)节点,其中所有节点的先前父节点都符合条件?

How to search for (possibly multiple) nodes in a binary tree where all node's previous parents match criteria?

我正在用 Golang 编写路径跟踪器,最近我添加了对三角形和 OBJ 文件的支持。我正在使用 Möller–Trumbore 交叉算法来测试交叉点,但是当模型有很多三角形时,渲染会变慢。解决方案是使用 BVH,它们是二叉树。在阅读 BVH 之后,我发现使用 AABB(轴对齐边界框),因为它们易于构建且易于测试交叉点。例如,让我们为具有 10 个三角形的模型构建一个两级 BVH。我没有测试射线与这些三角形中的每一个的相交,而是测试与顶部边界框的相交。如果它不相交,我知道它不会与模型中的任何三角形相交,但如果相交,我想测试较低级别的相交。如果光线与左侧边界框相交,我知道我的三角形在这个框中,现在我可以遍历其中的三角形。

假设我有一个包含 50 个三角形的模型,并且我构建了这样一个 BVH:

                            50 tris  <--- the ray intersects with this bounding box
                            |
                            |
                           / \
                          /   \
                         /     \
                        /       \
                       /         \
                 25 tris         25 tris   <--- the ray intersects with both bounding boxes
                   |                 |
                   |                 |
                  / \               / \
                 /   \             /   \
                /     \           /     \
           12 tris  13 tris   12 tris  13 tris  <--- leaves
           ^                               ^
           |                               |
the ray intersects with this bb       and this bb

现在有一个问题:光线与两片叶子相交。我尝试像这样递归测试 BVH 交叉点:

// here's my BVH struct:

type BVH struct {
    left, right *BVH
    leaves      []Triangle
    bounds      AABB
    last        bool
}

func testBVH(tree *BVH, level int, r Ray, tMin, tMax float64) []Triangle {
    temp := []Triangle{}
    if tree == nil {
        return nil
    }
    if tree.last {
        return tree.leaves
    } else if level > 1 {
        if tree.left.bounds.hit(r, tMin, tMax) {
            temp = testBVH(tree.left, level-1, r, tMin, tMax)
        }
        if tree.right.bounds.hit(r, tMin, tMax) {
            tr := testBVH(tree.right, level-1, r, tMin, tMax)
            for i := 0; i < len(tr); i++ {
                temp = append(temp, tr[i])
            }
        }
    }
    return temp
}

,但它仍然不起作用,它不会 return 命中边界框内的所有三角形。这是 BVH 级别 3 的猴头渲染图:

没有任何 BVH 的同一型号:

很难通过射线找到与两个或多个边界框相交的三角形。我查了一下,BVH生成没问题,所以问题出在二叉树搜索上。检查与 BVH 相交的正确方法是什么?

好的,问题出在树的结构本身。我将叶子更改为具有两个元素并将 testBVH 函数更改为如下所示:

func testBVH(tree *BVH, level int, r Ray, tMin, tMax float64) [][2]Leaf {
    temp := [][2]Leaf{}
    if tree == nil {
        return nil
    }
    if tree.last {
        if tree.bounds.hit(r, tMin, tMax) {
            return append(temp, tree.leaves)
        }
        return temp
    } else if level > 0 {
        if tree.left.bounds.hit(r, tMin, tMax) {
            temp = testBVH(tree.left, level-1, r, tMin, tMax)
        }
        if tree.right.bounds.hit(r, tMin, tMax) {
            tr := testBVH(tree.right, level-1, r, tMin, tMax)
            temp = append(temp, tr...)
        }
    }
    return temp
}

然后我遍历树叶以找到三角形交点。我不知道这是否是最佳方式,但它显着加快了渲染过程,所以我认为它已经足够了。