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的纹理,进行绘制。