OpenGL ES 2.0:片段着色器中的Alpha值被忽略(使用glReadPixels())

时间:2013-11-27 23:04:14

标签: java android graphics opengl-es-2.0 alphablending

我试图在Android上使用OpenGL ES 2.0显示一个非常简单的事情(至少我是这么认为的):具有透明度的单色四边形。我的片段着色器基本上只是这样做:

gl_FragColor = vec4(1.0, 0.0, 0.0, 0.5);

因此四边形应该以纯红色显示,但透明度为50%,以便背景(黑色)通过,这应该会使它更暗一些。但是,无论我为矢量中的alpha通道元素选择什么值,四边形都具有完全相同的外观。即使我将alpha设置为0.0,它也会以纯红色绘制。

我打开了GL_BLEND。以下是我的初始化:

GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);        
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
GLES20.glDisable(GLES20.GL_CULL_FACE);
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);

绘制函数尽可能简单:

GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
shader.use(); // will select the vertex and fragment shader
GLES20.glViewport(0, 0, resX, resY); // sets the viewport to the current resolution
GLES20.glEnableVertexAttribArray(v_aPosId);
GLES20.glVertexAttribPointer(v_aPosId, COORDS_PER_VERTEX,
                                 GLES20.GL_FLOAT, false,
                                 0, vertexBuf);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount);
GLES20.glDisableVertexAttribArray(v_aPosId);

表面视图的创建方式如下:

glView = new GLSurfaceView(this);
glView.setEGLContextClientVersion(2);
glView.setRenderer(new GLRenderer(this));

如何忽略alpha通道?我是否错过了打开或关闭的东西?二手硬件:谷歌Nexus 10与Android 4.2.1。

修改:当我使用glReadPixels()回读帧缓冲区时,RGBA像素值也是255, 0, 0, 255,而不是255, 0, 0, 127。但是我修好了。如果您想正确显示透明度,请参阅@ martijn-courteaux的答案。如果您想要获得正确的像素值(通过glReadPixels()),请参阅我的答案。

2 个答案:

答案 0 :(得分:3)

选择glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);混合功能时,您必须预先计算颜色。因此,这意味着您必须将每个颜色分量(红色,绿色和蓝色)乘以alpha值。在您的情况下,这将是:(1.0 * alpha, 0.0, 0.0, alpha)。混合功能描述了GPU如何计算最终颜色作为两种混合颜色的结果。如果您选择GL_ONE,GL_ONE_MINUS_SRC_ALPHA,则您有以下公式:

finalColor = srcColor + (1 - srcAlpha) * dstColor;

如果你填写红色,你会看到:

finalColor = (1.0, 0.0, 0.0) + (1 - 0.5) * (0.0, 0.0, 0.0)
           = (1.0, 0.0, 0.0)

这就是为什么它看起来很纯粹的红色。

如果您不喜欢,请将混合功能更改为:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);如果您使用此功能,公式显然会显现:

finalColor = srcAlpha * srcColor + (1 - srcAlpha) * dstColor;

插上你的红色:

finalColor = 0.5 * (1.0, 0.0, 0.0) + (1.0 - 0.5) * (0.0, 0.0, 0.0)
           = (0.5, 0.0, 0.0)

请注意,在使用图像时,预乘是很好的:它会为每个片段保存GPU三次乘法。

答案 1 :(得分:1)

我发现了。关于以正确的透明度显示四边形,@ martijn-courteaux的回答(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA))是完全正确的。 但是,我试图实现一些我尚未提及的不同之处。我不只是想正确显示四边形,而是想使用glReadPixels()获取生成的图像的正确RGBA像素值。如果要执行此操作,则需要通过调用GLSurfaceViewsetEGLConfigChooser(8, 8, 8, 8, 0, 0)中选择正确的EGL配置。注意第4个“8”。 android文档说“默认情况下视图将选择RGB_888表面”,所以我不得不将alpha通道设置为8。现在,您必须通过glDisable(GL_BLEND) 禁用混合。现在GL表面将绘制四边形而没有透明度,但如果使用glReadPixels(),它将返回RGBA像素值255, 0, 0, 127,就像上面的片段着色器一样。如果您在GPU上生成屏幕外的图像,这非常有用。