OpenGL3.3帧缓冲
帧缓冲
帧缓冲的定义:用于写入颜色值的颜色缓冲、用于写入深度信息的深度缓冲和允许我们根据一些条件丢弃特定片段的模板缓冲。这些缓冲结合起来叫做帧缓冲,如果我们不用自己写的帧缓冲 那用的是默认的帧缓冲是在你创建窗口的时候生成和配置的
一个完整的帧缓冲需要满足以下的条件:
1.附加至少一个缓冲(颜色、深度或模板缓冲)。
2.至少有一个颜色附件(Attachment)。
3.所有的附件都必须是完整的(保留了内存)。
4.每个缓冲都应该有相同的样本数
纹理附件:当把一个纹理附加到帧缓冲的时候,所有的渲染指令将会写入到这个纹理中。优点是:所有渲染操作的结果将会被储存在一个纹理图像中
渲染缓冲对象附件:渲染缓冲对象是一个真正的缓冲,即一系列的字节、整数、像素等。好处是,它会将数据储存为OpenGL原生的渲染格式
离屏渲染:渲染到一个不同的帧缓冲,因为渲染不是在默认的帧缓冲中,所以渲染指令不会再窗口中显示
创建帧缓冲的过程:
unsigned int fbo;
glGenFramebuffers(1, &fbo);//创建帧缓冲对象
glBindFrameBuffer(GL_FRAMEBUFFER,fbo);//绑定帧缓冲对象
/ 生成纹理
unsigned int texColorBuffer
glGenTextures(1, &texColorBuffer);//创建一个纹理
glBindTexture(GL_TEXTURE_2D, texColorBuffer);//绑定这个纹理
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 800, 600, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);//将这个纹理设置成屏幕大小800,600,并且data位设置为NULL,先不传数据进去
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);//绑定为0号纹理
// 将它附加到当前绑定的帧缓冲对象
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texColorBuffer, 0);
unsigned int rbo;
glGenRenderbuffers(1, &rbo);//创建一个渲染缓冲对象
glBindRenderbuffer(GL_RENDERBUFFER, rbo); //绑定这个对象
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 800, 600); //创建一个深度和模板渲染缓冲对象,选择GL_DEPTH24_STENCIL8作为内部格式,它封装了24位的深度和8位的模板缓冲。
glBindRenderbuffer(GL_RENDERBUFFER, 0);//将他绑定到0
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);//将渲染缓冲对象附加到帧缓冲的深度和模板附件上
/*这里是检查是否绑定成功*/
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0);//最后这里解绑,恢复到默认帧缓冲中 要保证所有的渲染操作在主窗口中有视觉效果,我们需要再次**默认帧缓冲,将它绑定到0
这个后面就是在绘制这张白纸上的东西之前需要先 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);绑定一下再开始绘制
其他的就是自己创建横跨屏幕的长方形,把这个纹理绘制到上面去就行了
从这里以后所有的深度和模板操作都会从当前绑定的帧缓冲的深度和模板附件中(如果有的话)读取
要想绘制场景到一个纹理上,我们需要采取以下的步骤:
1将新的帧缓冲绑定为**的帧缓冲,和往常一样渲染场景
2绑定默认的帧缓冲
3绘制一个横跨整个屏幕的四边形,将帧缓冲的颜色缓冲作为它的纹理。
函数:
unsigned int fbo;
glGenFramebuffers(1, &fbo);//创建一个帧缓冲对象
glBindFramebuffer(GL_FRAMEBUFFER, fbo);绑定缓冲对象
上面这个绑定了是读取和写入都行 也可以单独绑定为写入或者读取GL_READ_FRAMEBUFFER或GL_DRAW_FRAMEBUFFER,将一个帧缓冲分别绑定到读取目标或写入目标
glBindFramebuffer(GL_FRAMEBUFFER, 0);这个操作目前还不懂 说是**默认帧缓冲对象 将他绑定到0
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);//检查帧缓冲是否完整 如果是GL_FRAMEBUFFER_COMPLETE则完整
glDeleteFramebuffers(1, &fbo);删除帧缓冲对象
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);//将纹理附件绑定给帧缓冲
target:帧缓冲的目标(绘制、读取或者两者皆有)
attachment:我们想要附加的附件类型。当前我们正在附加一个颜色附件。注意最后的0意味着我们可以附加多个颜色附件。我们将在之后的教程中提到。
textarget:你希望附加的纹理类型
texture:要附加的纹理本身
level:多级渐远纹理的级别。我们将它保留为0。
若是要增加的是深度缓冲 则为GL_DEPTH_ATTACHMENT 此时纹理的格式和内部格式类型将变为GL_DEPTH_COMPONENT
若是要增加的是模板缓冲 则为GL_STENCIL_ATTACHMENT 并且纹理的格式设定为GL_STENCIL_INDEX
也可以将深度缓冲和模板缓冲附加为一个单独的纹理 也就是深度缓冲和模板缓冲都在一个纹理里 则为GL_DEPTH_STENCIL_ATTACHMENT 纹理的每32位数值将包含24位的深度信息和8位的模板信息 并且配置纹理的格式,让它包含合并的深度和模板值
例子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);
unsigned int rbo;
glGenRenderbuffers(1, &rbo);//创建一个渲染缓冲对象
glBindRenderbuffer(GL_RENDERBUFFER, rbo);//绑定渲染缓冲对象
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 800, 600);//创建一个深度和模板渲染缓冲对象
GL_DEPTH24_STENCIL8作为内部格式 封装了24位的深度和8位的模板缓冲
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);//附加这个渲染缓冲对象