C++ OpenGL渲染的优化

C++ OpenGL渲染的优化,c++,opengl,optimization,C++,Opengl,Optimization,目前,我的场景由模型组成。模型由网格组成。每个网格都有自己的缓冲区,其中有8个顶点、法线、纹理坐标、切线、双切线和骨骼权重。我按如下方式渲染每个帧: void drawModel(Model &model) { ... for (size_t i = 0; i < model.shape->meshes.size(); i++) { ... pointer(cs.inPosition, 3, model.shape->m

目前,我的场景由模型组成。模型由网格组成。每个网格都有自己的缓冲区,其中有8个顶点、法线、纹理坐标、切线、双切线和骨骼权重。我按如下方式渲染每个帧:

void drawModel(Model &model) {
    ...
    for (size_t i = 0; i < model.shape->meshes.size(); i++) {
        ...

        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());
        ...
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model.shape->meshes[i].getIndicesBuffer());
        glDrawElements(GL_TRIANGLES, model.shape->meshes[i].indices.size(), GL_UNSIGNED_INT, nullptr);
    }
}
我也只在整个场景中使用一个VAO


我如何优化这段代码?也许我应该只为模型创建缓冲区,而不是为每个网格创建缓冲区?也许值得为每个型号分配一个单独的VAO??“我的场景”由相当多的顶点(约500k)组成,并显示相当低的FPS(约35)。

在启动和初始化期间创建VAO,而不是在渲染循环期间。正如@Ripi2所说,更改它会导致上下文滚动

VAO将保持状态,包括引用的缓冲区,但不包括缓冲区的数据,因为这些数据仍然存储在VBO和所有顶点属性数据中。使用VAO的全部目的是避免一直重置这些内容。创建一个逐顶点缓冲区或一个逐模型缓冲区,将其存储在模型或形状类中。渲染时,只需在glDraw*之前绑定并解除绑定即可

请注意缓冲区中的字节对齐。最好不要让单个值跨越对齐边界,因为这样会增加着色器中的提取时间,而且缓存并不友好。对于每个顶点组件,使用隔行缓冲区而不是单独的缓冲区可能会更容易,而不会牺牲缓冲区中的太多空间。但是,为每个属性使用单独的缓冲区是一种常见做法——例如,Unity使用这种方法——因此这可能没有帮助

对于复杂场景,您至少还需要实现平截头体剔除。遮挡剔除和其他半高级功能也将有助于减少渲染时间。在绘制之前将模型从前到后排序将减少过度绘制,因为不会为被遮挡的片段调用片段着色器

如果有许多共享材质的小模型,请考虑在单个绘制调用中绘制它们。如果有很多相同的模型,请考虑使用例程绘制。
另外,不要羞于添加一些计时数据,并使用您最喜欢的分析工具来识别性能瓶颈

每个VAO只能使用一次GlvertexAttribute指针。与任何其他上下文状态一样,更改它是昂贵的。不幸的是,这个问题太广泛了。但有一些提示:根据您拥有的网格数量,您可能需要将其中一些网格批处理在一起,然后立即渲染它们。减少draw调用的数量可能会有所帮助。而且,每个网格有8个缓冲区的声音非常好。为什么不将一个网格的所有数据打包到一个缓冲区中,或者更好,打包所有网格的数据?
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
    );
}