Aquacolor

Aquacolor



LearningOpenGL【16】

Gumdrop · 2025-09-14 · 4浏览 · 未分类


face culling

cull和discard差不多是同义,所以这也是减去一部分运算的方法,和alpha test(fragment discard)类似,但是其发生的位置不同、使用的方式不同。

用到的函数包括:

  • glEnable(GL_CULL_FACE)

  • glCullFace(GL_FRONT)

  • glFrontFace(GL_CCW)

一些英文知识是前方front-facing、后方back-facing、顺时针clockwise、逆时针counter_clockwise。

在draw函数调用后,将能够得到三角形面元,它顶点存储与提供的VBO具有一样的顺序,呈现顺时针或逆时针。

若在模型设计时就将面元的序号按逆时针存储,那么当面元正面向视角时序号逆时针,而反面向视角时序号顺时针。

对于一个封闭物体,定义其面元法向向外和定义其正面逆时针同义,于是此时就可以通过面元顶点(当前应该处于rasterization步骤)排序情况判断是否需要光栅化这个面元。该步是自动进行的,能够节约一部分时间。

默认去除的面是后面glCullFace(GL_BACK),而正方向是逆时针glFrontFace(GL_CCW)

如果和前面的内容结合起来,可以发现:

  • 非封闭物体使用该功能可能导致在另一个方向不可见,如草丛纹理(贴图)就不能使用。

  • 具有透明像素的物体使用该功能将导致透明像素不能与后面的像素混合,因为后面没有光栅化。

(这部分内容相对独立就提一下)

新建缓冲区

framebuff可以认为是帧缓冲区,或者认为是一个包含了许多缓冲区的缓冲区组。(和之前的了解不一样了)

一个FB一定要包含一个colorbuffer,同时也可以包含depthbuffer、stencilbuffer以及其他自定义的buffer。

GLFW创建窗口会维护一个初始的帧缓冲区,相当于默认调用了glBindFrmebuffer(GL_FRAMEBUFFER, 0)。把它称为默认帧缓冲区,或者主窗口的帧缓冲区。

创建对象和以前相同:

unsigned int FBO;
glGenFramebuffer(1, &FBO);
glBindFramebuffer(GL_FRAMEBUFFER, FBO)
...
glDeleteFramebuffer(1, &FBO);

由于一个FB必须包含一个CB,且各缓冲区的尺寸相同才行,所以能使用glCheckFramebufferStatus(GL_FRAMEBUFFER)==GL_FRAMEBUFFER_COMPLETE判断是否可以使用。

配置纹理到缓冲区

使用glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0)能为帧缓冲区通过纹理配置其他类型的缓冲区,在这里是CB0,也可以认为该函数为空FB添加了一个CB,其内容为texture。最后的0是mipmap level,默认0。

创建固定大小的空纹理使用glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 800, 600, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL),各参数意义在前文,但是NULL表示没有数据。此时被连接到GL_TEXTURE_2D的纹理将被设置为指定大小但是全空。

glFramebufferTexture2D()也可以设置DB、SB、DSB,设置DSB使用的宏将是GL_DEPTH24_STENCIL8GL_UNSIGNED_INT_24_8等奇特类型。

renderbuffer对象

使用它的代码:

unsigned int RBO;
glGenRenderbuffers(1, &RBO);
glBindRenderbuffer(GL_RENDERBUFFER, RBO);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 800, 600);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH24_STENCIL_ATTACHMENT, GL_RENDERBUFFER, RBO);
glDeleteRenderbuffers(1, &RBO);

要理解它的作用,需要补充大量知识。

渲染通道的语言模型

一次完整的渲染(render)过程包含绑定FBO、绑定着色器、绑定纹理和绑定uniform、设置状态、发起绘制调用等过程后,得到渲染结果。把这一次完整过程称为一个通道(pass)。在renderloop中,一次循环可以看作是一次多通道渲染。

在使用渲染通道前,应该已经存在描述模型各部分(mesh)的位置数据、材质数据,某些情况下也需要对应的着色器的数据等。这些数据指导程序在绘制指定的mesh时,选择对应的着色器、渲染管线设置为对应状态、绑定对应的纹理(采样器)和uniform变量作为着色器参数、输出到对应的帧缓冲(FBO)内。

当已经使用这些数据完成了各部分之间的对应后,该通道的处理存储在FBO中。

而FBO下属缓冲区按内容分类可以分为颜色缓冲、深度缓冲、模板缓冲、自定义缓冲等,而按照类型分类可以分成texture类型的和renderbuffer类型的缓冲区,它们的区别能够看出renderbuffer的作用。

默认帧缓冲的颜色缓冲区之间输出到屏幕,而深度缓冲区、模板缓冲区不输出到屏幕,它的作用是进行一些测试。认为在默认渲染通道中,颜色缓冲区是渲染目标,其他两个缓冲区是辅助渲染目标生成。

在一个多通道渲染过程中,自定义的FBO,它的下属缓冲区是我们连接上的,取英文则为附件(attachment),所以一个通道的渲染结果就分成纹理附件和RB附件。

纹理附件能作为uniform sampler在下一个通道使用,而RB附件不能,它被设计为无法被采样。

因此RB附件通常被特异性的作为一个通道渲染过程中提供深度测试和模板测试功能的手段,它仅通过上面给出的语句被连接到帧缓冲,作为深度附件和模板附件,辅助渲染目标。

而纹理附件通常作为渲染目标存在,在下一个通道内传入作为参数。

但是在除了深度和模板测试外的自定义过程中,也有使用纹理附件的情况。由于一个通道不能同时读取和写入同一个纹理附件,要通过渲染通道实现纹理的自更新,即一定需要以使用的纹理作为渲染目标时,可以通过ping-pong缓冲的写法完成,即同时维护两个纹理附件,但是交替作为采样器和渲染目标。

在多通道渲染中,虽然颜色缓冲区可以有多个,但是只有一个缓冲区作为渲染目标,即只有一个纹理附件的数据在多通道中从头到尾流动。所以多通道渲染默认不分支。

离屏渲染

这是理解为什么需要通道概念和多通道渲染的重要语言模型,其字面含义就是渲染目标为纹理附件的渲染通道。

功能上可以认为就是多通道渲染的功能:视效后处理、反走样、阴影映射、UI/HUD合成等。

使用的方法是将上一步纹理附加到全窗/屏矩形上,于是就能光栅化后在片元着色器中进行像素级的处理。

一个容易疑惑的地方是如何在片元着色器中使用卷积核,因为它只处理一个片元。事实上这个问题是一个误解,一个片元着色器只能在FBO一个位置上产生渲染结果,但是它的数据来源并非只能来源于对应位置的片元;当使用texture(texture0, TexCoords)函数采样时,改变TexCoords就改变了数据来源。

texture(texture0, TexCoords+vec2(1,1)的渲染结果将会把整个图片平移。





comment 评论区

添加新评论





  • ©2025 bilibili.com

textsms
内容不能为空
account_circle
昵称不能为空
email
邮件地址格式错误
web
beach_access
验证码不能为空
keyboard发表评论


star_outline 咱快来抢个沙发吧!




©2025 Aquacolor

鄂ICP备2024059763号-1

鄂公网安备42011102005556号



Theme Romanticism2.1 by Akashi
Powered by Typecho