优化OpenGL渲染

时间:2019-05-07 13:18:11

标签: c++ opengl assimp

使用Assimp渲染到OpenGL时,我遇到了性能不佳的问题。场景中有367727个三角形。同时298084是国际象棋的模型。我认为问题不在于着色器,因为:

128x128窗口:44(43.7657)FPS,22.849毫秒

256x256窗口:42(40.9563)FPS,24.4162毫秒

512x512窗口:35(34.8007)FPS,28.7351毫秒

1024x1024窗口:22(21.084)FPS,47.4293毫秒

但是,如果我不下棋,则在窗口1366x763:55(54.8424)FPS,18.2341毫秒

此外,更改阴影贴图的分辨率不会严重影响FPS。

场景中有2个点光源,当为每个通道绘制10 FPS(从23到55)时,此模型会损失FPS。即,绘制此模型的位置没有区别:在深度图中还是在“颜色纹理”中。损失〜是相同的。我使用以下参数加载模型:aiProcess_Triangulate | aiProcess_CalcTangentSpace | aiProcess_JoinIdenticalVertices

并渲染如下:

inline void pointer(GLint location, int count, GLuint buffer) {
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    glVertexAttribPointer(
        location, // attribute location
        count,    // count (1, 2, 3 or 4)
        GL_FLOAT, // type
        GL_FALSE, // is normalized?
        0,        // step
        nullptr   // offset
    );
}

inline void pointerui(GLint location, int count, GLuint buffer) {
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    glVertexAttribIPointer(
        location, // attribute location
        count,    // count (1, 2, 3 or 4)
        GL_UNSIGNED_INT, // type
        0,        // step
        nullptr   // offset
    );
}
...
pointer(cs.inPosition, 3, model.shape->meshes[i].getVerticesBuffer());
pointer(cs.inNormal, 3, model.shape->meshes[i].getNormalsBuffer());
pointer(cs.inTangent, 3, model.shape->meshes[i].getTangentsBuffer());
pointer(cs.inBitangent, 3, model.shape->meshes[i].getBitangentsBuffer());
pointer(cs.inTexCoord, 2, model.shape->meshes[i].getTexCoordsBuffer());

if (model.shape->bonesPerVertex != 0) {
    pointer(cs.inBoneWeights, 4, model.shape->meshes[i].getBoneWeightsBuffer());
    pointerui(cs.inBoneIds, 4, model.shape->meshes[i].getBoneIdsBuffer());
}

modelMatrix = &model.transformation;
updateMatrices();

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model.shape->meshes[i].getIndicesBuffer());
glDrawElements(GL_TRIANGLES, model.shape->meshes[i].indices.size(), GL_UNSIGNED_INT, nullptr)

这是场景本身: scene

编辑vertex_shader.glslfragment_shader.glsl

很抱歉,片段着色器难以阅读,我尚未完全完成工作

我的GPU是NVGF 920mx

编辑:这里是capture,来自renderdoc

1 个答案:

答案 0 :(得分:1)

我知道此答案不是您问题的直接答案,根据您提供的详细信息,您可能至少已经知道其中大部分内容,但无论如何我都会将其放在此处,以防其他人找到您的问题并且寻找可能的解决方案。

在大多数情况下,很难给出确切的答案,但是需要一些一般的想法来寻找解决方案。

您知道,无论如何,使用着色器都会对真实事物产生一种幻觉。如果您追求准确性,那么无论如何您都会将目光投向光线追踪和其他更逼真的图像渲染方法。只要您使用着色器进行实时渲染,就可以欺骗眼睛以使场景看起来逼真,即使事实并非如此。这就是为什么您应该寻找便宜的把戏,以使场景看起来比实际更真实。


提高性能的最有效方法就是少花钱。如果可以,请尝试使用法线贴图将高多边形网格烘焙为低多边形网格。在几乎所有旨在提高实时性能的项目中,这都是非常普遍的方式,即更高的FPS等级。通常,如果您追求高细节和准确性,则将需要大量处理能力,但是如果您可以做出一些新颖的折衷以保留细节感觉,则可以提高性能。以50 FPS绘制大约一百万个顶点(即每秒2500万个顶点)可能对您的GPU来说太高了。

您的着色器也是如此。您确定使用配置了着色器的所有光源吗?如果您有如果您的着色器只能管理三盏灯,则可以大大提高三盏灯的性能。请记住,灯光的数量是特定于片段的常数(*):您无需考虑场景中有多少灯光,这完全取决于每个片段像素要考虑多少灯光(即,灯光在片段着色器中处理。

(*)嗯,这可能是特定于模型的常数,因为即使重要的是每个片段使用多少灯,每个片段可能也很难发送灯光-为每个模型发送灯光更容易渲染。

作为一般规则,将计算移至顶点着色器总是很有利的,让它为片段着色器预先计算值。例如,您可以考虑将片段着色器切换为使用相机空间,在这种情况下,您可以完全在顶点着色器中进行TBN计算。

问题的注释字段中已经有一些不错的主意,您可以考虑使用它们以获得更好的性能。


如果您发现这是限制性能的内存瓶颈,则有一篇关于该问题的老文章但仍然不错:https://www.khronos.org/opengl/wiki/Vertex_Specification_Best_Practices

在这种情况下,您可以做的是首先压缩顶点属性。例如,您可以将TBN矩阵很好地转换为GL_INT_2_10_10_10 -type(如果可用),这会将矩阵从9 x float压缩到3 x float。它会降低精度,但大多数情况下不会引起任何可见效果。您甚至可以走得更远,以四元数的形式发送TBN,如果精度足够,它将把9个浮点数压缩为一个浮点数。

此外,您可以尝试交错的缓冲区(由结构数组形成VBO)。不确定它是否有效果,即使有效果,也与GPU非常相关。对于某些GPU,它可能会改善顶点缓存的性能。

但是无论如何,如果您需要细致入微,那么最好的性能好处通常是很小的(至少在考虑使用的顶点属性方案简单的情况下),有时您只需要接受您的GPU无法在您想要的时间内处理您拥有的数据。硬件相关的限制限制了您可以获得的最高性能。

我知道这对您没有多大帮助,但是我仍然希望您能从中找到一些解决问题的办法。