在 OpenGL ES Android 中更改背景颜色会更改纹理颜色

Changing background color in OpeGL ES Android changes color of texture

如果我更改 GLES20.glClearColor(1.0f, 1.0f, 0.0f, 1.0f) 的背景,然后尝试绘制纹理,最后的颜色会发生意外变化。这是 png 文件:

当我尝试简单地显示它时,应用程序的结果是:

我正在使用此代码:

public class GLRenderer implements GLSurfaceView.Renderer {

    private static final String TAG = "MyGLRenderer";
    private float[] vertices = {
            -1f, -1f,
            1f, -1f,
            -1f, 1f,
            1f, 1f
    };

    private float[] textureVertices = {
            0f, 1f,
            1f, 1f,
            0f, 0f,
            1f, 0f
    };

    private final String vertexShaderCode =
            "attribute vec4 aPosition;" +
                    "attribute vec2 aTexPosition;" +
                    "varying vec2 vTexPosition;" +
                    "void main() {" +
                    "  gl_Position = aPosition;" +
                    "  vTexPosition = aTexPosition;" +
                    "}";

    private final String fragmentShaderCode =
            "precision mediump float;" +
                    "uniform sampler2D uTexture;" +
                    "varying vec2 vTexPosition;" +
                    "void main() {\n" +
                    "vec4 color = texture2D(uTexture, vTexPosition);\n"+
                  //"if(color.r == 0.0 && color.g == 0.0 && color.b == 0.0)\n"+
                  // "color = vec4(1.0,0.5,0.5,1.0);"+
                  //  "discard;"+
                    "  gl_FragColor = color;" +
                    "}";

    private FloatBuffer verticesBuffer;
    private FloatBuffer textureBuffer;


    private int vertexShader;
    private int fragmentShader;
    private int program;

    private Bitmap bmp;
    private int textures[] = new int[2];
    // mMVPMatrix is an abbreviation for "Model View Projection Matrix"
    private final float[] mMVPMatrix = new float[16];
    private final float[] mProjectionMatrix = new float[16];
    private final float[] mViewMatrix = new float[16];
    private final float[] mRotationMatrix = new float[16];

    public GLRenderer() {
        bmp=Bitmap.createBitmap(513,912, Bitmap.Config.ARGB_8888);
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        GLES20.glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
        checkGlError("glClearColor");
        setup();
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0, 0, width, height);

        float ratio = (float) width / height;
        Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);

    }

    @Override
    public void onDrawFrame(GL10 gl) {
        Log.d("Drawing_Frame","Working");
        float[] scratch = new float[16];

        // Draw background color
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

        // Set the camera position (View matrix)
        Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

        // Calculate the projection and view transformation
        Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);

        // Draw Bitmap
        drawBinaryImage(bmp,textures[0]);
        Matrix.setRotateM(mRotationMatrix, 0, 0, 0, 0, 1.0f);
        Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);

    }

    private void setup(){
        GLES20.glGenTextures(2, textures, 0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);

        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        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);
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
        //GLES20.glBindTexture(GL);
        initializeBuffers();
        initializeProgram();



    }


    private void initializeBuffers() {
        ByteBuffer buff = ByteBuffer.allocateDirect(vertices.length * 4);
        buff.order(ByteOrder.nativeOrder());
        verticesBuffer = buff.asFloatBuffer();
        verticesBuffer.put(vertices);
        verticesBuffer.position(0);

        buff = ByteBuffer.allocateDirect(textureVertices.length * 4);
        buff.order(ByteOrder.nativeOrder());
        textureBuffer = buff.asFloatBuffer();
        textureBuffer.put(textureVertices);
        textureBuffer.position(0);
    }
    private void initializeProgram() {
        vertexShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
        GLES20.glGetShaderInfoLog(vertexShader);
        checkGlError("glCreateShader");
        GLES20.glShaderSource(vertexShader, vertexShaderCode);
        GLES20.glCompileShader(vertexShader);

        fragmentShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
        GLES20.glShaderSource(fragmentShader, fragmentShaderCode);
        GLES20.glCompileShader(fragmentShader);

        program = GLES20.glCreateProgram();
        GLES20.glAttachShader(program, vertexShader);
        GLES20.glAttachShader(program, fragmentShader);

        GLES20.glLinkProgram(program);
        checkGlError("glLinkProgram");

    }
    public void updateTexture(Bitmap bmp){
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
    }
    private void drawBinaryImage(Bitmap bmp,int texture){
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
        GLES20.glUseProgram(program);
        //Changes Here original Line GLES20.glDisable(GLES20.GL_BLEND);
        GLES20.glDisable(GLES20.GL_CULL_FACE);
        GLES20.glDisable(GLES20.GL_DEPTH_TEST);
        GLES20.glEnable(GLES20.GL_BLEND);
        GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE);

        int positionHandle = GLES20.glGetAttribLocation(program, "aPosition");
        int textureHandle = GLES20.glGetUniformLocation(program, "uTexture");
        int texturePositionHandle = GLES20.glGetAttribLocation(program, "aTexPosition");
        //Log.d("GL_SETUP",positionHandle+" , "+textureHandle);
        GLES20.glVertexAttribPointer(texturePositionHandle, 2, GLES20.GL_FLOAT, false, 0, textureBuffer);
        GLES20.glEnableVertexAttribArray(texturePositionHandle);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
        Log.d("FILTER_APPLY","Applying");
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);
        GLES20.glUniform1i(textureHandle, 0);

        GLES20.glVertexAttribPointer(positionHandle, 2, GLES20.GL_FLOAT, false, 0, verticesBuffer);
        GLES20.glEnableVertexAttribArray(positionHandle);

        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
        checkGlError("glDrawArrays");
    }

    public void setBitmap(Bitmap bitmap){
        updateTexture(bitmap);
        this.bmp = bitmap;
    }
    public static void checkGlError(String glOperation) {
        int error;
        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
            Log.e(TAG, glOperation + ": glError " + error);
            throw new RuntimeException(glOperation + ": glError " + error);
        }
    }
}

帧缓冲区被GLES20.glClearColor(1.0f, 1.0f, 0.0f, 1.0f);清除。
RGBA(1, 1, 0, 1) 黄色 。这导致在渲染纹理之前,整个帧缓冲区被黄色填充。

纹理包含 blue 颜色 RGBA(0, 0, 1, 1)black 颜色 RGBA(0, 0, 0, 1)

绘制带有纹理的四边形时,使用以下函数启用混合:
(参见 Blending and glBlendFunc

GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE);

在混合时,帧缓冲区的当前颜色与实际绘制的颜色混合。通过以下功能完成上述设置:

destinationColor = sourceColor * 1 + destinationColor * 1

在纹理为蓝色的区域,最终颜色变为白色:

(1, 1, 0) * 1 + (0, 0, 1) * 1 = (1, 1, 1)

在纹理为黑色的区域,帧缓冲区中的颜色保持黄色:

(1, 1, 0) * 1 + (0, 0, 0) * 1 = (1, 1, 0)