使用 glReadPixels 读取 rgb 值时,OpenGLES Alpha 值会修改它们

Posted

技术标签:

【中文标题】使用 glReadPixels 读取 rgb 值时,OpenGLES Alpha 值会修改它们【英文标题】:OpenGLES Alpha value modifies rgb values when reading them out with glReadPixels 【发布时间】:2021-08-13 19:02:16 【问题描述】:

当使用glReadPixels 读取 rgba(1,1,1,0.1) 时,将导致 rgba(0.1,0.1,0.1,???)。该函数正在从帧缓冲区读取修改后的值,我假设是因为 alpha 混合。

我使用的示例具有以下设置:

片段着色器:

String fragmentShaderSource =
        "  #version 440\n" +
        "  out vec4 gl_FragColor;\n" +
        "  in vec4 gl_FragCoord;  \n" +
        "  varying vec2 v_texCoords;\n" +
        "\n" +
        "  uniform float chunkSize;\n" +
        "  layout(binding=1)uniform sampler2D inputs1;\n" +
        "  layout(binding=2)uniform sampler2D inputs2;\n" +
        "\n" +
        "  void main(void)\n" +
        "    gl_FragColor.r = 1;\n" +
        "    gl_FragColor.g = 1;\n" +
        "    gl_FragColor.b = 1;\n" +
        "    gl_FragColor.a = 0.1;\n" +
        "  "
        ;

初始化:

fboHandle = Gdx.gl.glGenFramebuffer();
Gdx.gl.glBindFramebuffer(GL20.GL_FRAMEBUFFER, fboHandle);

/* Create output texture */
outputTextureHandle = Gdx.gl.glGenTexture();
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0);
Gdx.gl.glBindTexture(GL20.GL_TEXTURE_2D, outputTextureHandle);
Gdx.gl.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MIN_FILTER, GL20.GL_NEAREST);
Gdx.gl.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MAG_FILTER, GL20.GL_NEAREST);
Gdx.gl.glTexImage2D(
    GL20.GL_TEXTURE_2D, 0, GL30.GL_RGBA32F,
    width, height, 0, GL20.GL_RGBA, GL20.GL_FLOAT, null
);

/* Configure Framebuffer */
/* Set "renderedTexture" as our colour attachement #0 */
Gdx.gl.glFramebufferTexture2D(
    GL20.GL_FRAMEBUFFER, GL20.GL_COLOR_ATTACHMENT0,
    GL20.GL_TEXTURE_2D, outputTextureHandle, 0
);

渲染后:

Gdx.gl30.glReadPixels(0,0,width, height, GL20.GL_RGBA, GL20.GL_FLOAT, resultBuf);
System.out.println("result r: " + resultBuf.get(0));
System.out.println("result g: " + resultBuf.get(1));
System.out.println("result b: " + resultBuf.get(2));
System.out.println("result a: " + resultBuf.get(3));

输出:

result r: 0.1
result g: 0.1
result b: 0.1
result a: 0.90999997

我不明白为什么 alpha 值是这样的。根据this answer 的说法,在渲染到帧缓冲区时,alpha 通道会丢失,并用于修改像素值。

我的问题:

当 rgb 值发生“组合”时,Alpha 通道会发生什么情况? 我了解除了 alpha 以外的像素值会发生什么情况,但这是为什么呢? 是否可以禁用此行为,以便使用 glReadPixels 保留 alpha 值和原始像素值?

补充:Gdx.gl.glBlendFunc(GL20.GL_ONE, GL20.GL_ZERO); 被调用,或使用Gdx.gl.glDisable(GL20.GL_BLEND); 禁用混合时,观察到相同的行为。

使用渲染缓冲区代替纹理颜色附件具有相同的效果。

【问题讨论】:

您是否碰巧调用glReadBufferglReadPixels 指向您的帧缓冲区对象?我认为默认情况下,像素将从后台缓冲区中读取;要读取 FBO 中的值,您需要在读取像素之前调用 glReadBuffer(GL_COLOR_ATTACHMENT0);。在您的示例中,您正确请求了一个具有 alpha 值存储的渲染表面,但取决于您如何配置应用程序的默认帧缓冲区(即,通过 EGL、GLX 等与窗口关联的帧缓冲区),它可能不包括任何用于存储 alpha 值的位。 我没有明确地调用它,但现在我调用了它,它仍然产生相同的结果。谢谢你的建议! 【参考方案1】:

glReadPixels 没有修改任何值。

我认为您的帧缓冲区的像素一开始是 rgba(0,0,0,1),然后您使用启用了 alpha 混合的 rgba(1,1,1,0.1) 进行渲染。

所以你看到了:

src * srcalpha + dest * (1.0 - srcalpha)

(1,1,1,0.1)*0.1 + (0,0,0,1)*0.9 = (0.1,0.1,0.1,0.901)

您需要禁用 alpha 混合才能看到您期望的结果(我假设您期望 rgba(1,1,1,0.1))。

你的 libgdx 是 glDisable(GL_BLEND) 或大概是 Gdx.gl.glDisable(GL20.GL_BLEND)

【讨论】:

我禁用了混合,但没有任何改变。我从未说过该函数正在修改像素值,而是该函数只能读回修改后的像素值。我会在问题中澄清这一点。 出于某种原因,我认为设置Gdx.gl.glBlendFunc(GL20.GL_ONE, GL20.GL_ZERO); 会起作用,但它仍然不起作用 我可以在您正在使用的Gdx.gl.glDraw* 呼叫之前检查您正在使用Gdx.gl.glDisable(GL20.GL_BLEND)Gdx.gl.glBlendFunc(GL20.GL_ONE, GL20.GL_ZERO); 吗? 任意组合,最终结果都是一样的。

以上是关于使用 glReadPixels 读取 rgb 值时,OpenGLES Alpha 值会修改它们的主要内容,如果未能解决你的问题,请参考以下文章

glReadPixels 与屏幕像素

整个窗口的 glReadPixels (OpenGL)

如何使用 glReadPixels 读取浮点数据

保存使用 glReadPixels 读取的图像,其中 alpha 值不是一

opengl glReadPixels

glReadPixels 不更新值