之前的博客opengl 离屏渲染,实现相机的实时滤镜讲到过离屏渲染,主要是android层的应用,这里在jni层来实现,并来讲解下原理,以及和android层的不同的地方。
#extension GL_OES_EGL_image_external : require
uniform samplerExternalOES vTexture;
opengl离屏渲染
平时我们设置shader,然后draw是将我们的纹理图像绘制到了系统默认的0号frambuffer中,这个buffer用户是读取不到的,只是用来显示渲染用。因此为了离屏渲染,我们需要自己创建frambuffer,当然我们自己创建的frambuffer是可以读取到里面的colorbuffer的,即texure。
创建frambuffer
glGenFramebuffers(1 , &fboObject);
这样创建了frambuffer我们还不能用来绑定,因为frambuffer得含有三部分:
colorBuffer:即所谓的texture的buffer
创建和纹理的创建一样:
void CreateTexture2D( GLuint* textures ,int number ,unsigned char *pixelData, int width, int height ,GLenum type){
glGenTextures(number ,textures);
for(int i=0 ;i< number ; i++) {
glBindTexture(GL_TEXTURE_2D, textures[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// 表示图像放大时候,使用线性过滤
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);// 表示图像缩小时候,使用线性过滤
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, type, width, height, 0, type, GL_UNSIGNED_BYTE,
pixelData);//GL_RGBA
glBindTexture(GL_TEXTURE_2D, 0);
}
}
depthBuffer:只让opengl读取,用户无法读取,但还是得创建
stencilBuffer:模板buffer,同样只有opengl读取,但也得创建。
其中后面的2个buffer,组成RenderBuffer,RenderBuffer第一个为depthbuffer,第二个为stencilBuffer
创建2个buffer,只需要创建RenderBuffer
//生成renderbuffer
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER,rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// 挂载 depth buffer fbo上
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo);
//挂载stencil buffer fbo上
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
node:这里的width和height都为纹理渲染的大小,若renderbuffer中的glRenderbufferStorage小了,可能导致图像纹理显示不全。
使用frambuffer
创建好了renderBuffer 和 colorbuffer后,调用下面函数就可以bind frambuffer,然后我们渲染的图像就会会知道我们定义的framebuffer中,屏幕将不会显示我们的图片,这时候如果调用filter,即其他的图像处理shader,处理我们定义的frambuffer中的colorbuffer,即texture, 就可以达到多次处理的效果了。
void fbo::bind(){
glBindFramebuffer(GL_FRAMEBUFFER , fboObject);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,colorBuffer[(currentColorBufferIndex + 1)%2],0);
currentColorBufferIndex = (currentColorBufferIndex + 1)%2;
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
}
解除frambuffer
void fbo::unBind() {
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
这里给出demo,给大家参考。