着色器中包围体层次结构的遍历

2023-11-21

我正在使用 vulkan 计算着色器开发路径跟踪器。我实现了一棵树代表包围体层次结构。 BVH 的想法是最大限度地减少需要执行光线相交测试的对象数量。


#1 简单的实施

我的第一个实现非常快,它遍历树到singleBVH 树的叶子。然而,射线可能相交multiple树叶。然后,此代码会导致一些三角形未渲染(尽管它们应该渲染)。

int box_index = -1;

for (int i = 0; i < boxes_count; i++) {
    // the first box has no parent, boxes[0].parent is set to -1
    if (boxes[i].parent == box_index) {
        if (intersect_box(boxes[i], ray)) {
            box_index = i;
        }
    }
}

if (box_index > -1) {
    uint a = boxes[box_index].ids_offset;
    uint b = a + boxes[box_index].ids_count;

    for (uint j = a; j < b; j++) {
        uint triangle_id = triangle_references[j];
        // triangle intersection code ...
    }
}

#2 多叶实施

我的第二个实现考虑了多个叶子可能相交的事实。然而,这个实现是36x比实现 #1 慢


经过一番挖掘,我找到了解决方案。需要理解的重要一点是,BVH 树并不排除需要评估的可能性all leaves.

下面的实现 #3 使用命中和未命中链接。需要对这些框进行排序,以便在最坏的情况下以正确的顺序查询所有框(因此单个循环就足够了)。然而,链接用于跳过不需要评估的节点。当当前节点是叶子节点时,进行实际的三角形相交。

  • 命中链接~命中时跳转到哪个节点(下面绿色)
  • miss link ~ 错过时跳转到哪个节点(下图红色)

BVH tree evaluation order

图片取自here。相关论文和源代码也在 Toshiya Hachisuka 教授的文章中page。相同的概念也描述于幻灯片中引用的本文.


#3 带有命中和未命中链接的 BVH 树

我必须扩展通过链接推送到着色器的数据。此外,还需要进行一些离线操作才能正确存储树。起初我尝试使用 while 循环(循环直到box_index_next是-1),这再次导致了疯狂的减速。无论如何,以下方法运行得相当快:

int box_index_next = 0;

for (int box_index = 0; box_index < boxes_count; box_index++) {
    if (box_index != box_index_next) {
        continue;
    }

    bool hit = intersect_box(boxes[box_index], ray);
    bool leaf = boxes[box_index].ids_count > 0;

    if (hit) {
        box_index_next = boxes[box_index].links.x; // hit link
    } else {
        box_index_next = boxes[box_index].links.y; // miss link
    }

    if (hit && leaf) {
        uint a = boxes[box_index].ids_offset;
        uint b = a + boxes[box_index].ids_count;

        for (uint j = a; j < b; j++) {
            uint triangle_id = triangle_references[j];
            // triangle intersection code ...
        }
    }
}

这段代码比快速但有缺陷的实现 #1 慢大约 3 倍。这在某种程度上是预料之中的,现在速度取决于实际的树,而不是 GPU 优化。例如,考虑一种退化情况,其中三角形沿轴对齐:同一方向的射线可能与所有三角形相交,然后需要评估所有树叶。

Toshiya Hachisuka教授针对此类情况提出了进一步优化在他的幻灯片中(第 36 页及以后):存储 BVH 树的多个版本,沿 x、-x、y、-y、z 和 -z 进行空间排序。对于遍历,需要根据光线选择正确的版本。然后,一旦叶子中的三角形相交,就可以停止遍历,因为要访问的所有剩余节点在空间上都将位于该节点后面(从光线角度来看)。


一旦构建了 BVH 树,查找链接就非常简单(下面是一些 python 代码):

class NodeAABB(object):

    def __init__(self, obj_bounds, obj_ids):
        self.children = [None, None]
        self.obj_bounds = obj_bounds
        self.obj_ids = obj_ids

    def split(self):
        # split recursively and create children here
        raise NotImplementedError()

    def is_leaf(self):
        return set(self.children) == {None}

    def build_links(self, next_right_node=None):
        if not self.is_leaf():
            child1, child2 = self.children

            self.hit_node = child1
            self.miss_node = next_right_node

            child1.build_links(next_right_node=child2)
            child2.build_links(next_right_node=next_right_node)

        else:
            self.hit_node = next_right_node
            self.miss_node = self.hit_node

    def collect(self):
        # retrieve in depth first fashion for correct order
        yield self
        if not self.is_leaf():
            child1, child2 = self.children
            yield from child1.collect()
            yield from child2.collect()

将所有 AABB 存储在数组中(将发送到 GPU)后,您可以使用hit_node and miss_node查找链接的索引并存储它们。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

着色器中包围体层次结构的遍历 的相关文章

  • 使用 glDrawElements 时在 OpenGL 核心配置文件中选取三角形

    我正在使用 glDrawElements 绘制三角形网格 并且希望能够使用鼠标单击来拾取 选择三角形 三角形的网格可以很大 在固定功能 OpenGL 中 可以使用 GL SELECT http content gpwiki org inde
  • Three.js 对象的“中心”是什么?

    当我使用 Blender 对对象进行建模时 我能够明确定义其发生平移和旋转的中心位置 当使用 Three js 对象时 我似乎没有找到等效的对象 Three js 对象是否具有定义其 中心 位置的属性 如果不是 物体的中心是如何确定的 在
  • 如何在 C++ 项目的 Cmake 文件上添加 Mac OS 框架

    我正在尝试将外部库 Vulkan 添加到我的项目中 这个库是预编译的并且有一个框架 我的项目树 build source Entry main cpp include ext vulkan macos include lib Framewo
  • 如何使用网格分割图像并保留透明度边界框

    我有一些 png 图像 我想将其分成几个部分 例如按网格或大小 但每个部分应具有与原始图像相同的边界框 透明度 Example 将图像分成两部分 原来的 200 89 Output 部分 1 png 200 89 第2部分 png 200
  • 使用 GLSL 直接在着色器中从位置计算平移矩阵

    我正在开发 C OpengL 程序以及 GLSL 顶点和片段着色器 我正在创建同一对象的多个实例 我只需要改变实例之间的对象位置 这是我所做的 我正在使用一个统一变量 它是一个变换矩阵数组 每个矩阵代表一个对象实例 MVP 也是一个变换矩阵
  • android ndk 硬件调试内存

    背景 我对 C 很有经验 对 Android 和 Java 还很陌生 但这是编程的环境问题 我已经用 ANSI C 开发了一个管理应用程序 可以移植到任何操作系统 只需在依赖于操作系统的代码中添加 UI 即可 它使用相当多的内存 特别是对于
  • SSBO 是更大的 UBO?

    我目前正在 OpenGL 4 3 中使用 UBO 进行渲染 以将所有常量数据存储在 GPU 上 诸如材料描述 矩阵等内容 它可以工作 但是 UBO 的小尺寸 我的实现为 64kB 迫使我多次切换缓冲区 减慢渲染速度 我正在寻找类似的方法来存
  • 函数式语言中的部分求值和函数内联有什么区别?

    我知道 函数内联就是用函数定义代替函数调用 部分评估是在编译时评估程序的已知 静态 部分 在 C 等命令式语言中 两者之间存在区别 其中运算符与函数不同 但是 在像 Haskell 这样的函数式语言 其中运算符也是函数 中 两者之间有什么区
  • 当 foreach 块的内容具有 Conditional 属性时,C# 编译器是否会对其进行优化?

    我正在工作中编写一些调试代码 我想知道我所做的是否会损害性能 让我们看一下代码 foreach var item in aCollection Debug WriteLine item Name 我知道 Debug 类使用 Conditio
  • LTO、去虚拟化和虚拟表

    比较 C 中的虚拟函数和 C 中的虚拟表 一般来说 编译器 对于足够大的项目 在去虚拟化方面做得同样好吗 天真地说 C 中的虚拟函数似乎有更多的语义 因此可能更容易去虚拟化 Update Mooing Duck 提到了内联去虚拟化函数 快速
  • 子组调用索引是否映射到 gl_LocalInitationIndex?

    我需要计算吗gl SubgroupID gl SubgroupSize gl SubgroupInvocationID 或者我可以使用gl LocalInvocationIndex 单个子组内的调用是否连续gl SubgroupInvoca
  • 计算边界框重叠的百分比,用于图像检测器评估

    在测试大图像中的对象检测算法时 我们根据地面实况矩形给出的坐标检查检测到的边界框 根据 Pascal VOC 挑战 有这样的 如果预测的边界框重叠更多 则认为它是正确的 超过 50 带有真实边界框 否则边界框 被认为是误报检测 多次检测是
  • 现代编译器是否优化乘以 1 和 -1

    如果我写 template
  • 并排显示图像的一半 - OpenGL

    我为两个图像创建了两个纹理 现在我想在opengl中按图像2的左侧部分 完整的图像1 图像2的右侧部分的顺序显示该纹理 我已经做了如下 Image1 显示在 opengl 屏幕的中央 但屏幕的左右部分不正确 应分别显示 image2 的左侧
  • 有关 Swift 编译器选项的文档

    您好 我想开始在 Apple Swift 语言上运行一些微基准测试 然而 我觉得很难找到有关编译器优化的不同选项的适当文档 我读过很多关于其他人的语言微基准的问题和文章 但是如果能有一些关于该主题的可靠文档那就太好了 在最新的测试版中 使用
  • 如何重复更新单个 Vulkan 渲染通道内对象数量的统一数据并使更新同步?

    我正在尝试将我的 OpenGL 3D 游戏引擎移植到 Vulkan 游戏场景中有大量的 3D 对象 每个对象都有自己的属性 模型矩阵 灯光等 并且对象是完全动态的 这意味着在游戏过程中可能会出现一些 3D 对象 而另一些可能会被移除 使用
  • 着色器属性 mat4 未正确绑定(Opengl ES 2.0 Android)

    我有以下着色器 protected final static String vertexShaderCode attribute vec4 vPosition attribute vec2 texCoord attribute mat4 u
  • 如何获取片段的当前颜色?

    我正在尝试了解 GLSL 中的着色器 并且找到了一些有用的资源和教程 但我一直在寻找一些应该是基本且微不足道的东西 我的片段着色器如何检索当前片段 你通过说设置最终颜色gl FragColor whatever 但显然这是一个仅输出值 如何
  • GCC、字符串化和内联 GLSL?

    我想使用宏字符串化来声明内联 GLSL 着色器字符串 define STRINGIFY A A const GLchar vert STRINGIFY version 120 n attribute vec2 position void m
  • 未定义的行为真的有助于现代编译器优化生成的代码吗?

    现代编译器不是足够聪明 能够生成快速且安全的代码吗 看下面的代码 std vector

随机推荐