BVH的构建
在场景中只有一个物体时,直接对该物体进行划分
对应代码
node->bounds = objects[0]->getBounds();
node->object = objects[0];
node->left = nullptr;
node->right = nullptr;
node->area = objects[0]->getArea();
return node;
在场景中有两个物体时,将两个物体包围起来,再分别进行划分,对于代码
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进行划分
对应代码
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对象的目的,找到该区域的包围盒,但可以通过方式找到包围盒,这种遍历方式较为耗时建议删除。
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是与包围盒如何求交,和课上内容一致,不做展开