在LearnOpenGL网站学习,记录一下学习笔记
面剔除
注意: 面剔除只应用于封闭形状
OpenGL能够检查所有面向(Front Facing)观察者的面,并渲染它们,而丢弃那些背向(Back Facing)的面,节省我们很多的片段着色器调用(它们的开销很大!)。但我们仍要告诉OpenGL哪些面是正向面(Front Face),哪些面是背向面(Back Face)。OpenGL使用了一个很聪明的技巧,分析顶点数据的环绕顺序(Winding Order)。
环绕顺序
渲染三角形时,可以定义三角形三个顶点的旋转顺序,是为逆时针或者顺时针,OpenGL默认定义逆时针为正面(面向摄像机的面)
对于右侧的平面,是逆时针旋转,所以我们现在看到面(立方体的外面)。对于左侧的平面,从外面看也是逆时针的方向,即正面,所以也保留。
面剔除
OpenGL执行面剔除的步骤以及相关函数属性:
1.启用OpenGL的GL_CULL_FACE选项:默认所有的背面都会被剔除。
glEnable(GL_CULL_FACE);
2.也可以更改剔除面的类型:
3.还可以重新定义正向面。
帧缓冲
个人理解: 帧缓冲的作用,只需要读取一次数据,比如说贴图、顶点、法线信息,然后将数据存储在自定义的帧缓冲当中,节省了CPU效能。
到目前为止,我们已经使用了很多屏幕缓冲了:用于写入颜色值的颜色缓冲、用于写入深度信息的深度缓冲和允许我们根据一些条件丢弃特定片段的模板缓冲。这些缓冲结合起来叫做帧缓冲(Framebuffer),它被储存在内存中。
我们能够定义我们自己的颜色缓冲,甚至是深度缓冲和模板缓冲。
OpenGL缓冲绑定的附件种类
OpenGL创建的缓冲种类有两种:纹理和渲染缓冲对象。
纹理附件: 可以读取可以写入,可以将所有的数据写入其中,就像是一个普通的颜色/深度或者模板缓冲对象一样。
渲染缓冲对象附件: 通常是只可写的。
渲染缓冲对象也可以写入所有的数据,但是熏染缓冲对象会将数据储存为OpenGL原生的渲染格式,所以数据写入或者复制它的数据到其他缓冲中时是非常快的。所以在渲染最后一步,交换缓冲对象时,用渲染缓冲对象就会非常快。
渲染缓冲对象附件然通常是只可写的,所以不能读取他们(比如使用纹理访问),但是可以使用glReadPixels来读取它,这会从帧缓冲读取特定区域的像素,而不是附件本身。
由于渲染缓冲对象通常都是只写的,它们会经常用于深度和模板附件,因为大部分时间我们都不需要从深度和模板缓冲中读取值,只关心深度和模板测试。我们需要深度和模板值用于测试,但不需要对它们进行采样,所以渲染缓冲对象非常适合它们。当我们不需要从这些缓冲中采样的时候,通常都会选择渲染缓冲对象,因为它会更优化一点。
帧缓冲的使用
帧缓冲的使用分为以下几个步骤:
1、创建一个帧缓冲
2、创建一个颜色附件
3、 所有的附件都是完整的
之后所有的渲染操作将会渲染到当前绑定帧缓冲的附件中。由于我们的帧缓冲不是默认帧缓冲,渲染指令将不会对窗口的视觉输出有任何影响。出于这个原因,渲染到一个不同的帧缓冲被叫做离屏渲染(Off-screen Rendering)。要保证所有的渲染操作在主窗口中有视觉效果,我们需要再次激活默认帧缓冲,将它绑定到0。
接下来粘贴上述过程的代码:
创建帧缓冲对象
绑定帧缓冲对象
glBindFramebuffer(GL_FRAMEBUFFER, 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);
- 创建并绑定渲染缓冲对象附件
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);
所有的附件都是完整的
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
最后激活默认值缓冲
glBindFramebuffer(GL_FRAMEBUFFER, 0);
后期处理
由于整个场景都渲染输出到一个纹理上,所有我们可以对纹理的数据进行处理,整体得到一些不同的效果
反相
在片段着色器中对每个顶点的颜色进行反相(Inversion):用1.0减去每个颜色的值,对它进行反相
void main(){
FragColor = vec4(vec3(1.0-texture(screenTexture,TexCoords),1.0));
}
处理效果:
灰度
让整个图像灰度化的方法之一:取所有颜色值,求它们的平均值。
对人眼来说,对不同的光的敏感度不同,所以对不同的颜色添加权重
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);
}
处理效果:
核效果
所谓的核是指卷积核,核处理就是对颜色值于卷积核进行卷积,使用不同的卷积核会有不同的效果。
锐化核
图像的锐化效果是,扩大像素点与周围像素的颜色值。
模糊
创建模糊效果的核:
边缘检测
边缘检测与锐化的核很相似:
边缘检测的核高亮了所有的边缘,暗化了其他部分