我如何通过 glReadPixels 读取数据?

How can i read data by glReadPixels?

我正在 Android 上开发 openGL es。 现在我遇到一个问题。我定义了一个float数组,用来传递给fragment shader

float[] data = new float[texWidth*texHeight];
// test data
for (int i = 0; i < data.length; i++) {
    data[i] = 0.123f;
}

1。初始化纹理:

glGenTextures...
glBindTexture...
glTexParameteri...
FloatBuffer fb = BufferUtils.array2FloatBuffer(data);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, fb);

2.FBO:

glGenBuffers...
glBindFramebuffer...
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId, 0);

3.onDrawFrame:

glUseProgram(mProgram);...
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);...

IntBuffer fb = BufferUtils.iBufferAllocateDirect(texWidth*texHeight);
glReadPixels(0, 0, texWidth, texHeight, GL_RGBA, GL_UNSIGNED_BYTE, fb);
System.out.println(Integer.toHexString(fb.get(0)));
System.out.println(Integer.toHexString(fb.get(1)));
System.out.println(Integer.toHexString(fb.get(2)));

片段着色器:

precision mediump float;
uniform sampler2D sTexture;
varying vec2 vTexCoord;

void main()
{
    tex = texture2D(sTexture, vTexCoord.st);
    vec4 color = tex;
    gl_FragColor = color;
}

那么,如何使用 glReadPixels 获取浮点数据(0.123f,我之前定义的)?现在我得到的是 ff000000(ABGR),所以我怀疑着色器没有通过这种方式获取数据。有人可以告诉我为什么以及我该如何处理吗?我是新手,非常感谢。

您的主要问题发生在 glReadPixels() 之前。主要问题在于您使用 glTexImage2D():

的方式
FloatBuffer fb = BufferUtils.array2FloatBuffer(data);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0,
             GL_RGBA, GL_UNSIGNED_BYTE, fb);

第 8 个参数的 GL_UNSIGNED_BYTE 值指定传入的数据由无符号字节组成。但是,缓冲区中的值是浮点数。所以你的浮点值被解释为字节,这不可能很好地结束,因为它们是完全不同的格式,具有不同的大小和内存布局。

现在,您可能会想这样做:

FloatBuffer fb = BufferUtils.array2FloatBuffer(data);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0,
             GL_RGBA, GL_FLOAT, fb);

这适用于桌面 OpenGL,它支持隐式格式转换作为指定纹理数据的一部分。但 OpenGL ES 不支持。在 ES 2.0 中,GL_FLOAT 甚至不是格式参数的合法值。在 ES 3.0 中,它是合法的,但仅适用于实际存储浮点数的内部格式,如 GL_RGBA16FGL_RGBA32F。将它与 GL_RGBA 内部格式(第三个参数)结合使用是错误的。

所以除非你在 ES 3.0 中使用浮点纹理(它消耗更多内存),否则你需要将你的原始数据转换为字节。如果浮点值介于 0.0 和 1.0 之间,则可以将它们乘以 255,然后四舍五入到下一个整数。

然后您也可以使用 glReadPixels() 将它们作为字节读回,并且应该再次获得相同的值。