【问题标题】:How to use unsigned short in an opengl shader?如何在 opengl 着色器中使用 unsigned short?
【发布时间】:2014-06-17 22:53:00
【问题描述】:

我正在尝试在着色器中上传带有未签名短裤的纹理,但它不起作用。

我尝试了以下方法:

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, vbt[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 640, 480, 0, GL_RED, GL_UNSIGNED_SHORT, kinect_depth);
glUniform1i(ptexture1, 1);
GLenum ErrorCheckValue = glGetError();

我知道我正确绑定了纹理,因为我通过使用得到了一些结果

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, vbt[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 640, 480, 0,
    GL_RG, GL_UNSIGNED_BYTE, kinect_depth);
glUniform1i(ptexture1, 1);
GLenum ErrorCheckValue = glGetError();

特别是,我在红色通道中获得了我的部分价值观。我想将纹理作为无符号字节或浮点数上传。但是,我无法正确获取 glTexImage2D 调用。此外,是否可以使用深度纹理进行类似的操作?我想对我从 kinect 获得的深度信息做一些操作并显示出来。

【问题讨论】:

  • kinect_depth 的类型是什么?为什么您的第二个示例使用GL_RG 而您的第一个示例使用GL_RGB
  • 如果您想以无符号短裤的形式访问着色器中的数据,您需要以这种方式将其存储在纹理中,并将其指定为内部格式(第三个参数)。您可能想要使用GL_R16UIGL_RG16UIGL_RGB16UI,具体取决于您拥有的频道数量。
  • GL_UNSIGNED_SHORT 在您对glTexImage2D (...) 的调用中没有与 GPU 如何存储您的纹理有关。这仅在 GL 读取您的图像数据时使用,因此它知道如何解释像素。 GL_RGB(由于缺少大小而非常模糊)很有可能会变成 8 位无符号归一化(GL_RGB8)。
  • @ColonelThirtyTwo 第二个案例是一个黑客,以确保我正确绑定纹理。数据类型为 uint16。

标签: c opengl glsl glteximage2d


【解决方案1】:

您对glTexImage2D 的论点不一致。第三个参数 (GL_RGB) 建议您想要一个 3 分量纹理,第 7 个参数 (GL_RED) 建议一个单分量纹理。然后你的另一个尝试使用GL_RG,它建议了 2 个组件。

您需要使用存储未签名短裤的内部纹理格式,例如GL_RGB16UI

如果你想要一个组件,你的调用应该是这样的:

glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, 640, 480, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, kinect_depth);

如果你想要三个组件:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16UI, 640, 480, 0, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, kinect_depth);

您还需要确保着色器中用于对纹理进行采样的类型与存储在纹理中的数据类型相匹配。在此示例中,由于您使用包含无符号整数值的 2D 纹理,因此您的采样器类型应为 usampler2D,并且您希望将采样操作的结果(在着色器中调用 texture() 的结果)存储在变量输入uvec4。 (根据Andon的建议添加的段落)

更多关于glTexImage2D 的格式/类型参数的背景知识,因为这是相当频繁的误解的根源:

第三个参数 (internalFormat) 是您的 OpenGL 实现将存储在纹理中的数据格式(如果硬件不支持确切格式,则至少是最接近的格式),并且将从纹理中采样时使用。

最后 3 个参数(formattypedata)属于一起。 formattype 描述了 data 中的内容,即它们描述了您传递给 glTexImage2D 调用的数据。

最好让这两种格式保持匹配。和本例一样,您传入的数据是GL_UNSIGNED_SHORT,而内部格式GL_R16UI 包含无符号短值。在 OpenGL ES 中,内部格式需要匹配格式/类型。如有必要,完整的 OpenGL 会进行转换,这出于性能原因是不可取的,而且通常不是您想要的,因为纹理中数据的精度与原始数据的精度不同。

【讨论】:

  • 您可能想要添加关于 GLSL 着色器所需更改的信息,以便实际使用整数纹理。 (例如 usampler2D 然后返回的颜色将存储在uvec4 中)。我不完全相信 OP 需要/想要一个整数纹理,归一化的定点似乎足以进行深度计算。
  • @Andon:好建议,我会补充的。我刚刚添加了一些其他细节。添加采样方面也会使答案更完整。
  • @Andon:好的,完成,谢谢。顺便说一句,我在做一些事实检查时注意到,较新的 GL 版本也有格式值,如 GL_RED_INTEGERGL_RGB_INTEGER。我没有去深入研究这些内容的全部细节。看起来它们实际上应该在这种情况下使用。
  • 是和不是。 GL_RED_INTEGER 告诉 GL 保持精确的整数值而不是标准化。例如,假设您有GL_R16UI 并使用GL_REDGL_UNSIGNED_BYTE...在这种情况下,255 的值将被标准化为 1.0,然后1.0 的值映射到 16 位无符号整数纹理中的 65535。如果您使用 GL_RED_INTEGER,则 255 的值将保持为 255。这是一个与像素转移有关的怪癖; GL ES,在像素传输过程中不支持数据转换,绝对需要GL_R16UIGL_RED_INTEGER配对,否则会产生错误。
  • 我不确定我是否完全理解了答案。保持 internalFormat 和格式一致似乎很重要,但同时它似乎不是强制性的,可能不是我的问题的根源,也就是说,我在着色器中只得到零。另一方面,我确实尝试了 GL_R16UI,但我的笔记本电脑返回了一个错误(来自 gluErrorString 的无效操作)。我忘了在我的问题中提到这一点。
猜你喜欢
  • 2019-09-19
  • 2013-05-29
  • 1970-01-01
  • 1970-01-01
  • 2011-03-10
  • 1970-01-01
  • 2011-04-19
  • 2011-08-13
  • 1970-01-01
相关资源
最近更新 更多