帧缓冲组成:颜色缓冲、深度缓冲、模板缓冲
应用:离屏渲染、后期处理
完整的帧缓冲:
- 附加至少一个缓冲(颜色、深度或模板缓冲)。颜色附件使用纹理,深度、模板附件使用渲染缓冲对象。
- 至少有一个颜色附件(Attachment)。还有深度缓冲附件、模板缓冲附件等。
- 所有的附件都必须是完整的(保留了内存)。
- 每个缓冲都应该有相同的样本数。
检查帧缓冲是否完整:
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) // 执行胜利的舞蹈
创建帧缓冲:
unsigned int fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
附件:是一个内存位置,它能作为帧缓冲的一个缓冲。有两种,纹理或渲染缓冲对象(Renderbuffer Object)
纹理:当把一个纹理附加到帧缓冲的时候,所有的渲染指令将会写入到这个纹理中,就像它是一个普通的颜色/深度或模板缓冲一样。
为帧缓冲创建一个纹理:
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 800, 600, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
将纹理附(作为颜色附件)加到帧缓冲上:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
参数:
target
:帧缓冲的目标(绘制、读取或者两者皆有)attachment
:我们想要附加的附件类型。当前我们正在附加一个颜色附件。注意最后的0
意味着我们可以附加多个颜色附件。我们将在之后的教程中提到。textarget
:你希望附加的纹理类型texture
:要附加的纹理本身level
:多级渐远纹理的级别。我们将它保留为0。
将深度或模板附件附加到帧缓冲上:(这里使用纹理,最好使用渲染缓冲对象)
附件类型:
GL_DEPTH_ATTACHMENT
GL_STENCIL_ATTACHMENT
GL_DEPTH_STENCIL_ATTACHMENT
//深度+模板缓冲
glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 800, 600, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL ); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texture, 0);
渲染缓冲对象:是一个真正的缓冲,即一系列的字节、整数、像素等。渲染缓冲对象附加的好处是,它会将数据储存为OpenGL原生的渲染格式,它是为离屏渲染到帧缓冲优化过的。
渲染缓冲对象通常都是只写的,所以你不能读取它们(比如使用纹理访问)。当然你仍然还是能够使用glReadPixels来读取它,这会从当前绑定的帧缓冲,而不是附件本身,中返回特定区域的像素。
创建一个渲染缓冲对象:
unsigned int rbo;
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
将渲染缓冲对象设置为深度和模板渲染缓冲对象:
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 800, 600);
将渲染缓冲对象附加到帧缓冲上:
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 800, 600);
由于渲染缓冲对象通常都是只写的,它们会经常用于深度和模板附件,因为大部分时间我们都不需要从深度和模板缓冲中读取值,只关心深度和模板测试。我们需要深度和模板值用于测试,但不需要对它们进行采样,所以渲染缓冲对象非常适合它们。当我们不需要从这些缓冲中采样的时候,通常都会选择渲染缓冲对象,因为它会更优化一点。
步骤:
将场景渲染到纹理,场景每帧更新一次,纹理也每帧更新一次。opengl会对部分物体进行裁剪,每次只渲染了部分场景;当摄像机移动时,投影矩阵会变化,看到的场景也会变化。
摄像机移动,我们所看到的场景会像直接渲染到默认帧缓冲中一样随之变化,但在这个项目中,本质上我们看到的还是一张图片,只是这张图片会不断更新。
创建并绑定帧缓冲;
附加颜色附件、深度和模板附件;
绑定默认帧缓冲;
绑定新的帧缓冲;
渲染到纹理(为空白的纹理填充颜色,形成一个纹理);
绑定默认帧缓冲;
使用纹理();
处理后渲染到屏幕。