无法在 openGL 片段着色器中正确检索 16 位整数

Cannot correctly retrieve 16-bit integers inside openGL fragment shader

我想做的事:在 iOS.

上使用 openGL ES 2.0,在片段着色器中使用带符号的 16 位整数进行 GPGPU 计算

我已经验证我已经正确设置了我的(输入)纹理缓冲区和(输出)帧缓冲区,并且可以传递 16 位整数(通过使用无符号的 8 位指针别名到缓冲区),将各个字节渲染到帧缓冲区,检索字节并在 CPU 端重建正确的 16 位值。

如果我调用 glClearColor,我可以传入

这样的值
glClearColor(0.5, 0.5, 0.5, 0.5);  // endian-agnostic way to initialize buffer with "no data" values (-32640)
glClear(GL_COLOR_BUFFER_BIT);

我正在使用 glClearColor 的测试值 (0.5, 0.5, 0.5, 0.5)。这些应该等同于传入 -32640(有符号)或 32896(无符号)。

我可以正确地检索片段着色器中的值(作为无符号等效值)

#extension GL_EXT_shader_framebuffer_fetch : require

varying highp vec2 vTexCoord;
uniform sampler2D myTexture;

void main()
{
    lowp vec4 myIntArray = texture2D( myTexture, vTexCoord);
    // Retrieve value from frame buffer
    lowp vec4 lastFragColor = gl_LastFragData[0];

    // Recover the value (stored in alpha (high byte) and red (low byte)
    highp float signed_value = lastFragColor.a;
    signed_value = signed_value*255.0*256.0 + lastFragColor.r*255.0;

    //  ... Do stuff with the recovered value.
    // Here, I simply verify value is recovered correctly (as an unsigned int equivalent):

    // This draws the pixel green, indicating success
    if (signed_value >= 32896.0) {
        gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
    }
    else {
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    }

    // But changing the threshold value very slightly (replacing the lines
    // above with those below) draws the pixel red, correctly
    // indicating the condition is not met, because the value is
    // 32896
    if (signed_value >= 32896.01) {
        gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
    }
    else {
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    }
}

但是,我想传递一个不同值的数组,所以我没有使用 glClearColor,而是设置了一个缓冲区,并将一个指向我的有符号 16 位整数数组的指针传递给它(基本上是别名到我的有符号 int16_t 字节就好像它们只是无符号字节一样。)

然后我可以将它们渲染到帧缓冲区,并使用 glReadPixels 并将指向该数组的 int16_t 指针重新设置为 CPU 上的别名以返回正确的值。然而,使用与上面相同的逻辑,但访问我的纹理而不是帧缓冲区:

highp float signed_value = myIntArray.a;
signed_value = value*255.0*256.0 + myIntArray.r*255.0;

使用纹理中的值,我只能在片段着色器中正确重建从 0 到 32767 的值,但不能重建 > 32767 的值。我需要能够重建 2^16 个可能值中的任何一个,或者作为签名或未签名。为什么我可以从帧缓冲区而不是我的纹理缓冲区重建大于 32767 的值?

(编辑添加:更正 - 似乎我无法通过我的纹理传入、渲染和检索 所有 16 位整数......之前出现的是负面的值是使用 glClear() 进行初始化的产物。我通过纹理渲染为黑色传递的负值,并在 CPU 上重建为零。正确处理 0 到 32767 之间的值。所以...是可以传入带符号的 int16 值(或无符号的 int16 值 > 32767)并在片段着色器中正确重建它们?)

原来片段着色器代码没问题;我找错地方了。我不知道的是,"client" 将输入限制为非负值。谜团解开了,尽管额头上有一个大耳光。