在 OpenGL 中采样 16 位高度图的正确方法是什么

What is the correct way to sample a 16-bit height map in OpenGL

我有一个由 16 位有符号值组成的高度图,我只是想知道从着色器中对其进行采样的正确方法是什么。到目前为止,我使用的是 GL_R16 格式,我认为这种格式将图像存储为无符号整数,但是当采样 returns 一个浮点数时,我假设它被标准化为 0 - 1。是否还有一个选项将纹理采样为存储在纹理中的整数而不是浮点数?

当我上传我做的纹理时:

glTexImage2D(GL_TEXTURE_2D, 0, GL_R16, 10800, 10800, 0, GL_R16, GL_SHORT, buffer.data());

在我的着色器中,我对其进行了采样:

float colour = texture2D(heightmap, texCoords).r;
outFragColour = vec4(colour, colour, colour, 1);

好像只采样了黑色(即0);

此外,这会保留高度图的负值吗?这一切都非常令人困惑。

编辑:我刚刚意识到我在调用时从 OpenGL 得到一个 INVALID_ENUM 错误:

glTexImage2D(GL_TEXTURE_2D, 0, GL_R16, 10800, 10800, 0, GL_R16, GL_SHORT, buffer.data());

谢谢。

纹理格式:

  • GL_R16 将 [0, 65535] 区间映射到 [0, 1]。它本身不能表示负值,当然你可以在自己采样后调整值。

  • GL_R16_SNORM 会在采样时将 [-32767, 32767] 范围映射到 [-1, 1],因此您可以原生存储负值。

  • GL_R16I 不做映射。它在采样时准确存储值 [-32768, 32767] 和 returns。但是,此纹理格式 不支持插值 ,因此您可以指定的唯一 minification/magnification 过滤器是 GL_NEARESTGL_NEAREST_MIPMAP_NEAREST。您必须在着色器中使用整数采样器类型(如 isampler2D),并且采样函数将 return ivec4 中的数据。

  • GL_R16UIGL_R16I 相同,但用于 [0, 65535] 范围内的无符号数据。对应的采样器类型为usampler2D,采样函数为return uvec4.

  • 中的数据
  • GL_R16F 是 half-float 格式。它是上述所有内容的一个很好的替代方案,因为如果您可以忍受其较低的精度,它具有普通浮点数据的优点。

至于你的代码:

不清楚为什么你只有黑色。如果 data 中的所有值都很小,那么在转换为 on-screen 8 位格式时,它们可能会简单地四舍五入为零,因此您会看到全黑。

确保没有出现任何错误(例如,您的纹理很大,OpenGL 是否有足够的内存来创建此纹理?)。