使用 OpenGL 渲染位数组
Posted
技术标签:
【中文标题】使用 OpenGL 渲染位数组【英文标题】:Rendering a bit array with OpenGL 【发布时间】:2016-10-15 14:25:49 【问题描述】:我有一个表示图像掩码的位数组,存储在uint8_t[]
容器数组中,按行第一顺序排列。因此,对于每个字节,我有 8 个像素。
现在,我需要使用 OpenGL ( >= 3.0 ) 来渲染它。正位被绘制为白色像素,负位被绘制为黑色像素。
我怎么能这样做?请
想到的第一个想法是为此开发一个特定的着色器。任何人都可以提供一些提示吗?
【问题讨论】:
您使用的是哪个 OpenGL 版本?如果您使用具有固定功能管道(OpenGL 由于 OpenGL 每个纹素至少需要 8 位,因此您很可能需要将蒙版转换为灰度图像。 4.5 规范提到了 STENCIL_INDEX1。不确定你会用它做什么,所以它可能不适合你。 "现在,我需要将其渲染为 2D 图像/纹理" 您是尝试从这样的图像中采样还是渲染到这样的图像一个图像? "in row first order." 这是否保证每个字节都来自特定的行?也就是说,图像的宽度是否可以被 8 整除? @NicolBolas 我不确定我是否理解您的问题。我想将其显示为白色/黑色像素 2D 图像 【参考方案1】:您绝对必须为此编写一个着色器。首先,您要防止 OpenGL 实现将 B/W 位图的整数位重新解释为特定范围内的数字,并将它们映射到 [0…1] 浮点数。这意味着您必须将您的位加载为整数图像格式。由于您的图像格式是二进制像素的八位字节组(字节是一个相当不具体的术语,可以指代任意数量的位,尽管通常是 8 位),单通道格式 8 位格式似乎是正确的选择。 OpenGL-3 的名字是GL_R8UI
。请记住,纹理的“宽度”将是黑白图像实际宽度的 1/8。此外,对于非规范化访问,您必须使用usampler
(用于未签名)或isampler
(用于签名)(感谢@derhass 注意到此处未正确写入)。
要访问单个位,您可以使用通常的位操作运算符。由于您不希望您的位被过滤,因此必须使用 texel 提取访问。因此,要访问整数位置 x,y 处的二进制像素,将使用以下内容。
uniform usampler2D tex;
uint shift = x % 8;
uint mask = 1 << shift;
uint octet = texelFetch(tex, ivec2(x/8,y)).r;
value = (octet & mask) >> shift;
【讨论】:
如果你使用非规范化的无符号整数格式,你也应该使用usampler
...
@derhass:已修复
@manatttta:以像素为单位的纹理坐标。您必须将它们作为顶点属性(进入顶点着色器)传递,然后使用 out
变量将其传递给片段着色器。
谢谢。不过,我还有另一个问题(抱歉滥用)。我正在使用 > 20k 像素的图像。仍然在创建纹理时,我将其大小作为原始图像的宽度和高度传递。由于典型的 gpu 将允许 8k 像素之类的东西,我可以修改纹理大小以传递整个图像吗?
@manatttta:有几种方法可以解决这个问题。您可以使用多个纹理。您可以使用 2D 阵列纹理(即几个未混合的 2D 图层,与 3D 纹理一样,并使用图层索引来遍历图块)。最后但并非最不重要的一点是,您可以使用稀疏纹理 (opengl.org/registry/specs/ARB/sparse_texture.txt),它允许您定义“虚拟纹理”,其中只有当前需要的部分由您的程序按需加载。【参考方案2】:
最好的解决方案是使用着色器,你也可以像这样破解:
std::bitset<8> bits = myuint;
然后用 bits.at(position) 获取单个位的值,最后做一个简单的点画。
【讨论】:
以上是关于使用 OpenGL 渲染位数组的主要内容,如果未能解决你的问题,请参考以下文章