【问题标题】:Strategies for packing data into OpenGL 3D array将数据打包到 OpenGL 3D 数组中的策略
【发布时间】:2013-03-19 02:41:31
【问题描述】:

我正在 OpenGL 4.3.0 中实现体素光线投射器。我有一个基本版本,我将浮点值的 256x256x256 体素数据集存储在相同尺寸的 3D 纹理中。

但是,我想使用八叉树制作 LOD 方案。我将数据存储在主机端的一维数组中。根的索引为 0,根的子节点的索引为 1-8,下一级的索引为 9-72,依此类推。八叉树总共有 9 个级别(最后一个级别具有完整的 256x256x256 分辨率)。因为八叉树总是满的,所以结构是隐式的,不需要存储指针,每个体素只有一个浮点值。我已经设置好了一维索引和遍历算法。

我的问题是我不知道如何将它存储在纹理中。 GL_TEXTURE_MAX_SIZE 太小(16384),无法使用我已经找到索引的一维数组方法。我需要将它存储在 3D 纹理中,我不知道当我尝试将我的 1D 数组塞入其中时会发生什么,也不知道如何选择尺寸和 1D->3D 转换方案以免浪费空间或时间。

我的问题是,是否有人有一个很好的策略来将整个八叉树结构存储在一个 3D 纹理中,在这种情况下如何为它选择维度和索引。

【问题讨论】:

  • 你的最大纹理大小不是 3397,而是属性的枚举值。使用以下代码获取最大纹理尺寸: int size; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size);
  • 是的,当然。感谢您指出了这一点!我已经编辑了原始问题。

标签: opengl 3d glsl textures octree


【解决方案1】:

首先介绍一下直接移植一维阵列解决方案:

首先,正如Mortennobel在他的评论中所说,最大纹理大小很可能不是3397,这只是GL_MAX_TEXTURE_SIZE的枚举值( opengl.h 标头(定义此值)应该如何知道您的硬件和驱动程序限制?)。要从您的实现中获取实际值,请使用int size; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size);。但即便如此,这对你来说可能还是太小了(可能是 8192 或类似的东西)。

但要将更大的一维数组放入您的着色器,您可以使用buffer textures(自 OpenGL 3 以来它是核心,因此存在于 DX10 类硬件上)。这些是从标准 OpenGL 缓冲区对象中获取数据的纹理。但是这些纹理始终是一维的,由整数 texCoords(可以说是数组索引)访问而不是过滤。因此,它们实际上并不是真正的纹理,而是一种将缓冲区对象作为着色器内的线性 1D 数组访问的方法,这非常适合您的需求(实际上比普通过滤和标准化的 1D 纹理更适合) .


编辑:您可能还考虑像以前一样使用直接的 3D 纹理,但在较高部分使用自制的 mipmap 级别(是的,3D 纹理也可以有 mipmap)的层次结构。所以 mipmap 级别 0 是精细的 256 网格,级别 1 包含较粗的 128 网格,...但是要有效地使用此数据结构,您可能需要在着色器中显式访问 LOD 纹理(使用 textureLod 或者甚至更好没有过滤,texelFetch),这也需要 OpenGL 3。


编辑:如果您不支持 OpenGL 3,我仍然不建议使用 3D 纹理将您的 1D 数组放入,而是使用 2D 纹理,例如 Rahul 在他的回答中建议(1D-2D 索引魔法并不那么难)。但是如果你有 OpenGL 3,那么我要么使用缓冲区纹理直接使用你的线性 1D 数组布局,要么使用带有 mipmaps 的 3D 纹理进行直接八叉树映射(或者可能会提出一个完全不同且更复杂的数据结构首先是体素网格)。


编辑:当然,完全细分的八叉树并没有真正利用八叉树的内存节省特性来发挥其优势。对于将八叉树打包到 3D 纹理中的更动态和内存效率更高的方法,您还可以从这个经典的 GPU Gems article on octree textures 中获得一些灵感。它们基本上将所有八叉树单元作为 2x2x2 网格任意存储到 3D 纹理中,使用内部节点的值作为指向该纹理中子节点的指针。当然,现在您可以对此进行各种改进(因为您似乎也希望内部节点存储数据),例如将整数与浮点数一起存储并使用漂亮的位编码等,但基本思想非常简单。

【讨论】:

  • 感谢您非常详细的回答,我肯定会尝试缓冲纹理。我确实支持 OpenGL 3。至少我会从那里开始!长期目标是能够使用稀疏八叉树,但现在完整的八叉树就足够了。
【解决方案2】:

这是一个解决方案草图/大纲:

使用 2D 纹理来存储您的 256x256x256(它将是 4096x4096 -- 我希望您使用的是支持 4k x 4k 纹理的 OpenGL 平台)。

现在以行优先顺序存储您的一维数据。在您的光线投射器中,只需进行行/列转换(从 1D 地址到 4k x 4k)并查找您需要的值。

我相信你会自己解决剩下的:)

【讨论】:

  • 谢谢,但问题不在于将 256x256x256 数据集打包到纹理中。那部分是我想出来的!
猜你喜欢
  • 1970-01-01
  • 2017-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-29
  • 2018-02-05
  • 2010-09-20
  • 1970-01-01
相关资源
最近更新 更多