OpenGl,glUseProgram() 返回 GL_INVALID_VALUE 即使着色器的 ID 是正确的 [重复]

Posted

技术标签:

【中文标题】OpenGl,glUseProgram() 返回 GL_INVALID_VALUE 即使着色器的 ID 是正确的 [重复]【英文标题】:OpenGl, glUseProgram() returns GL_INVALID_VALUE even the shader's ID is right [duplicate] 【发布时间】:2019-10-15 15:53:38 【问题描述】:

我正在尝试使用 ASSIMP 库在 OpenGl/GLEW/GLFW 中创建模型加载器。我的问题是我在主循环 第二次 迭代中 glUseProgram() 收到 GL_INVALID_VALUE 错误 (我已经设置了宏,名为 GLCall 这会破坏调试 glGetError 返回一些东西)

这里有一些代码使上下文更清晰:

绘制模型的主循环中的代码,第一次运行良好,model.Draw() 第二次出现错误

model_shader.Bind();

glm::mat4 View = inputCompute(deltaTime, window);
glm::mat4 Projection = glm::perspective(glm::radians(45.0f), (float)CONFIG::WINDOW_WIDTH / (float)CONFIG::WINDOW_HEIGHT, 0.1f, 100.0f);
glm::mat4 Model = glm::translate(glm::mat4(1.0f), lampPosition) * glm::translate(glm::mat4(1.0f), transVectorControl(deltaTime, window)) * glm::scale(glm::mat4(1.0f), glm::vec3(0.5f, 0.5f, 0.5f));
glm::mat4 mvp = Projection * View * Model;
model_shader.SetUniformMat4f("u_MVP", mvp);
model.Draw(model_shader);
model_shader.Unbind(); 

所以我认为函数 model.Draw() 必须对着色器的 id 做一些事情,但在这里它实际上只读取着色器的 id。

这是model.Draw() 函数(它是Mesh 类的成员):

void Mesh::Draw(Shader shader)

// bind appropriate textures
    unsigned int diffuseNr = 1;
    unsigned int specularNr = 1;
    unsigned int normalNr = 1;
    unsigned int heightNr = 1;
    for (unsigned int i = 0; i < textures.size(); i++)
    
        GLCall(glActiveTexture(GL_TEXTURE0 + i)); // active proper texture unit before binding
        // retrieve texture number (the N in diffuse_textureN)
        std::string number;
        std::string name = textures[i].type;
        if (name == "texture_diffuse")
            number = std::to_string(diffuseNr++);
        else if (name == "texture_specular")
            number = std::to_string(specularNr++); // transfer unsigned int to stream
        else if (name == "texture_normal")
            number = std::to_string(normalNr++); // transfer unsigned int to stream
        else if (name == "texture_height")
            number = std::to_string(heightNr++); // transfer unsigned int to stream

                                                 // now set the sampler to the correct texture unit
        GLCall(glUniform1i(glGetUniformLocation(shader.getID(), (name + number).c_str()), i));
        // and finally bind the texture
        GLCall(glBindTexture(GL_TEXTURE_2D, textures[i].id));
    

    // draw mesh
    GLCall(glBindVertexArray(VAO));
    GLCall(glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0));
    GLCall(glBindVertexArray(0));

    // always good practice to set everything back to defaults once configured.
    GLCall(glActiveTexture(GL_TEXTURE0));

如您所见,着色器的 id 只是被读取,而不是被写入。 我实际上检查了第二次 ID 与执行 model.Draw() 之前相同。该模型实际上是在主循环的第二次迭代之前绘制的。 我尝试从glUseProgram() 中删除错误检查,但是glUniform() 给了我关于没有绑定着色器的错误。

【问题讨论】:

我敢打赌,着色器程序对象在Shader类的析构函数中被销毁。在Draw 中使用引用参数:void Mesh::Draw(Shader &amp;shader) 并阅读OpenGL object in C++ RAII class no longer works @Rabbid76 我想过,但是着色器在int main() 中被实例化,所以它在程序退出之前是“活动的”。我按照你的建议做了,还是不行 @Rabbid76 好吧,请原谅我的收入,正如我所说,我仍然是初学者,通过参考并没有做任何工作。 @Rabbid76 但这一切都无关紧要,因为我在 int main()mes.Draw() 中绑定着色​​器只将着色器作为参数来使用其 Id @Rabbid76 我必须承认你是对的,我忘记了我通过另一个类调用了Mesh.Draw(),我不得不将所有参数切换为通过引用传递。请原谅我脾气这么轻。感谢您帮助我解决问题! 【参考方案1】:

解决这个问题的方法非常简单,我只是传递了 ID 而不是整个着色器,它工作得很好。通过引用传递着色器也解决了这个问题。

【讨论】:

以上是关于OpenGl,glUseProgram() 返回 GL_INVALID_VALUE 即使着色器的 ID 是正确的 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

C++/OpenGL - 如何获得从类继承的正确变量

使用 GLM 在 OpenGL 中绘制 2 个立方体

glUseProgram 会改变 VAO 和/或 VBO 状态吗?

Qt FrameBuffer 对象甚至不渲染顶点

OpenGL 项目返回未定义的引用

C++ OpenGL,绘制形状返回错误