将数据打包到OpenGL 3D阵列的策略

时间:2013-03-19 02:41:31

标签: opengl 3d glsl textures octree

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

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

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

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

2 个答案:

答案 0 :(得分:3)

首先直接移植您的1D阵列解决方案:

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

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


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


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


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

答案 1 :(得分:1)

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

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

现在以行主顺序存储您的1D数据。在raycaster内部,只需进行行/列转换(从1D地址到4k x 4k)并查找所需的值。

我相信你会自己弄清楚其余的事情:)