Search code examples
c++openglsdlglad

OpenGL changing uniform changes previous draw


I have this sample code

// EBO is just a rectangle
// copypasted from learnopengl
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

glUseProgram(shaderId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);

glUniform1f(glGetUniformLocation(shaderId, shiftName), 0); //shiftName is string "shift"
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

glUniform1f(glGetUniformLocation(shaderId, shiftName), 0.5);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

glFlush();
SDL_GL_SwapWindow(window);

Shaders that I have:
Vertex:

#version 330 core
layout (location = 0) in vec3 pos;

out vec4 vertexColor;
uniform float shift = 0;

void main()
{
    gl_Position = vec4(pos.x, pos.y - shift, pos.z, 1.0);
    vertexColor = vec4(0, shift, 0, 1.0);
}

Fragment:

#version 330 core
out vec4 FragColor;

in vec4 vertexColor;

void main()
{
    FragColor = vertexColor;
}

In my understanding, I should get two rectangles, one under another, with two colors, for each glDraw call. But instead I get one rectangle for second draw.
I assume, that both draw calls actually draw me one same rectangle. But I clearly don't understand why.
I tried flushing in between, creating second buffer, glUseProgram in between, etc.
You can see full code here


Solution

  • The actual source code triggering this issue was this:

    shader.Select();
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    shader.Set("shift", 0);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);        
    shader.Set("shift", 0.5f);         
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    

    In conjunction with some shader class containging these methods:

    void Shader::Set(const std::string& name, bool value) const {
      glUniform1i(glGetUniformLocation(id, name.c_str()), (int32_t)value);
    }
    
    void Shader::Set(const std::string& name, int32_t value) const {
      glUniform1i(glGetUniformLocation(id, name.c_str()), value);
    }
    
    void Shader::Set(const std::string& name, float value) const {
      glUniform1f(glGetUniformLocation(id, name.c_str()), value);
    }
    

    This means that shader.Set("shift", 0); does call the int32 overload, resulting in trying to use glUniform1i to set a float uniform, which will just produce a GL error and not change the uniform at all. THe first frame will acutally be correct since the uniform is intialized to 0 by default, but after that, it will stay on 0.5 forever. Use shader.Set("shift", 0.0f);, but IMO, that kind of overloads is doing more harm than good.

    Side note: Those glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); calls are not necessary, the VAO will store the GL_ELEMENT_ARRAY_BINDING.