QT+OpenGL实例化和抗锯齿
本篇完整工程见gitee:QtOpenGL 对应点的tag,由turbolove提供技术支持,您可以关注博主或者私信博主
实例化
如果我们需要渲染大量物体时, 代码看起来会像这样:
for(int i = 0; i < amount; i++)
{
DoSomeThing()l
glDrawArrays(GL_TRIANGLES, 0, amount_of_veritices);
}
- OpenGL在绘制顶点数据之前需要告诉GPU该从哪个缓冲读取数据,从哪里寻找顶点属性
- 这些都是在相对缓慢的CPU to GPU总线上进行的
- 所以,渲染非常快,命令GPU去渲染却未必
如果将数据一次性发送给GPU,然后使用一个绘制函数让OpenGL利用这些数据绘制多个物体,就会方便了。这就是实例化(Instancing)。
代码:
顶点着色器
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aOffset;
uniform vec2 offsets[100];
out vec3 Color;
void main() {
Color=aNormal;
gl_Position = vec4(aPos, 1.0) + vec4(aOffset, 0.0, 0.0);
}
片段着色器
#version 330 core
out vec4 FragColor;
in vec3 Color;
void main() {
FragColor = vec4(Color, 1.0);
}
主要代码:mesh.cpp
unsigned int instanceVBO;
gl_fn_->glGenBuffers(1, &instanceVBO);
gl_fn_->glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
gl_fn_->glBufferData(GL_ARRAY_BUFFER, sizeof(QVector2D) * 100, &translations[0], GL_STATIC_DRAW);
gl_fn_->glBindBuffer(GL_ARRAY_BUFFER, 0);
......
gl_fn_->glEnableVertexAttribArray(2);
gl_fn_->glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
gl_fn_->glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
gl_fn_->glBindBuffer(GL_ARRAY_BUFFER, 0);
gl_fn_->glVertexAttribDivisor(2, 1);
glVertexAttribDivisor函数告诉了OpenGL该什么时候更新顶点属性的内容到新一组数据:
- 它的第一个参数时需要的顶点属性
- 第二个参数时属性除数
- 0默认值,告诉opengl在定点着色器的每次迭代时更新一次属性
- 1:告诉OpenGL在渲染一个新实例的时候更新一次属性
- 2:告诉OpenGL在渲染的每两个实例时候更新一次属性
- 以此类推
抗锯齿
-
超采样抗锯齿:使用比正常分辨率更高的分辨率,即超采样来渲染场景,当图像输出在帧缓冲中更新时,分辨率会被下采样到正常的分辨率。这些额外的分辨率被用来放置锯齿边缘的产生
-
多重采样:每个像素中心包含一个采样点,它会被用来决定这个三角形是否遮盖了某个像素
多重采样所做的是将一个采样点编程多个采样点
采样点的数量可以是任意的,更多的采样点能带来更精确的遮盖率
QSurfaceFormat format;
format.setSamples(4);
setFormat(format);
glEnable(GL_MULTISAMPLE);
帧缓冲离屏MSAA
如果想要使用自己的帧缓冲进行离屏渲染,那么需要手动生成多重采样缓冲
将纹理渲染到multiSamples帧缓冲 --》将multiSamples帧缓冲中的纹理赋值给另外一个自定义的帧缓冲–》使用另外一个自定帧缓冲中的纹理附件作为mesh的纹理,进行绘制。