第一次听到离屏渲染的时候觉得很高级,遥不可及,直到后来做高斯模糊的时候,需要通过两次处理来节省性能,一直玩一次渲染处理的我这时候才认识FBO,继而明白了离屏渲染,今天抽个空做个记录。
一、FBO怎么用
由于我玩纹理比较多,所以就通过纹理来介绍FBO的用法吧,对纹理不熟可以看看我之前文章。至于FBO是什么这种概念,可以百度下,到处都是,我就不写了。
FBO其实就是帧缓存对象,有时候渲染一次结束,需要保存处理的结果,当作下一次处理的输入时,我们就可以把上一次的处理纹理保存到帧缓存中,给下一个着色器输入即可。
1.FBO的创建和绑定
先上代码:
glGenFramebuffers(1, &FBO[0]); //和其他buffer类似的创建
glGenTextures(1, &uTexture[2]); //再创建个纹理对象
glBindTexture(GL_TEXTURE_2D, uTexture[2]); //绑定纹理,接下来设置纹理的默认参数
// 为当前绑定的纹理对象设置环绕、过滤方式
// 将纹理包装设置为GL_REPEAT(默认包装方法)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// 设置纹理过滤参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); //此处尺寸设置要是窗口大小,很重要,也可以自己尝试别的尺寸,看效果
glBindFramebuffer(GL_FRAMEBUFFER, FBO[0]); //绑定FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, uTexture[2], 0);//将纹理绑到FBO上
glBindTexture(GL_TEXTURE_2D, 0);//解绑纹理对象
glBindFramebuffer(GL_FRAMEBUFFER, 0);//解绑FBO
从上面可以看到我们为FBO绑定了一张空有尺寸无内容的纹理,为什么呢?因为我们用帧缓存是去存处理后的纹理的,所以绑定个啥样的都不重要,但尺寸要对!
2.FBO的使用
同样还是代码,在渲染时这么写:
glUseProgram(programObject[3]); // 使用着色器,假设我这里是第3号着色器
glBindVertexArray(VAOId[0]); // 使用VAO信息
glActiveTexture(GL_TEXTURE1); //激活纹理单元
glBindTexture(GL_TEXTURE_2D, uTexture[0]);//设定纹理对象,0号纹理
glUniform1i(glGetUniformLocation(programObject[3], "uTexture1"), 1);//将0号纹理绑定到shader中的纹理变量
glBindFramebuffer(GL_FRAMEBUFFER, FBO[0]); //绑定FBO开始操作
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);//绘制
glBindFramebuffer(GL_FRAMEBUFFER, 0);//解绑FBO
从上述可以看出,跟普通使用着色器绘制相比就多了两行代码,绑定FBO和解绑,有了这两行代码,着色器处理后的结果将不会显示在窗口了,而是保存到FBO绑定的纹理对象上,比如上面绑定的2号纹理对象。离屏渲染也就是这么回事。
那么怎么使用这个FBO保存的纹理呢?怎么多次离屏渲染呢?看接下来的代码:
glUseProgram(programObject[1]); // 使用着色器
glActiveTexture(GL_TEXTURE0); //激活纹理单元
glBindTexture(GL_TEXTURE_2D, uTexture[2]);//绑定FBO[0]绑定的纹理对象
glUniform1i(glGetUniformLocation(programObject[1], "uTexture1"), 0);//将纹理绑定到shader中的纹理变量
glBindFramebuffer(GL_FRAMEBUFFER, FBO[1]); //绑定第二个FBO对象
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);//解绑
glUseProgram(programObject[0]); // 使用着色器
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, uTexture[1]); //绑定FBO[1]绑定的纹理对象,假设为1号
glUniform1i(glGetUniformLocation(programObject[0], "uTexture1"), 1);//将0号纹理绑定到shader中的纹理变量
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
上面代码先是使用了第一个FBO绑定的纹理,再是用第二个FBO对象去保存第二步着色器处理的纹理,再给第三步着色器使用,这样就利用两次离屏渲染实现了3次处理,当然我们还可以进行三次,四次的离屏渲染,以此类推。
二、总结
前期我也遇到了很多不知名问题,很是崩溃,但是逐行去理解代码之后,问题一一解决,沉下气静下心来理解代码很容易就通畅了。希望有问题可以提出来,非常感谢!