我正在为x86消费者硬件编写CPU光线跟踪器(在C ++ 11中,到目前为止使用gcc 4.7.1)。
我正在使用一个持有三角形的kD树,并且用我给定的光线将叶子中的所有三角形相交。此任务根据我的探查器占用大部分运行时间(取决于kd-tree以及大约50%或更多运行时的输入和选择参数)。
for (auto p : leaf.triangles) {
p->intersect(ray, t, intersection); //void intersect(const Ray& ray, float t, Intersection& output)
}
(p是指向矢量中其他位置的三角形的类型指针。)
我的kd树可能会更深,但这迫使我有更多的叶子共享同一个三角形。因为我经常被迫测试相邻的叶子,所以我最终将一遍又一遍地交叉相同的三角形。到目前为止,这可能是我最大的瓶颈。
一个简单的解决方案似乎是某种列表,可以保留我已经交叉的所有指针。我决定使用unordered_set<Triangle*>
因为find
和emplace
的平均费用不变。
unordered_set<Triangle*> alreadyTested; //used for all leafs a ray visits
for (auto p : leaf.triangles) {
if (alreadyTested.find(p) == alreadyTested.end()) {
p->intersect(ray, t, intersection);
alreadyTested.emplace(p);
}
}
使用GCC -O3编译
我的运行时整体增加了4到8倍。我的探查器告诉我,find
和emplace
大约需要一个intersect
取消任何速度加值。错过的跳跃预测可能是大幅放缓的原因。
我该怎么做(“它”每个三角形只调用一次相交)?
答案 0 :(得分:1)
您可以继续对光线进行计数,并将与三角形相交的最后一条光线的索引直接存储在三角形中。如果你是多线程的,你可以通过线程索引拥有多个这样的值和索引。
由于重新散列, emplace
可能会花费很多时间。您可以使用从最后一帧收集的统计信息(对于相同的光线,或者只是所有光线的上限),为unordered_set
构造函数指定更好的初始桶数。