如何在调用glDrawElements后使用FrameBuffer中的glReadPixels获取“渲染”图像

时间:2017-01-09 08:33:10

标签: android bitmap opengl-es

我通过OpenGL ES 2.0的片段着色器修改了某些图像的亮度,对比度和饱和度。并且......为了保存修改后的图像,我使用了这种方法。

public static Bitmap saveTexture(int texture, int width, int height) {
    int[] frame = new int[1];
    GLES20.glGenFramebuffers(1, frame, 0);
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frame[0]);
    GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, texture, 0);

    ByteBuffer buffer = ByteBuffer.allocate(width * height * 4);
    GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buffer);
    Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    bitmap.copyPixelsFromBuffer(buffer);

    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
    GLES20.glDeleteFramebuffers(1, frame, 0);

    return bitmap;
}

但是,此方法返回原始图像,而不是修改。怎么了? 请告诉我如何解决这个问题。 :/

我添加了更多信息。 这段代码是我的GLSurfaceView.Renderer的代码。

@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
    mTextureID = OpenGLTools.loadImageTexture(mBitmap, true);
    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    mProgram = OpenGLTools.loadProgram(VERTEX_SHADER, FRAGMENT_SHADER);
}

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

@Override
public void onDrawFrame(GL10 gl10) {
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    draw();
}

public void draw() {
    if (!GLES20.glIsProgram(mProgram)) OpenGLTools.loadProgram(VERTEX_SHADER, FRAGMENT_SHADER);
    GLES20.glUseProgram(mProgram);

    int positionHandle = GLES20.glGetAttribLocation(mProgram, "position");
    GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 0, mVertexBuffer);
    GLES20.glEnableVertexAttribArray(positionHandle);

    int textureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "inputTextureCoordinate");
    GLES20.glVertexAttribPointer(textureCoordinateHandle, 2, GLES20.GL_FLOAT, false, 0, mTexCoordBuffer);
    GLES20.glEnableVertexAttribArray(textureCoordinateHandle);

    int brightness = GLES20.glGetUniformLocation(mProgram, "brightness");
    GLES20.glUniform1f(brightness, mEditParams.mBrightness / 200.0f);
    int contrast = GLES20.glGetUniformLocation(mProgram, "contrast");
    GLES20.glUniform1f(contrast, mEditParams.mContrast / 200.0f);
    int saturation = GLES20.glGetUniformLocation(mProgram, "saturation");
    GLES20.glUniform1f(saturation, (mEditParams.mSaturation + 100) / 100.0f);

    GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, mDrawListBuffer);

    GLES20.glDisableVertexAttribArray(positionHandle);
    GLES20.glDisableVertexAttribArray(textureCoordinateHandle);
}

public Bitmap getBitmap() {
    return OpenGLTools.saveTexture(mTextureID, mBitmap.getWidth(), mBitmap.getHeight());
}

而且......这是OpenGLTools类中的代码。

public static int loadImageTexture(final Bitmap bitmap, final boolean recycle) {
    int[] textureNames = new int[1];
    GLES20.glGenTextures(1, textureNames, 0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureNames[0]);
    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_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);

    if (recycle) {
        bitmap.recycle();
    }

    return textureNames[0];
}

public static int loadProgram(final String vsc, final String fsc) {
    int[] success = new int[1];

    int vshader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
    GLES20.glShaderSource(vshader, vsc);
    GLES20.glCompileShader(vshader);
    GLES20.glGetShaderiv(vshader, GLES20.GL_COMPILE_STATUS, success, 0);

    if (success[0] == 0) {
        Log.e("CheckLog", "Could not compile vertex shader : " + GLES20.glGetShaderInfoLog(vshader));
        GLES20.glDeleteShader(vshader);
        return 0;
    }

    int fshader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
    GLES20.glShaderSource(fshader, fsc);
    GLES20.glCompileShader(fshader);
    GLES20.glGetShaderiv(fshader, GLES20.GL_COMPILE_STATUS, success, 0);
    if (success[0] == 0) {
        Log.e("CheckLog", "Could not compile fragment shader : " + GLES20.glGetShaderInfoLog(fshader));
        GLES20.glDeleteShader(fshader);
        return 0;
    }

    int program = GLES20.glCreateProgram();
    GLES20.glAttachShader(program, vshader);
    GLES20.glAttachShader(program, fshader);
    GLES20.glLinkProgram(program);
    GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, success, 0);
    if (success[0] <= 0) {
        Log.e("CheckLog", "Could not link OpenGLES program :" + GLES20.glGetProgramInfoLog(program));
        GLES20.glDeleteProgram(program);
        return 0;
    } else {
        Log.i("CheckLog", "Linked OpenGLES program");
    }

    return program;
}

public static Bitmap saveTexture(int texture, int width, int height) {
    int[] frame = new int[1];
    GLES20.glGenFramebuffers(1, frame, 0);
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frame[0]);
    GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, texture, 0);

    ByteBuffer buffer = ByteBuffer.allocate(width * height * 4);
    GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buffer);
    Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    bitmap.copyPixelsFromBuffer(buffer);

    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
    GLES20.glDeleteFramebuffers(1, frame, 0);

    return bitmap;
}

如果我触摸保存按钮,则在OpenGLES上下文中调用getBitmap方法。我可以更改Bitmap的参数(亮度,对比度和饱和度),它会实时显示。但是,当我触摸保存按钮时,更改的参数不会应用于保存的图像。我想用更改的参数保存图像。

1 个答案:

答案 0 :(得分:0)

您将原始纹理句柄作为texture参数输入到saveTexture(),因此毫不奇怪这是您要保存回磁盘的数据。

您实际上并不想保存纹理 - 您希望保存活动帧缓冲区的内容 - 因此该功能不是您的代码所需的功能。试试这个:

public static Bitmap saveTexture(int width, int height) {   
    ByteBuffer buffer = ByteBuffer.allocate(width * height * 4);
    GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buffer);
    Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    bitmap.copyPixelsFromBuffer(buffer);      
    return bitmap;
}