-1

I am trying to create model loader in OpenGl/GLEW/GLFW using ASSIMP library. My problem is that I get an GL_INVALID_VALUE error on glUseProgram() on second iteration of the main loop (I have set up the macro, named GLCall that breaks the debugging whenever glGetError returs something).

Here's some code the make context clearer:

Code in main loop that draws a model, runs well first time, after model.Draw() second time I get an error

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(); 

So I figured the function model.Draw() must do something to the shader's id but here it is and it actually only reads the shader's id.

Here's model.Draw() function (it is a member of the Mesh class):

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));
}

shader.getID() simply returns ID that is held in Shader class a private member.

As You can see shader's id is only being read, but not written. I actually checked and second time ID remains the same as before model.Draw() was executed. The model actually gets drawn right before second iteration of the main loop. I tried removing error checking from glUseProgram() but then the glUniform() gives me error about no shader being bind.

Szahu
  • 43
  • 5
  • I bet that the shader program object is destroyed in the destructor of the class `Shader`. Use a reference parameter in `Draw`: `void Mesh::Draw(Shader &shader)` and read [OpenGL object in C++ RAII class no longer works](https://stackoverflow.com/questions/46839586/opengl-object-in-c-raii-class-no-longer-works) – Rabbid76 Oct 15 '19 at 16:23
  • @Rabbid76 I thought about it, but shader is instantieted in `int main()` so it is 'alive' until program exits. I did what you suggested and it still doesnt work – Szahu Oct 15 '19 at 16:29
  • @Rabbid76 well Forgive my incomeptence sicne I still am a beginner, as I said, passing it by refrence didn't do a job. – Szahu Oct 15 '19 at 16:33
  • @Rabbid76 but its all inrelevant since I bind shader in `int main()` and `mes.Draw()` only takes shader as a parameter to use its Id – Szahu Oct 15 '19 at 16:34
  • It is completely irrelevant where the object is instanced, if it is passed by value then a copy of the object is constructed and destructed. – Rabbid76 Oct 15 '19 at 16:36
  • @Rabbid76, well So I fixed it by just passing the ID and not the whole shader, guess I shouldnt have blindly follow tutorials. Thanks for help! – Szahu Oct 15 '19 at 16:37
  • 1
    @Rabbid76 I must admit you being right, I forgot that I call the `Mesh.Draw()` through another class and I had to switch all parameters to passing by refrence. Please forgive me being so light tempered. Thanks for helping me resolving the issue! – Szahu Oct 15 '19 at 16:41

1 Answers1

0

A fix to this problem turned out quite simple, I just passed the ID instead of whole shader and it worked just fine. Also passing Shader by refrence resolved the issue.

Szahu
  • 43
  • 5