优化OpenGL渲染

3
我在使用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的影响不大。
在场景中有两个点光源,每次绘制此模型时每个通道的FPS损失约为10 FPS(从23到55)。也就是说,我在哪里绘制这个模型没有任何区别:在深度图中还是在“颜色纹理”中。损失量大致相同。我使用以下参数加载模型: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)

以下是场景本身: 场景

编辑vertex_shader.glsl, fragment_shader.glsl

非常抱歉片段着色器很难阅读,我还没有完全完成它的工作

我的GPU是NVGF 920mx

编辑:这里是capture来自renderdoc


3
只测量以毫秒为单位的问题度量。发布您的着色器代码,包括顶点和片段着色器。如果您的电脑配置过低,GPU规格可能有帮助 - 数字会更有意义 ;-) - Andreas
你的棋子模型中有多少个网格? - Fibbs
@Fibbles,4个网格 - congard
1
那个着色器里面确实有很多东西,而且你的GPU是2015年的低端设备。for 20 do texture lookup 可能是罪魁祸首,但需要进行测量才能确定。注意:textureCubeShadow采样器专门用于阴影映射,所以我相信你应该使用它。不过我个人不太熟悉它。 - Andreas
@Andreas,当禁用pcf时,增益微不足道。当在片段着色器中禁用阴影映射时-同样的情况。我认为你是对的,整个问题都出在我的显卡上... - congard
显示剩余2条评论
1个回答

3
最初的回答:
我知道这个回答并不是你问题的直接答案,根据你提供的细节,你可能已经知道大部分内容,但我仍然会在这里放置它,以防其他人找到你的问题并寻找可能的解决方案。
在大多数这样的情况下,很难给出确切的答案,但可以提供一些通用的想法来寻找解决方案。
你知道,使用着色器总是创造出某种真实的幻觉。如果你追求准确性,你会转向光线追踪和其他更逼真的渲染图像的方法。只要你在实时渲染和使用着色器,就是为了欺骗眼睛使场景看起来逼真,即使它并不是真实的。这就是为什么你应该寻找便宜的技巧让你的场景看起来比它实际上更逼真。
提高性能最有效的方法就是画得更少。如果可能的话,尝试使用法线贴图将高面数网格烘焙成低面数网格。这是在几乎所有旨在实现实时性能(即更高的FPS评级)的项目中非常普遍的方法。通常而言,如果你追求高细节和准确性,你将需要大量的处理能力,但是如果你可以做出一些妥协来保留某种感觉的细节,那么你可以提高性能。使用50 FPS(即每秒25百万个顶点)绘制像50万个顶点这样的模型可能对你的GPU来说太过于繁重。
同样适用于你的着色器。你确定你正在使用所有已配置的着色器吗?如果你有三个灯光,你可以极大地提高性能,如果你的着色器只能管理三个灯光。请记住,灯光的数量是特定于片段的常量(*):你不需要考虑场景有多少灯光,而是取决于每个片段像素考虑了多少灯光(也就是说,灯光在片段着色器中进行处理)。
(*) 好吧,它可能是一个模型特定的常数,因为所有事情都取决于每个片段使用多少灯光,但是将灯光按片段发送可能很困难 - 将灯光按模型发送更容易用于渲染。
作为一般规则,将计算移动到顶点着色器通常总是更好的,让其预先计算片段着色器的值。例如,你可以考虑将片段着色器切换为使用相机空间,在这种情况下,你可以在顶点着色器中完全进行TBN计算。
问题的评论区已经有一些不错的想法,你可以考虑使用以获得更好的性能。
如果你看到内存瓶颈限制了你的性能,那么有一篇旧但仍然不错的文章涉及到这个问题:https://www.khronos.org/opengl/wiki/Vertex_Specification_Best_Practices 在这种情况下,你可以做的第一件事是压缩顶点属性。例如,你可以将TBN矩阵转换为GL_INT_2_10_10_10类型(如果可用),这将把矩阵从9个浮点数压缩为3个浮点数。虽然会失去一些精度,但大多数情况下不会产生任何可见影响。如果精度足够,你甚至可以将TBN作为四元数发送,这将把9个浮点数压缩为只有一个浮点数。
此外,你可以尝试交错缓冲区(从结构体数组形成VBO)。无法确定它是否有任何效果,即使有,它也非常依赖于GPU。对于某些GPU,它可能会提高顶点缓存的性能。
但无论如何,如果你需要像这样的细节,最好的性能效益通常很小(至少在考虑你正在使用的相对简单的顶点属性方案时),并且在某个时候,你只需接受你的GPU不能在你想要的时间内处理你拥有的数据的硬件相关限制。你可以获得的最大性能有限制。
我知道这并没有对你有太大帮助,但我仍然希望你能从中得到一些可能解决你问题的思路。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接