OpenGL ES 2.0 - Android上的多通道/后处理

时间:2014-12-27 16:35:05

标签: android opengl-es-2.0 post-processing

我是新手,也是OpenGL ES 2.0 for Android的新手。我正在尝试做一些非常简单的事情但由于某些原因我无法让它发挥作用。 基本上我试图使用帧缓冲在片段着色器中进行一些后处理工作,然后在屏幕上显示它。下面是我的片段着色器的简化版本:

precision mediump float;

uniform sampler2D u_Texture0;
uniform sampler2D u_Texture1;
uniform float u_FirstPass;
varying vec3 v_texCoord;

float mytexture2D(sampler2D text0, vec2 coord)
{
    vec4 pixelColor=texture2D(text0, coord.xy);
    return pixelColor.r * 0.299 + pixelColor.g * 0.587 + pixelColor.b * 0.114;
}

void main() 
{    
    if(u_FirstPass==1.0)
    {
        gl_FragColor = vec4(0.0,0.0,mytexture2D(u_Texture0, v_texCoord.st),1.0);
    }
    else
    {
        gl_FragColor = texture2D(u_Texture1, v_texCoord.st);
    }
}

我正在使用的FrameBufferObject类是:

package com.my.cameratesting;

import android.opengl.GLES20;

public class FrameBufferObject {
    public int colorTexture;
    private int frameBuffer;
    private int depthRenderBuffer;

    public FrameBufferObject(){

    }

    public void generate(int w, int h){
           //Generate color texture
           //-------------------------
           int [] id = new int[1];
           GLES20.glGenTextures(1, id, 0);
           colorTexture = id[0];
           GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, colorTexture);
           GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
           GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
           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.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, w, h, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
           //-------------------------

           // Generate frame buffer;
           //-------------------------
           GLES20.glGenFramebuffers(1, id, 0);
           frameBuffer = id[0];
           GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffer);
           //Attach 2D texture to this FBO
           GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, colorTexture, 0);
           //-------------------------

           // Generate depth render buffer
           //-------------------------
           GLES20.glGenRenderbuffers(1, id, 0);
           depthRenderBuffer = id[0];
           GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, depthRenderBuffer);
           GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, w, h);
           //-------------------------

           //Attach depth buffer to FBO
           GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, depthRenderBuffer);
           //-------------------------
           //and now you can render to GL_TEXTURE_2D
           //GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffer);

           //GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
    }

    public void unbind(){
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
    }

    public void bind(){
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffer);
    }

    public int getTextureId(){
        return colorTexture;
    }

}

最后:

@Override
public void onDrawFrame(GL10 gl) {

    GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1f);
    GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT );

    GLES20.glUseProgram(mProgramHandle);
    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);    

    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    //fbo0 is properly instanciated in my onSurfaceCreated function
    fbo0.generate(mWidth, mHeight);
    fbo0.bind();

    GLES20.glUniform1i(mTextureUniformHandle0, 0);
    GLES20.glUniform1f(mFirstPassUniformHandle,1);
    checkFBOError();

    objects[0].draw(mProgramShader,mMVPMatrix);

    fbo0.unbind();

    //***** THIS IS THE BIT THAT DOESNT WORK AS I WOULD LIKE IT TO*******/

    GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,fbo0.colorTexture);
    GLES20.glUniform1i(mTextureUniformHandle1, 0);
    GLES20.glUniform1f(mFirstPassUniformHandle,0);

    objects[0].draw(mProgramShader,mMVPMatrix);
}

所以我期待我的照片在第一次传球后以蓝色显示 - 当我不使用任何帧缓冲并且不打算运行第二次传球时,它工作正常。现在当我运行第二遍时,我期待相同的输出,因为我没有对我的u_Texture1进行任何修改......相反,我得到一个黑屏。 我在绑定纹理时显然做错了,但我不清楚纹理之间的这种乒乓是如何工作的。我做了很多谷歌搜索,无法在任何地方找到任何明确的例子。所以,如果有人能在这里帮助我,那将是很棒的,因为我已经在这很长一段时间里一直在用这个打击我。 THKS。

顺便说一下,如果您需要更多详细信息,请告诉我。

1 个答案:

答案 0 :(得分:0)

当你渲染第二遍时,看起来你并没有使用你在第一遍中产生的纹理:

GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,fbo0.colorTexture);
GLES20.glUniform1i(mTextureUniformHandle1, 0);
GLES20.glUniform1f(mFirstPassUniformHandle,0);

这会将纹理绑定到纹理单元1,但随后设置均匀,以便着色器从纹理单元0采样。如果要使用纹理单元1,则设置制服的调用需要为:

GLES20.glUniform1i(mTextureUniformHandle1, 1);

还有一些可能涉及的事情:

  • 至少在此处显示的代码中,您永远不会清除FBO。在绑定FBO后,您需要确保有glClear()电话。

  • 我认为此调用首先需要纹理绑定。还要确保您拥有正确的活动纹理单元:

    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);    
    

    您可能不想在每次重绘时从位图加载纹理。您应该能够在安装过程中加载一次。

  • 您在每次重绘时调用generate()方法。在设置期间,大部分内容只需要完成一次。

  • ES 2.0中的非二次幂纹理不保证GL_REPEAT环绕模式。除非您的宽度和高度是2的幂,否则您可能希望使用GL_CLAMP_TO_EDGE来确定它适用于所有设备。