Games101作业6(BVH的构建和遍历)

文章目录

    • BVH的构建
    • BVH的遍历

BVH的构建

Games101作业6(BVH的构建和遍历)_第1张图片
在场景中只有一个物体时,直接对该物体进行划分

对应代码

 node->bounds = objects[0]->getBounds();
        node->object = objects[0];
        node->left = nullptr;
        node->right = nullptr;
        node->area = objects[0]->getArea();
        return node;

Games101作业6(BVH的构建和遍历)_第2张图片
在场景中有两个物体时,将两个物体包围起来,再分别进行划分,对于代码
Games101作业6(BVH的构建和遍历)_第3张图片

		node->left = recursiveBuild(std::vector{objects[0]});
        node->right = recursiveBuild(std::vector{objects[1]});

        node->bounds = Union(node->left->bounds, node->right->bounds);
        node->area = node->left->area + node->right->area;
        return node;

当场景中有多个物体时,先找到xyz哪一项加起来的值最大,以最大的坐标进行排序,进行划分,以下图为例,如果X的和最大,即对X进行划分
Games101作业6(BVH的构建和遍历)_第4张图片
Games101作业6(BVH的构建和遍历)_第5张图片
对应代码

    else {
        Bounds3 centroidBounds;
        for (int i = 0; i < objects.size(); ++i)
            centroidBounds =
                Union(centroidBounds, objects[i]->getBounds().Centroid());
        // 判断xyz哪个坐标最大
        int dim = centroidBounds.maxExtent();
        switch (dim) {
        case 0:
            std::sort(objects.begin(), objects.end(), [](auto f1, auto f2) {
                return f1->getBounds().Centroid().x <
                       f2->getBounds().Centroid().x;
            });
            break;
        case 1:
            std::sort(objects.begin(), objects.end(), [](auto f1, auto f2) {
                return f1->getBounds().Centroid().y <
                       f2->getBounds().Centroid().y;
            });
            break;
        case 2:
            std::sort(objects.begin(), objects.end(), [](auto f1, auto f2) {
                return f1->getBounds().Centroid().z <
                       f2->getBounds().Centroid().z;
            });
            break;
        }

        auto beginning = objects.begin();
        auto middling = objects.begin() + (objects.size() / 2);
        auto ending = objects.end();

        auto leftshapes = std::vector<Object*>(beginning, middling);
        auto rightshapes = std::vector<Object*>(middling, ending);

        assert(objects.size() == (leftshapes.size() + rightshapes.size()));

        node->left = recursiveBuild(leftshapes);
        node->right = recursiveBuild(rightshapes);

        node->bounds = Union(node->left->bounds, node->right->bounds);
        node->area = node->left->area + node->right->area;

代码冗余部分
在recursiveBuild中,有如下代码,bounds对象创建而未使用

Bounds3 bounds;
    for (int i = 0; i < objects.size(); ++i)
        bounds = Union(bounds, objects[i]->getBounds());

bounds对象的目的,找到该区域的包围盒,但可以通过方式找到包围盒,这种遍历方式较为耗时建议删除。
Games101作业6(BVH的构建和遍历)_第6张图片

BVH的遍历

对BVH的结构的理解,在BVH的非叶子节点中,都有多个物体,所以走到只有叶子节点的时候才会真正的与物体求交,因此我们需要从根节点遍历到叶子节点,才进行与物体的求交

代码如下


Intersection BVHAccel::getIntersection(BVHBuildNode* node, const Ray& ray) const
{
    // TODO Traverse the BVH to find intersection
    if (node == nullptr)
    {
        return Intersection();
    }

    std::array<int, 3> dirIsNeg;
    dirIsNeg[0] = (ray.direction[0] > 0);
    dirIsNeg[1] = (ray.direction[1] > 0);
    dirIsNeg[2] = (ray.direction[2] > 0);

    if ((node->bounds.IntersectP(ray, ray.direction_inv, dirIsNeg)) == false)
    {
        return Intersection();
    }

    // 在叶子结点
    if (node->left == nullptr && node->right == nullptr)
    {
        return node->object->getIntersection(ray);
    }

    Intersection left = getIntersection(node->left, ray);
    Intersection right = getIntersection(node->right, ray);

    if (left.distance < right.distance)
    {
        return left;
    }

    return right;

}

IntersectP是与包围盒如何求交,和课上内容一致,不做展开

你可能感兴趣的:(计算机图形学,c++)