我试图在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()
),请参阅我的答案。
答案 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像素值。如果要执行此操作,则需要通过调用GLSurfaceView
在setEGLConfigChooser(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上生成屏幕外的图像,这非常有用。