opengl 离屏渲染,实现相机的实时滤镜

android 相机预览中讲到了,我们使用的是:samplerExternalOES ,这个不能自由的变化预览的尺寸,还会出现卡顿现象,为了克服这个问题,也是采用网上的一些人的解决方案,既将samplerExternalOES 转化为 sampler2D,然后再进行渲染。

这里我们还是以相机预览为基础,这里我们最终将 texture不再渲染到屏幕,而是渲染到buffer中,因此我们在draw 之前,创建(为空时候创建,只创建一次) 绑定 fFrame和outTextureId,这样我们draw就不会渲染到屏幕了,而是渲染到创建的outTextureId。这样就完成了samplerExternalOES 转化为 sampler2D

//创建
if(fFrame[0] ==0)
 GLES20.glGenFramebuffers(1, fFrame, 0);
 if(outTextureId[0] ==0)
 EasyGlUtils.genTexturesWithParameter(1, outTextureId,0,GLES20.GL_RGBA,width,height);
 //绑定
  GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBufferId);
  GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, 
  GLES20.GL_TEXTURE_2D, textureId, 0);
  
 public static void genTexturesWithParameter(int size,int[] textures,int start,
                             int gl_format,int width,int height){
        GLES20.glGenTextures(size, textures, start);
        for (int i = 0; i < size; i++) {
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[i]);
            GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0,gl_format, width, height,
                0, gl_format, GLES20.GL_UNSIGNED_BYTE, null);
            useTexParameter();
        }
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,0);
    }

那么我们接下来要怎么显示outTexture呢,这里我们需要新的着色器(用sampler2D),例如最简单的着色器:

//#extension GL_OES_EGL_image_external : require
precision mediump float;
varying vec2 textureCoordinate;
uniform sampler2D vTexture;
//uniform samplerExternalOES vTexture;

void main()
 {
   gl_FragColor = texture2D( vTexture, textureCoordinate );
 }

然后setTexute(outTexture),draw出来就好了。有时候为了添加多个filter,因此 写了一个groupFitler 这里可以 添加多个filter,并且只需要额外的创建2个 texture2d。

public class GroupFilter {

    private  ArrayList<LyFilter> lyFilters = new ArrayList<>();

    private CameraFilter cameraFilter;


    public GroupFilter(CameraFilter cameraFilter){
        this.cameraFilter = cameraFilter;
        width = cameraFilter.getWidth();
        height = cameraFilter.getHeight();
        createFrameBuffer();
    }

    public void addFilter(LyFilter lyFilter){
        lyFilters.add(lyFilter);
    }

    private int textureIndex=0;
    public void draw(){

        cameraFilter.draw();

        textureIndex=0;
        for(LyFilter filter:lyFilters){
            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fFrame[0]);
            GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, fTexture[textureIndex%2], 0);
            GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, fRender[0]);

            if(textureIndex ==0){
                filter.setTextureId(cameraFilter.getOutTextureId());
            }else{
                filter.setTextureId(fTexture[(textureIndex - 1)%2]);
            }
                filter.draw();
                unBindFrame();
                textureIndex++;
        }

    }
    public int getOutputTexture() {
        if (lyFilters.size() == 0) {
            return cameraFilter.getOutTextureId();
        } else {
            return  fTexture[(textureIndex - 1) % 2];
        }
    }


    public void onSizeChanged(int width, int height) {
        this.width=width;
        this.height=height;
        cameraFilter.onSizeChanged(width , height);
        createFrameBuffer();
    }

    //创建离屏buffer
    private int fTextureSize = 2;
    private int[] fFrame = new int[1];
    private int[] fRender = new int[1];
    private int[] fTexture = new int[fTextureSize];

    private int width , height;

    //创建FrameBuffer
    private boolean createFrameBuffer() {
        GLES20.glGenFramebuffers(1, fFrame, 0);
        GLES20.glGenRenderbuffers(1, fRender, 0);

        genTextures();
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fFrame[0]);
        GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, fRender[0]);
        GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, width,
                height);
        GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
                GLES20.GL_TEXTURE_2D, fTexture[0], 0);
        GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT,
                GLES20.GL_RENDERBUFFER, fRender[0]);
//        int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
//        if(status==GLES20.GL_FRAMEBUFFER_COMPLETE){
//            return true;
//        }
        unBindFrame();
        return false;
    }

    //生成Textures
    private void genTextures() {
        GLES20.glGenTextures(fTextureSize, fTexture, 0);
        for (int i = 0; i < fTextureSize; i++) {
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fTexture[i]);
            GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height,
                    0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
            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);
            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);
        }
    }

    //取消绑定Texture
    private void unBindFrame() {
        GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, 0);
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
    }


    private void deleteFrameBuffer() {
        GLES20.glDeleteRenderbuffers(1, fRender, 0);
        GLES20.glDeleteFramebuffers(1, fFrame, 0);
        GLES20.glDeleteTextures(1, fTexture, 0);
    }

}

完整的demo欢迎各位老铁下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值