【发布时间】:2020-07-28 01:29:30
【问题描述】:
在我的 CPU 光线追踪器(嗯,路径追踪器)中,大部分 CPU 时间花费在 BVH 遍历函数中。根据我的分析器,75% 的光线追踪时间花在这个函数和它调用的函数上,而 35% 的时间花在函数本身上。另外 40% 在它调用的不同交叉点测试中。
基本上,代码对所有与之相交的边界框和三角形进行 DFS 遍历。它使用堆栈上的静态分配数组来保存要探索的节点(BVHSTACKSIZE 设置为 32,它从不需要大部分空间),因此不会动态分配内存。然而,对我来说,35% 的时间都花在这里似乎很疯狂。我花了一段时间优化代码,目前它是我能做到的最快速度,但它仍然是我程序中最大的单一瓶颈。
有没有人有更多优化这个的提示?我已经有了一个不错的 BVH 构造算法,所以我认为使用不同的 BVH 不会得到任何加速。有没有人有关于如何在 Mac 上最好地进行逐行分析的提示?
作为参考,示例场景中的此代码所需时间从
谢谢!
bool BVHAccel::intersect(Ray& ray) const {
bool hit = false;
BVHNode* to_intersect[BVHSTACKSIZE];
int head = 0;
to_intersect[head++] = root;
while (head != 0) {
assert(head < BVHSTACKSIZE);
BVHNode* cur = to_intersect[--head];
if (cur->bb.intersect(ray)) { // Does not modify the ray
if (cur->isLeaf()) {
for (const auto& primitive : cur->primitives) {
hit |= primitive->intersect(ray); // Modifies the ray!
}
} else {
to_intersect[head++] = cur->r;
to_intersect[head++] = cur->l;
}
}
}
return hit;
}
bool BBox::intersect(const Ray& r) const {
double txmin = (min.x - r.o.x) * r.inv_d.x;
double txmax = (max.x - r.o.x) * r.inv_d.x;
double tymin = (min.y - r.o.y) * r.inv_d.y;
double tymax = (max.y - r.o.y) * r.inv_d.y;
double tzmin = (min.z - r.o.z) * r.inv_d.z;
double tzmax = (max.z - r.o.z) * r.inv_d.z;
ascending(txmin, txmax);
ascending(tymin, tymax);
ascending(tzmin, tzmax);
double t0 = std::max(txmin, std::max(tymin, tzmin));
double t1 = std::min(txmax, std::min(tymax, tzmax));
if (t1 < t0 || t0 > r.max_t || t1 < r.min_t) {
return false;
}
return true;
}
void ascending(double& a, double& b) {
if (a > b) {
std::swap(a, b);
}
}
【问题讨论】:
-
你能发布一段完整的运行代码吗?我可以收集你的代码做了什么(或多或少),但是修改一些我们可以复制粘贴并运行的东西要容易得多。
-
我会稍微扩展一下这个例子,但是很遗憾我不能发布一个独立的例子,因为我没有写很多周围的代码并且不能发布它。
-
但是将 BVH 视为一种深度优先遍历的二叉搜索树。这棵树大约有 10 深,遍历的每个树节点都需要一个 BBox 交集,而叶节点需要一个专门的交集(例如三角形、球体)。绝大多数 (~70%) 时间花在 DFS 遍历和 BBox 交叉点上,其中 DFS 遍历花费的时间最多。
-
我会关注这个问题,明天再考虑一下。感谢您对 intersect 方法的澄清!
-
没问题,感谢您的帮助!
标签: c++ c performance optimization depth-first-search