opengl 保留上一帧_细说OpenGL----------中卷

9e7965d0ca1d970ef2e335f66f002cf7.png

本篇将紧跟上卷的脚步,继续讲解OpenGL中的一些高级概念,由于篇幅实在过于庞大,原本打算直接一卷写完,发现内容还是太多了,所以插入一个中卷(∩_∩)O),下卷放在后边再写,下卷主要涉及到一些高级光照部分如切线空间由来,法线贴图,视差贴图,阴影算法CSM,SSAO,间接光IBL,PBR等等,主要集中在GLSL的算法上。 而本篇则是针对OpenGL中的一些高级概念和用法做一些介绍,主要针对OpenGL的API上而言。 废话不多说,直接开始正文。 由于编写仓促,如有任何问题,欢迎指出。

19,帧缓冲对象FrameBufferObject

FBO概念:在OpenGL中,渲染管线中的顶点,纹理经过一系列过程之后,最终显示在2D屏幕设备上,渲染管线的最终目的地就是帧缓冲区。帧缓冲包括OpenGL使用的颜色缓冲区(color buffer),深度缓冲区(depth buffer),模板缓冲区(stencil buffer),它被储存在内中中。我们前面一直在使用的默认缓冲区由窗口系统GLFW为我们创建称为窗口系统提供的缓冲区,除此之外,OpenGL还允许我们手动创建自己的缓冲区,并将渲染结果重定向到这个缓冲区,称之为应用程序缓冲区。

创建FBO:和其他对象的创建方式一样,先创建帧缓冲对象,再将它绑定为激活的(Active)帧缓冲,做一些操作,之后解绑帧缓冲

unsigned int fbo;
glGenFramebuffers(1, &fbo);
//还有用于只读GL_READ_FRAMEBUFFER和只写的GL_DRAW_FRAMEBUFFER的方式
glBindFramebuffer(GL_FRAMEBUFFER, fbo);

一个完整的帧缓冲炫耀包含以下条件:

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

全部操作完以后,可以使用glCheckFramebufferStatus来检测

if(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)

纹理附件:当把一个纹理附加到帧缓冲的时候,所有的渲染命令将会写入到这个纹理,就想它是一个普通的颜色/深度或模板缓冲一样。使用纹理的优点是,所有操作的结果将会存储在一个纹理图像中,我们之后可以很方便地使用它。 创建方式和普通纹理基本相同:

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

渲染缓冲对象:和纹理图像一样,渲染缓冲对象是一个真正的缓冲,即一系列的字节,整数,像素等。渲染缓冲对象附加的好处是,它会将数据缓存为OpenGL原生的数据格式,它是为离屏渲染到帧缓冲优化过的。因为它的数据已经是原生的格式了,当写入或复制它的数据到其他缓冲区时是非常快的。所以交换缓冲这样的操作在使用渲染缓冲对象时非常快。我们在每个渲染迭代后使用的glfwSwapBuffers也可以通过渲染缓冲对象实现:只需要写入一个渲染缓冲图像,并在最后交换到另外一个渲染缓冲就可以了。渲染缓冲对象对这种操作非常完美.

20,立方体贴图Cubemap

基础概念:一种将多个纹理组合起来映射到纹理上的纹理类型。其实就是一个包含了6个2D纹理的图像,每个2D纹理都组成了立方体的一个面;立方体贴图有一个非常有用的特性,它可以通过一个方向向量来进行索引/采样,如下所示使用橘黄色的方向向量从立方体贴图上采样

957822d0c2ba7c5e4064086bb8ff50cb.png

注:方向向量的大小并不重要,只要提供了方向,OpenGL就会获取方向向量(最终)所击中的向量,并返回对应的采样纹理值。

创建立方体贴图:基本创建方式如下:

unsigned int textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);

因为立方体贴图包含6个纹理,每个面1个,需要调用glTexImage2D函数6次,纹理目标(target)设置为立方体贴图的一个特定的面,而每个target正好是递增顺序

95c52ed8c1b2a63b6ea919dd09c9f685.png

纹理设置方式也和普通2D有所不同:

glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

shader中采样方式改变:

in vec3 textureDir; // 代表3D纹理坐标的方向向量
uniform samplerCube cubemap; // 立方体贴图的纹理采样器

void main()
{             
    FragColor = texture(cubemap, textureDir);
}

天空盒:游戏中的天空盒可以看作是一个包含了整个场景的大立方体,它包含周围环境的6个图像。

c19d7a4d7a5ed26f7497f25818ca7a03.png

如果将上图折成1个立方体,就会得到一个完全贴图的立方体。

加载天空盒:和之前的2D纹理加载类似,不过需要重复6次,代表立方体贴图的不同面。

优化方式显示天空盒:欺骗深度缓冲,让深度缓冲认为天空盒有着最大深度1.0,只要前面有一个物体,深度测试就会失败。透视除法是在顶点着色器中执行的,执行完后gl_Position的xyz坐标除以w分量,除完结果以后z分量等于顶点的深度值。利用这些信息,将输出的z分量直接设置为w分量,这样透视除法过后将永远等于1.0(z/w=1.0)

反射:表现为反射周围的环境,即根据观察者的视角,物体的颜色或多或少等于它的环境。例如最常见的镜子,会根据视角不同反射环境信息不同。

74320004898f814e0288800a848dc235.png

片段shader代码

#version 330 core
out vec4 FragColor;

in vec3 Normal;
in vec3 Position;

uniform vec3 cameraPos;
uniform
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值