OpenGL ES 2.0 在 Android 上 Alpha 值显示为黑色

4

我能够成功地将位图呈现到纹理上并在手机屏幕上显示它,没有问题。我现在想尝试从PNG文件中渲染另一个纹理覆盖在其上。覆盖的PNG文件包含一些透明(α)像素。

我可以将覆盖层渲染在背景纹理图像上方,但是当我这样做时,似乎透明像素被渲染为半透明黑色?除非黑色实际上来自我设置为黑色的纹理背景... 有人有什么建议吗,我可能做错了什么或者另一种实现所需效果的方法?

顶点着色器:

private final String vertexTextureShaderCode =
                "attribute vec4 aPosition;"+ // Position of out Vertex
                "attribute vec2 aTexPosition;"+ // Position of our texture contained in the vertex
                "varying vec2 vTexPosition;"+ //
                "void main(){"+
                "    gl_Position = aPosition;"+
                "    vTexPosition = aTexPosition;"+
                "}";

片元着色器:

private final String fragmentTextureShaderCode =
            "precision mediump float;" +
            "uniform sampler2D uTexture;" + // Our Background Image  ( Our uploaded image)
            "uniform sampler2D uOverlay;"+ // Our Ovrelay image
            "varying vec2 vTexPosition;" +
            "void main() {" +
            "  vec4 colImage = texture2D(uTexture,vTexPosition);" +
            "  vec4 colOverlay = texture2D(uOverlay, vTexPosition);"   +
            "  gl_FragColor = mix(colImage, colOverlay, 0.7);" +
            "}";

绘制框架方法
 public void drawOverlay(Context context,int resourceId){
    BitmapFactory.Options opts = new BitmapFactory.Options();
    opts.inScaled = false;

    Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId,opts);

    // Bind our TEXTURE_COORDS to the array
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,mTexturePointer[1]);

    // Create the nearest filter TEXTURE_COORDS
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);

    // Use Android GL Utils to specify a 2d TEXTURE_COORDS image from our bitmap
    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

    bitmap.recycle();

    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
    GLES20.glUseProgram(mProgram);

    // ENable bledning

//       GLES20.glEnable(GLES20.GL_BLEND);
//
//        // User SRC_OVE
//        GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);

    // get handle to vertex shader vPosition member
    mPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
    mTextureHandle = GLES20.glGetUniformLocation(mProgram, "uTexture");
    mTextureOverlayhandle = GLES20.glGetUniformLocation(mProgram, "uOverlay");
    mTexturePositionHandle = GLES20.glGetAttribLocation(mProgram, "aTexPosition");

    GLES20.glVertexAttribPointer(mTexturePositionHandle, 2, GLES20.GL_FLOAT, false, 0, mTextureBuffer);
    GLES20.glEnableVertexAttribArray(mTexturePositionHandle);

    // ACTIVATING OUR FIRST TEXTURE, I.E our background image.
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexturePointer[0]);
    GLES20.glUniform1i(mTextureHandle,0);

    // ACTIVATE OUR SECOND SECOND I.E our overlay
    GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexturePointer[1]);
    GLES20.glUniform1i(mTextureHandle,1);

    // Prepare the triangle coordinate data
    GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, vertexBuffer);

    // enable a handle to the triangle vertice
    GLES20.glEnableVertexAttribArray(mPositionHandle);

    // clear the colors
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

    GLES20.glDisable(GLES20.GL_DEPTH_TEST);

    GLES20.glEnable(GLES20.GL_BLEND);

    // User SRC_OVER
    GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
    // Draw the square
    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount);

    // Disbale the vertex array
    GLES20.glDisableVertexAttribArray(mPositionHandle);

}

在我的片段着色器中使用混合方法是正确的吗?我应该将这两张图片绘制到一个纹理(sampler2D)中,而不是使用mix函数来处理两个sampler2D对象吗?如果是这样,我该怎么做呢?每次我尝试这样做时,前景纹理直接覆盖了背景纹理。


据我所记,Bitmap对象(以及其底层的skia库)使用预先计算的alpha通道...因此通过BitmapFactory加载的带有alpha通道的png纹理无法正常工作...当我在使用OpenGL时,我使用原生的libpng进行加载。 - Selvin
没错,预乘 alpha 确实是这个问题的原因。然而,许多资源都指向使用 GLES20.BLEND 作为解决方法。但在我的情况下似乎并没有起作用。 - Devsil
1个回答

2

好的,我解决了自己的问题。

我试图将两个不同的位图绘制到一个纹理上,但是使用了相同的纹理句柄。上面发布的片段着色器无法实现这种类型的结果。在这两个纹理上使用 "mix" 不是正确的方法。

正确的方法是只使用一个纹理,但为我的背景纹理和前景纹理设置句柄。在 draw() 方法中,首先设置背景图像,就像通常一样使用 glDrawArrays(...),然后再使用另一个 glDrawArrays(...) 调用将前景图像(使用正确的指针)设置为绘制前景图像。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接