使用较少的调用切换着色器程序

Ste*_*nov 0 opengl performance

目前,每次我想切换着色器时,我都会调用此函数(简化):

void switchToShader(ShaderProgram* newProg, Mesh& mesh) {
    if(m_currentProg != nullptr) {
        m_currentProg->disableAttributeArray("aPos");
    }
    newProg->enableAttributeArray("aPos");
    mesh.vertexPosBuffer()->bind();
    glVertexAttribPointer(newProg->attributeLocation("aPos"), 2, GL_FLOAT, false, 0, 0);

    newProg->bind();

    mesh.indexBuffer()->bind();

    m_currentProg = newProg;
}
Run Code Online (Sandbox Code Playgroud)

尽管如此,这似乎是不必要的低效率.

请注意,此功能仅用于支持在具有相同属性数组集的程序之间切换.

理想情况下,我的代码看起来更像这样:

ShaderProgram::ShaderProgram() {
    // ...
    enableAttributeArray("aPos");
    glVertexAttribPointer(newProg->attributeLocation("aPos"), 2, GL_FLOAT, false, 0, 0);
}

void switchToShader(ShaderProgram* newProg, Mesh& mesh) {
    mesh.vertexPosBuffer()->bind();
    newProg->bind();
    mesh.indexBuffer()->bind();
}
Run Code Online (Sandbox Code Playgroud)

但由于显而易见的原因,这不起作用.

请注意,我的类ShaderProgram派生自Qt的QOpenGLShaderProgram.

任何提示如何使我的代码更有效?

我知道我可以使用glBindAttribLocation强制atder数组aPos,在着色器程序初始化时,使用例如位置1,对于我的所有着色器程序,这意味着我enableAttributeArray每帧只能做一次并且可以跳过disableAttributeArray.但这有点不优雅,因为它意味着编写一些额外的代码并通过我任意选择的attrib位置.

我目前正在调查VAO.

编辑:使用glBindAttribLocation和VAO后,我的问题解决了.我的代码现在看起来像这样:

void switchToShader(ShaderProgram* newProg, Mesh& mesh) {
    newProg->bind();
    mesh.vao()->bind();
    m_currentProg = newProg;
}
Run Code Online (Sandbox Code Playgroud)

我甚至可以在此功能之外将着色器程序和VAO彼此独立地绑定.

Nic*_*las 7

但这有点不优雅,因为它意味着要编写一些额外的代码

然后把它放在你的着色器中layout(location = #).那不是"不优雅"; 他说"把信息放在哪里".

并通过我任意选择的attrib位置.

然而,你没有"通过我的任意选择属性名称 "的问题.从代码的角度来看,"aPos"和1之间没有区别.您必须为VAO获取该属性的某种标识符.在这两种情况下,您都可以将其硬编码为特定值; 无论是字符串文字还是整数字面意思都没有.

只是如果使用整数,则在更改程序时不必不断重新创建VAO.

QT将VAO命令放入着色器对象的API是错误的,现在您可以看到确切的原因.程序不应负责启用哪些属性或来自哪些属性.

你知道如何解决你的问题.所以解决它.