3

I have a very basic engine based on OpenGL that can render polygons in any color to a resizeable window. I'm now trying to implement matrices for my shaders by giving the model, perspective and view matrices as uniforms via my shader. Before adding the uniforms everything worked as it should, I could even pass in a uniform vec2 to simulate a light source at my mouse position. The uniform mat4s doesn't work as well as the vec2s.

For debugging purposes I'm only rendering one yellow square centered on the screen. When using no uniforms the square shows as expected. i now try passing in one mat4, set as an identity matrix. In the vertex shader I'm multiplying gl_Position by the identity matrix I uniformed. When I run the program it only shows a black window.

I've tried manually creating an identity matrix in the vertex shader and multiplying gl_Position by that matrix instead of the uniform one. When I do that my yellow square shows as normal. This leads me to believe that the uniform mat4 doesn't get the correct values, however, I don't know how to check the values of the matrix when it's being used in the shader.

This is how my vertex shader looks:

#version 430 core

layout (location = 0) in vec3 position;
layout (location = 1) in vec4 color;

out vec4 Color;

uniform mat4 model;
uniform mat4 view;
uniform mat4 project;

void main()
{
    mat4 id;
    id[0] = vec4(1.0, 0.0, 0.0, 0.0);
    id[1] = vec4(0.0, 1.0, 0.0, 0.0);
    id[2] = vec4(0.0, 0.0, 1.0, 0.0);
    id[3] = vec4(0.0, 0.0, 0.0, 1.0);
    Color = color;
    gl_Position = id * vec4(position, 1.0);
}

The mat4 id is the manually created identity matrix, when changing id * to model * I get the black window.

This is how my fragment shader looks:

#version 430 core

in vec4 Color;

out vec4 outColor;

void main()
{
    outColor = Color;
}

The shader is initialized by this code:

m_shaderID = glCreateProgram();

const char* vertexSource = ReadFile::readFile(vertpath);
const char* fragmentSource = ReadFile::readFile(fragpath);

GLint status;

// Vertex Shader
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSource, NULL);
glCompileShader(vertexShader);
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE)
{
    std::cout << "Failed to compile vertex shader!\nInfo log: " << std::endl;
    char buffer[512];
    glGetShaderInfoLog(vertexShader, 512, NULL, buffer);
    std::cout << buffer << std::endl;
    glDeleteShader(vertexShader);
}

// Fragment Shader
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE)
{
    std::cout << "Failed to compile fragment shader!\nInfo log: " << std::endl;
    char buffer[512];
    glGetShaderInfoLog(fragmentShader, 512, NULL, buffer);
    std::cout << buffer << std::endl;
    glDeleteShader(fragmentShader);
}

// Shader program
glAttachShader(m_shaderID, vertexShader);
glAttachShader(m_shaderID, fragmentShader);
glLinkProgram(m_shaderID);
glValidateProgram(m_shaderID);

glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);

The matrix is created as a uniform by this code:

void Shader::setUniformmat4(const GLchar* name, glm::mat4 matrix)
{
    for (int i = 0; i <= 3; i++)
        printf("%f, %f, %f, %f\n", matrix[i].x, matrix[i].y, matrix[i].z, matrix[i].w);
    glUniformMatrix4fv(glGetUniformLocation(m_shaderID, name), 1, GL_FALSE, glm::value_ptr(matrix));
}

The printf is for checking the values of the matrix as they are used to create the uniform, and they have the values of an identity matrix at that point.

The function setUniformmat4 is called by this code:

glm::mat4 model = glm::mat4(1.0);
shader.setUniformmat4("model", model);

When creating a lighting effect I create the uniform by calling this function:

void Shader::setUniformvec2(const GLchar* name, glm::vec2 vector)
{
    glUniform2f(glGetUniformLocation(m_shaderID, name), vector.x, vector.y);
}

via this piece of code:

shader.setUniformvec2("light_pos", glm::vec2((x / window.getWidth()) * 2.0 - 1.0, 1.0 - 2.0 * (y / window.getHeight())));

Where x and y are the mouses coordinates. I then add the line

uniform vec2 light_pos;

To the fragment shader. This works no problem, and it traces the mouse perfectly. The function used for setting the uniform mat4 looks the same as the function for setting the uniform vec2, only difference is the 4fv for the mat4 and 2f for the vec2.

As you can see, I'm using glm for the matrices and vectors.

My main function looks like this:

    Window window(720, 720, "Window");

    Shader shader("shader.vert", "shader.frag");

    glm::mat4 model = glm::mat4(1.0);
    shader.setUniformmat4("model", model);

    Renderer* renderer = new Renderer();

    std::vector<StaticSprite*> sprites;

    sprites.push_back(new StaticSprite(-0.5, -0.5, 0.0, 1.0, 1.0, glm::vec4(1.0, 1.0, 0.0, 1.0), &shader));

    while (!window.closed())
    {
        window.clear();
        shader.enable();
        double x, y;
        window.getMousePosition(x, y);
        shader.setUniformvec2("light_pos", glm::vec2((x / window.getWidth()) * 2.0 - 1.0, 1.0 - 2.0 * (y / window.getHeight())));

        for (StaticSprite* sprite : sprites)
            renderer->submit(sprite);
        renderer->flush();

        shader.disable();
        window.update();
    }
    return 0;

My question summarized is basically why are the values of the uniform mat4 not correct, is there any way to find out what those values are, and what should I change in the code to make the uniform mat4s work?

Please ask for any additional information needed to give an answer, I will happily provide anything I forgot to include.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Viktor Axén
  • 199
  • 2
  • 11

1 Answers1

5

glUniform* specify the value of a uniform variable for the current program object. This means the program has to be installed by glUseProgram before:

Shader shader("shader.vert", "shader.frag");

shader.enable(); // <--- this is missing

glm::mat4 model = glm::mat4(1.0);
shader.setUniformmat4("model", model);

Active program resources can be get from a program object which is not the "current" program (e.g. glGetUniformLocation). Note, the program object is a parameter of glGetUniformLocation.
But to set the value of a uniform by glUniform*, the program has to be the currently installed program.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174