QT+OpenGL 面剔除和帧缓冲

简介: OpenGL能够检查所有面向(Front Facing)观察者的面,并且渲染他们,而丢弃那些背向的面,节省我们很多的片段着色器的调用。我们需要告诉OpenGL哪些是正面,哪些是背面。逆时针是正面,顺时针是反面。

QT+OpenGL 面剔除和帧缓冲

本篇完整工程见gitee:QtOpenGL 对应点的tag,由turbolove提供技术支持,您可以关注博主或者私信博主


面剔除

OpenGL能够检查所有面向(Front Facing)观察者的面,并且渲染他们,而丢弃那些背向的面,节省我们很多的片段着色器的调用。


我们需要告诉OpenGL哪些是正面,哪些是背面。逆时针是正面,顺时针是反面。

glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);

glCullFace函数有三个可用的选项:


●  GL_BACK:只剔除背向面。

GL_FRONT:只剔除正向面。

GL_FRONT_AND_BACK:剔除正向面和背向面。


帧缓冲

颜色缓冲、深度缓冲和模板缓冲,这些缓冲结合起来就叫帧缓冲。他被存储在显存中,我们目前所做的所有操作都在默认帧缓冲的渲染缓冲上进行的。


帧缓冲能够让我们在场景中加入类似镜子的东西,或者作出很酷的后期处理效果。


创建一个帧缓冲,并绑定它:

unsigned int fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffers(GL_FRAMEBUFFER, fbo);

也可以使用GL_READ_FRAMEBUFFER或者GL_WRITE_FRAMEBUFFER,将一个帧缓冲分别绑定到读取目标或者写入目标。


我们现在还不能使用我们的帧缓冲,因为它还不完整,一个完整的帧缓冲需要满足以下的条件:


   ● 附加至少一个缓冲(颜色、深度或模板缓冲)。

   ● 至少有一个颜色附件(Attachment)。

   ● 所有的附件都必须是完整的(保留了内存)。

   ● 每个缓冲都应该有相同的样本数。


从上面的条件中可以知道,我们需要为帧缓冲创建一些附件,并将附件附加到帧缓冲上。在完成所有的条件之后,我们可以以GL_FRAMEBUFFER为参数调用glCheckFramebufferStatus,检查帧缓冲是否完整。它将会检测当前绑定的帧缓冲,并返回规范中值的其中之一。如果它返回的是GL_FRAMEBUFFER_COMPLETE,帧缓冲就是完整的了。


GL_FRAMEBUFFER_UNDEFINED是 如果指定的帧缓冲是默认值,则返回 读取或绘制帧缓冲,但默认 帧缓冲不存在。

GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT如果有任何帧缓冲连接,则返回 点是帧缓冲不完整。

GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT如果帧缓冲没有 至少附有一个图像。

GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER如果值 为 对于任何颜色,则返回 由 命名的连接点。GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE GL_NONE GL_DRAW_BUFFERi

GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER如果不是,则返回,并且值 is 表示颜色 由 命名的连接点。GL_READ_BUFFER GL_NONE GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE GL_NONE GL_READ_BUFFER

GL_FRAMEBUFFER_UNSUPPORTED是 如果内部格式的组合返回 附加的图像违反了 依赖于实现的限制集。

GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE如果值不是 ,则返回 对于所有附加的渲染缓冲区都相同;如果 的值是 对于所有附加的纹理都不相同;或者,如果 附加的图像是渲染缓冲区和 纹理,做的价值 与 的值不匹配。GL_RENDERBUFFER_SAMPLES GL_TEXTURE_SAMPLES GL_RENDERBUFFER_SAMPLES GL_TEXTURE_SAMPLES

GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE如果 的值对于所有附着的纹理都不相同,则也会返回;或者,如果 附加的图像是渲染缓冲区和 纹理,的值不是所有附加的 纹理。GL_TEXTURE_FIXED_SAMPLE_LOCATIONS GL_TEXTURE_FIXED_SAMPLE_LOCATIONS GL_TRUE

GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS如果任何帧缓冲附件为 分层,任何填充的附件都不是 分层,或者如果所有填充的颜色附件都是 不是来自同一目标的纹理。

if(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)
  // 执行胜利的舞蹈

渲染到一个不同的帧缓冲叫做离屏渲染


在完成所有的帧缓冲操作之后不要忘了删除这个帧缓冲对象:

glDeleteFramebuffers(1, &fbo);

对帧缓冲创建一个纹理和普通纹理差不多:

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);

glFrameBufferTexture2D有以下的参数:


target:帧缓冲的目标(绘制、读取或者两者皆有)

attachment:我们想要附加的附件类型。当前我们正在附加一个颜色附件。注意最后的0意味着我们可以附加多个颜色附件。我们将在之后的教程中提到。

textarget:你希望附加的纹理类型

texture:要附加的纹理本身

level:多级渐远纹理的级别。我们将它保留为0。


将一个深度和模板缓冲附加为一个纹理,存入帧缓冲:

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原生的渲染格式


渲染缓冲对象通常都是只写的,需要深度和模板值用于测试,但是不需要对他们进行采样,所以渲染缓冲对象非常适合他们。

unsigned int rbo;
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 800, 600);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);

渲染到纹理

想要绘制场景到一个纹理上,我们需要采取以下步骤:


将新的帧缓冲绑定为激活的帧缓冲,和往常一样渲染场景

绑定默认的帧缓冲

绘制一个四边形,将帧缓冲的颜色缓冲作为它的纹理。

44c7ad723ba54d629a8cdb27ddfd2d16.png

代码在gitee中查看,这里不做展示了。


后期处理

既然整个场景都被渲染到了一个纹理上面,我们可以简单的通过修改纹理数据创建出一个非常有意思的效果。


反向:

void main()
{
    FragColor = vec4(vec3(1.0 - texture(screenTexture, TexCoords)), 1.0);
}

411d9bc315824b9192d6e164915a21b7.png

灰度:

void main()
{
    FragColor = texture(screenTexture, TexCoords);
    float average = (FragColor.r + FragColor.g + FragColor.b) / 3.0;
    FragColor = vec4(average, average, average, 1.0);
}

ea8f650eddf14452a446ebb4c81f63ae.png

void main()
{
    FragColor = texture(screenTexture, TexCoords);
    float average = 0.2126 * FragColor.r + 0.7152 * FragColor.g + 0.0722 * FragColor.b;
    FragColor = vec4(average, average, average, 1.0);
}

c1a845cbacf24dd28cfb1bc417ed95b3.png

核效果:

const float offset = 1.0 / 300.0;
void main()
{
    vec2 offsets[9] = vec2[](
    vec2(-offset,  offset), // 左上
    vec2( 0.0f,    offset), // 正上
    vec2( offset,  offset), // 右上
    vec2(-offset,  0.0f),   // 左
    vec2( 0.0f,    0.0f),   // 中
    vec2( offset,  0.0f),   // 右
    vec2(-offset, -offset), // 左下
    vec2( 0.0f,   -offset), // 正下
    vec2( offset, -offset)  // 右下
    );
   float kernel[9] = float[](
    1.0 / 16, 2.0 / 16, 1.0 / 16,
    2.0 / 16, 4.0 / 16, 2.0 / 16,
    1.0 / 16, 2.0 / 16, 1.0 / 16  
);
    vec3 sampleTex[9];
    for(int i = 0; i < 9; i++)
    {
        sampleTex[i] = vec3(texture(material.diffuse, TexCoords.st + offsets[i]));
    }
    vec3 col = vec3(0.0);
    for(int i = 0; i < 9; i++)
    col += sampleTex[i] * kernel[i];
    FragColor = vec4(col, 1.0);
}

e2969dcd87764748ac6e1daa842c891b.png

模糊:

float kernel[9] = float[](
    1.0 / 16, 2.0 / 16, 1.0 / 16,
    2.0 / 16, 4.0 / 16, 2.0 / 16,
    1.0 / 16, 2.0 / 16, 1.0 / 16
);

080aa0513e3e46aca7a3ca0e68dc7bc2.png

目录
相关文章
|
6月前
QT4.7版本的OPENGL的3D旋转模型例子
QT4.7版本的OPENGL的3D旋转模型例子
127 0
QT+OpenGL鼠标操作和模型控制
光线追踪法 从鼠标投射 3D 射线, 通过摄像机,进入场景,然后检查该光线是否与某个对象相交。
347 0
|
3月前
|
Linux
关于linux的qt发布(linuxdeployqt)中opengl版本过高的解决
关于linux的qt发布(linuxdeployqt)中opengl版本过高的解决
|
6月前
|
机器学习/深度学习 API vr&ar
Qt, OpenCV与OpenGL协同作战:图像处理与三维图形界面的完美结合
Qt, OpenCV与OpenGL协同作战:图像处理与三维图形界面的完美结合
938 4
|
异构计算
QT+OpenGL高级数据和高级GLSL
● OpenGL中的缓冲区 对象管理特定的GPU内存 ● 在将缓冲区绑定到特定的缓冲区目标时候赋予它意义 ● OpenGL在内部会保存每个目标(缓冲区)的引用,并且根据目标以不同的方式处理缓冲区。
152 0
QT+OpenGL高级数据和高级GLSL
|
6月前
|
Linux API iOS开发
【Qt 渲染引擎】一文带你了解qt的三种 渲染引擎,包括栅格引擎(Raster)、OpenGL 和本地绘图系统
【Qt 渲染引擎】一文带你了解qt的三种 渲染引擎,包括栅格引擎(Raster)、OpenGL 和本地绘图系统
196 0
|
存储 异构计算
QT+OpenGL深度测试
在前面的文章中,我们渲染了一个3D箱子,并且运用了深度缓冲来防止阻挡的面渲染到其他面的前面。 现在大部分的GPU都提供一个叫做提前深度测试(Early Depth Testing)的硬件特性。提前深度测试允许深度测试在片段着色器之前运行。只要我们清楚一个片段永远不会是可见的(它在其他物体之后),我们就能提前丢弃这个片段。
123 0
QT+OpenGL 摄像机
OpenGL本身没有摄像机的定义,但是我们可以通过把场景中的所有物体往相反方向移动的方式来模拟出摄像机,产生一种我们在移动的感觉。
172 0
|
6月前
Qt+OpenGL 打砖块游戏
Qt+OpenGL 打砖块游戏
71 0
|
6月前
|
数据可视化 API vr&ar
qt“五彩斑斓“ opengl
qt“五彩斑斓“ opengl