java - OpenGL ES 2.0 : Alpha value in fragment shader is ignored (using glReadPixels())

标签 java android graphics opengl-es-2.0 alphablending

我正在尝试在 Android 上使用 OpenGL ES 2.0 显示一个非常简单的东西(至少我是这么认为的):具有透明度的单色四边形。我的 fragment 着色器基本上就是这样做的:

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

因此,四边形应显示为纯红色,但透明度为 50%,以便背景(黑色)透过,这会使其稍微暗一些。然而,无论我为 vector 中的 Alpha channel 元素选择什么值,四边形都具有完全相同的外观。即使我将 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);

表面 View 的创建方式如下:

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

为什么 Alpha channel 会被忽略?我是否错过了打开或关闭某些东西?使用的硬件:搭载 Android 4.2.1 的 Google Nexus 10。

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

最佳答案

选择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)

请注意,当您处理图像时,预乘很有用:它可以为每个 fragment 节省 GPU 三次乘法。

关于java - OpenGL ES 2.0 : Alpha value in fragment shader is ignored (using glReadPixels()),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20254811/

相关文章:

android - iPhone 5 和 5S 媒体查询级联到三星 Galaxy S4

java - 随机颜色背景

java - 高效更新已排序的 JavaFX ObservableList

java - Twitter 快速回复 - Twitter4J (Java) 示例

android - RLIMIT_NPROC 的正确定义是什么?

android - 如果 View 更改其 XY 位置,则在 View 上收听

java - java中的多彩多变的文本

Java Graphics - 当我点击 -> all before works 时,repaint() 不起作用

java - 如何使 NoSuchElementException 不显示并将其替换为我自己的错误消息

java - 使用 ExecutorService 时正确管理内存