OpenGL学习笔记(八)-面剔除-帧缓冲-立方体贴图

参考网址:LearnOpenGL 中文版

第四章 高级OpenGL

4.4 面剔除

4.4.1 基本概念

1、一个3D立方体,从任意方向最多能同时看到3个面,以某种方式丢弃这几个看不见的面,能省下超过50%的片段着色器执行数。

2、如何确定物体的某一个面看不见?一个闭合形状的每个面都有两侧,每一侧要么面向用户,要么背对用户。面剔除能够检查所有面向观察者的面,并渲染它们,而丢弃那些背向的面。但要告诉OpenGL哪些是正向面和背向面,这可通过分析顶点数据的环绕顺序完成。

4.4.2 环绕顺序

1、当定义一组三角形顶点时,会以顺时针或逆时针的环绕顺序来定义它们。
在这里插入图片描述
2、一般按照逆时针定义三角形顶点,通过三角形图元的环绕顺序可确定三角形是正向还是背向。观察者所面向的三角形顶点都是以逆时针环绕顺序所渲染的,而立方体另一面的三角形顶点则是顺时针的环绕顺序。
3、在顶点数据中,将两个三角形都以逆时针顺序定义(1,2,3)。从观察者当前视角使用1、2、3的顺序来绘制的话,背面的三角形将会是以顺时针顺序渲染的,就要被剔除。
在这里插入图片描述

4.4.3 代码

1、启用OpenGL的GL_CULL_FACE面剔除选项,面剔除只对像立方体这样的封闭形状有效。

glEnable(GL_CULL_FACE);

2、允许我们改变需要剔除的面的类型,可以剔除正向面。GL_BACK:只剔除背向面。GL_FRONT:只剔除正向面。GL_FRONT_AND_BACK:剔除正向面和背向面。

glCullFace(GL_FRONT);

3、允许将顺时针的面定义为正向面,默认值是逆时针GL_CCW,另一个选项是顺时针GL_CW

glFrontFace(GL_CCW);

4.5 帧缓冲

4.5.1 创建帧缓冲

1、帧缓冲包括颜色缓冲、深度缓冲和模板缓冲,它被储存在内存中。目前所做的操作都是在默认帧缓冲的渲染缓冲上进行的,OpenGL允许我们定义我们自己的帧缓冲,就能够有更多方式来渲染。

2、使用glGenFramebuffers创建一个帧缓冲对象(Framebuffer Object, FBO),将它绑定为激活的(Active)帧缓冲。之后所有的读取和写入帧缓冲将会影响当前绑定的帧缓冲,可以使用GL_READ_FRAMEBUFFERGL_DRAW_FRAMEBUFFER,将一个帧缓冲分别绑定到读取目标或写入目标。

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

3、渲染到一个不同的帧缓冲被叫做离屏渲染,渲染指令将不会对窗口的视觉输出有任何影响。要保证所有的渲染操作在主窗口中有视觉效果,需要再次激活默认帧缓冲,将它绑定到0。

glBindFramebuffer(GL_FRAMEBUFFER, 0);
4.5.2 帧缓冲附件

1、一个完整的帧缓冲需要:附加至少一个缓冲(颜色、深度或模板缓冲);至少有一个颜色附件(Attachment); 所有的附件都必须是完整的(保留了内存); 每个缓冲都应该有相同的样本数。

  • 因此需要创建一些附件,并将附件附加到帧缓冲上。附件是一个内存位置,它能够作为帧缓冲的一个缓冲,可以将它想象为一个图像。当创建一个附件的时候我们有两个选项:纹理或渲染缓冲对象。
  • 检查帧缓冲是否完整:
    glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE
    

2、纹理附件:当把一个纹理附加到帧缓冲的时候,所有的渲染指令将会写入到这个纹理中,就像一个普通的颜色/深度或模板缓冲一样。使用纹理的优点是,渲染操作的结果储存在纹理图像中,可以在着色器中使用。

  • 纹理附件的创建与普通纹理差不多:

    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);
    
  • 纹理对象维度设置为了屏幕大小,纹理的data参数为NULL,仅仅分配了内存而没有填充它。同时不用设置环绕方式或多级渐远纹理。

  • 将纹理附件附加到帧缓冲上,target:帧缓冲的目标;attachment:附件类型,当前附加颜色附件,最后的0意味着可以附加多个颜色附件;textarget:附加的纹理类型;texture:要纹理本身;level:多级渐远纹理的级别。

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
    
  • 除了颜色附件之外,还可以附加一个深度和模板缓冲纹理到帧缓冲对象中。将附件类型设置为GL_DEPTH_ATTACHMENTGL_STENCIL_ATTACHMENT,将注意纹理的格式和内部格式类型变为GL_DEPTH_COMPONENTGL_STENCIL_INDEX

  • 也可以将深度缓冲和模板缓冲附加为一个单独的纹理。纹理的每32位数值将包含24位的深度信息和8位的模板信息,使用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);
    

3、渲染缓冲对象附件:渲染缓冲对象是一个真正的缓冲,即一系列的字节、整数、像素等。它会将渲染数据储存为OpenGL原生的渲染格式,不会做任何针对纹理格式的转换。

  • 渲染缓冲对象通常都是只写的,所以你不能读取它们,只从当前绑定的帧缓冲中,而不是附件本身,使用glReadPixels来读取特定区域的像素。

  • 因为它的数据是原生的格式,当写入或者复制它的数据到其它缓冲中时是非常快的。在每个渲染迭代使用的glfwSwapBuffers,可以通过渲染缓冲对象实现:只需要写入一个渲染缓冲图像,并在最后交换到另外一个渲染缓冲就可以了。

  • 创建一个渲染缓冲对象的代码和帧缓冲的代码很类似:

    unsigned int rbo;
    glGenRenderbuffers(1, &rbo);
    glBindRenderbuffer(GL_RENDERBUFFER, rbo);
    
  • 由于渲染缓冲对象通常都是只写的,经常用于深度和模板附件,因为通常不需要从深度和模板缓冲中读取值,只关心深度和模板测试。通过glRenderbufferStorage函数创建一个深度和模板渲染缓冲对象,与创建纹理对象类似。

    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 800, 600);
    
  • 附加渲染缓冲对象:

    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
    
4.5.3 渲染到纹理

1、将会将场景渲染到一个附加到帧缓冲对象上的颜色纹理中,之后将在一个横跨整个屏幕的四边形上绘制这个纹理。这样视觉输出和没使用帧缓冲时是完全一样的,但这次是打印到了一个四边形上。

//创建一个帧缓冲对象
unsigned int framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// 生成纹理
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);
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);
// 作为一个颜色附件附加到当前绑定的帧缓冲对象
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texColorBuffer, 0);  

2、添加一个深度和模板附件到帧缓冲中,能够进行深度测试。由于只需采样颜色缓冲,因此可以为它们创建一个渲染缓冲对象

unsigned int rbo;
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo); 
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 800
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值