c++openglglslglfwglm-math

glUniformMatrix4fv() causing GL_INVALID_OPERATION


When I call glUniformMatrix4fv() or glUniform4fv() in the below code it raises GL_INVALID_OPERATION every time, I have tried changing how I pass it the matrix data, the count I pass id, I've checked the model ids and shader program but can't figure out why it does it.

Here is the shader:

# version 330

uniform vec4 projection; /* view port / perspective */
uniform vec4 model; /* object */
uniform vec4 view; /*camera */
in vec3 position;

void main() {
    gl_Position = projection * view * model * vec4(position, 1.0);
}

Here is my code:

#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>
#include <fstream>
#include <stdlib.h>

GLuint getShader(const char* shaderName, GLenum shaderType) {
    /* Read file */
    std::ifstream shaderFile;
    shaderFile.open(shaderName, std::ios_base::in);

    if(!shaderFile) {
        std::cout <<  shaderName << " not found" << std::endl;
        return 0;
    }

    std::string line;
    std::string shaderData;
    while(std::getline(shaderFile, line)) {
        shaderData += line + "\n";
    }

    shaderFile.close();

    /* Create shader */
    GLuint shader = glCreateShader(shaderType);

    if(shader == 0) {
        std::cout << "Failed to create shader for " << shaderName << std::endl;
        return 0;
    }

    const char *shaderStr = shaderData.c_str();

    glShaderSource(shader, 1, &shaderStr, nullptr);
    glCompileShader(shader);

    /* Check compile status */
    GLint status;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
    if(status != GL_TRUE) {
        GLint logLength;
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);

        GLchar* infoLog = new GLchar[logLength + 1];
        glGetShaderInfoLog(shader, logLength, nullptr, infoLog);

        std::cout << shaderName << " failed to compile: " << infoLog << std::endl;
        return 0;
    }

    return shader;
}

int end(const char* message) {
    glfwTerminate();

    if(message != nullptr) {
        std::cout << message << std::endl;
        system("PAUSE");
    }
    return 1;
}

int main() {
    /* Initial checks */
    if (!glfwInit()) {
        return end("Failed to startup GLFW");
    }

    /* Create the window */
    GLFWwindow *window = glfwCreateWindow(500, 500, "3D world prototyping", nullptr, nullptr);

    if (!window) {
        return end("Failed to create window.");
    }

    glfwMakeContextCurrent(window); //make the window active

    /* Startup GLEW */
    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK) {
        return end("Failed to startup GLEW");
    }

    /* Start OpenGL constants */
    glEnable(GL_DEPTH_TEST);
    glViewport(0, 0, 500, 500);

    /* Support for multiple shaders without the need to switch attributes */
    GLuint vertexArray;
    glGenVertexArrays(1, &vertexArray);
    glBindVertexArray(vertexArray);

    /* Create buffers */
    GLuint vertexBuffer;
    glGenBuffers(1, &vertexBuffer);

    /* Shape vectors */
    GLfloat verticies[] = { //X, Y, Z
            -0.5f, -0.5f, -0.5f,
            0.5f, -0.5f, -0.5f,
            0.5f, 0.5f, -0.5f,
            0.5f, 0.5f, -0.5f,
            -0.5f, 0.5f, -0.5f,
            -0.5f, -0.5f, -0.5f,

            -0.5f, -0.5f, 0.5f,
            0.5f, -0.5f, 0.5f,
            0.5f, 0.5f, 0.5f,
            0.5f, 0.5f, 0.5f,
            -0.5f, 0.5f, 0.5f,
            -0.5f, -0.5f, 0.5f,

            -0.5f, 0.5f, 0.5f,
            -0.5f, 0.5f, -0.5f,
            -0.5f, -0.5f, -0.5f,
            -0.5f, -0.5f, -0.5f,
            -0.5f, -0.5f, 0.5f,
            -0.5f, 0.5f, 0.5f,

            0.5f, 0.5f, 0.5f,
            0.5f, 0.5f, -0.5f,
            0.5f, -0.5f, -0.5f,
            0.5f, -0.5f, -0.5f,
            0.5f, -0.5f, 0.5f,
            0.5f, 0.5f, 0.5f,

            -0.5f, -0.5f, -0.5f,
            0.5f, -0.5f, -0.5f,
            0.5f, -0.5f, 0.5f,
            0.5f, -0.5f, 0.5f,
            -0.5f, -0.5f, 0.5f,
            -0.5f, -0.5f, -0.5f,

            -0.5f, 0.5f, -0.5f,
            0.5f, 0.5f, -0.5f,
            0.5f, 0.5f, 0.5f,
            0.5f, 0.5f, 0.5f,
            -0.5f, 0.5f, 0.5f,
            -0.5f, 0.5f, -0.5f,

            -1.0f, -1.0f, -0.5f,
            1.0f, -1.0f, -0.5f,
            1.0f, 1.0f, -0.5f,
            1.0f, 1.0f, -0.5f,
            -1.0f, 1.0f, -0.5f,
            -1.0f, -1.0f, -0.5f
    };
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(verticies), verticies, GL_STATIC_DRAW);

    /* Load in the shaders */
    GLuint fragmentShader = getShader("fragmentShader.glsl", GL_FRAGMENT_SHADER);
    GLuint vertexShader = getShader("vertexShader.glsl", GL_VERTEX_SHADER);

    if (fragmentShader == 0 || vertexShader == 0) {
        return end("Failed to load shaders");
    }

    /* Setup the shaders */
    /* Create the shader program and use it */
    GLuint shaderProgram = glCreateProgram();

    if (shaderProgram == 0) {
        return end("Failed to create shader program");
    }

    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glBindFragDataLocation(shaderProgram, 0, "outColor"); //tell opengl about the out color variable
    glLinkProgram(shaderProgram);

    if(glIsProgram(shaderProgram) != GL_TRUE) {
        return end("Failed to create shader program");
    }

    /* Positioning */
    //FOV, Screen ratio, display range short, display range long
    glm::mat4 projection = glm::perspective(glm::radians(45.0f), 4.0f / 3.0f, 0.1f, 100.0f);
    glm::mat4 view = glm::lookAt(
        glm::vec3(4.0f, 3.0f, 3.0f), // Camera
        glm::vec3(0.0f, 0.0f, 0.0f), // Where the camera looks up
        glm::vec3(0.0f, 1.0f, 0.0f)  // Pitch of the head
    );
    glm::mat4 model = glm::mat4(1.0f);

    /* Rendering and logic */
    while (!glfwWindowShouldClose(window)) {
        /* Shutdown logic */
        if (glfwGetKey(window, GLFW_KEY_ESCAPE)) {
            break;
        }

        /* Clear */
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glClearColor(0.2f, 0.2f, 0.2f, 1.0f);

        /* Logic */
        glUseProgram(shaderProgram);

        GLint projectionId = glGetUniformLocation(shaderProgram, "projection");
        GLint viewId = glGetUniformLocation(shaderProgram, "view");
        GLint modelId = glGetUniformLocation(shaderProgram, "model");

GLenum error = glGetError();
        if(error != GL_NO_ERROR) {
            std::cout << "Uniform error " << error << ": " << glewGetErrorString(error) << std::endl;
            return end("");
        }
        else if(projectionId == -1) {
            return end("Projection ID failed to load");
        }
        else if(viewId == -1) {
            return end("View ID failed to load");
        }
        else if(modelId == -1) {
            return end("Model ID failed to load");
        }

        glUniformMatrix4fv(viewId, 3, GL_FALSE, glm::value_ptr(view));

        error = glGetError();
        if(error != GL_NO_ERROR) {
            std::cout << "View uniform matrix error " << error << ": " << glewGetErrorString(error) << std::endl;
        }

        glUniformMatrix4fv(projectionId, 3, GL_FALSE, glm::value_ptr(projection));

        error = glGetError();
        if(error != GL_NO_ERROR) {
            std::cout << "Projection matrix error " << error << ": " << glewGetErrorString(error) << std::endl;
        }

        glUniformMatrix4fv(modelId, 3, GL_FALSE, glm::value_ptr(model));

        error = glGetError();
        if(error != GL_NO_ERROR) {
            std::cout << "Model uniform matrix error " << error << ": " << glewGetErrorString(error) << std::endl;
        }

        /* Tell opengl about all the attributes */
        GLint positionAttribute = glGetAttribLocation(shaderProgram, "position");

        if(positionAttribute == -1) {
            std::cout << "Error: position attribute failed to load" << std::endl;
            end("");
        }
        error = glGetError();
        if(error != GL_NO_ERROR) {
            std::cout << "Position attribute error " << error << ": " << glewGetErrorString(error) << std::endl;
        }

        glEnableVertexAttribArray(positionAttribute);

        error = glGetError();
        if(error != GL_NO_ERROR) {
            std::cout << "Vertex enable error " << error << ": " << glewGetErrorString(error) << std::endl;
        }

        glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);

        error = glGetError();
        if(error != GL_NO_ERROR) {
            std::cout << "Buffer bind error " << error << ": " << glewGetErrorString(error) << std::endl;
        }

        glVertexAttribPointer(positionAttribute, 3, GL_FLOAT, GL_FALSE, 0, 0); //because not just XYZ need to tell opengl the size of the stride

        error = glGetError();
        if(error != GL_NO_ERROR) {
            std::cout << "Vertex attrib pointer error " << error << ": " << glewGetErrorString(error) << std::endl;
        }

        /* Draw */
        glDrawArrays(GL_TRIANGLES, 0, 36);

        error = glGetError();
        if(error != GL_NO_ERROR) {
            std::cout << "gl draw arrays " << error << ": " << glewGetErrorString(error) << std::endl;
        }

        glDisableVertexAttribArray(positionAttribute);

        error = glGetError();
        if(error != GL_NO_ERROR) {
            std::cout << "gl disable attrib error " << error << ": " << glewGetErrorString(error) << std::endl;
        }

        glfwSwapBuffers(window);
        glfwPollEvents();

        error = glGetError();
        if(error != GL_NO_ERROR) {
            std::cout << "Error " << error << ": " << glewGetErrorString(error) << std::endl;
        }
    }

    glfwDestroyWindow(window);
    glDeleteProgram(shaderProgram);
    glDeleteShader(fragmentShader);
    glDeleteShader(vertexShader);
    glDeleteBuffers(1, &vertexBuffer);
    glDeleteVertexArrays(1, &vertexArray);
    return end(nullptr);
}

Solution

  • For the particular uniforms in question, you are using the wrong API call to set them.

    Those are vectors, rather than matrices. You would use glUniform4fv (...) rather than glUniformMatrix4fv (...). The latter function assumes that you are setting 1 or more 4x4 matrix uniforms (your passed parameters are telling it that projection is supposed to be an array of 3 mat4s).


    I believe the appropriate function calls would look like this in your situation:

    glUniform4fv (modelId, 1, glm::value_ptr(model)); // Fill 1 4D vector, not an array of vectors