c++openglglslglfw

Why GLSL shader program can't link correctly?


For unknown reason GLSL shader program can't link correctly, log is empty. Shaders compiled correctly.

Trying to do:

CompileShaders("Data/Shaders/ui", 0b01, MainUiShader);

...gives an error:

ERROR: Cant link shaders

Here is header with functions:

void CompileShader(std::string ShaderFile, GLenum ShaderType, GLuint ShaderVariable) {
    LoadFile(ShaderFile);
    ShaderVariable = glCreateShader(ShaderType);
    const char* ShaderSource = TempData0.c_str();
    glShaderSource(ShaderVariable, 1, &ShaderSource, NULL);
    glCompileShader(ShaderVariable);

    glGetShaderiv(ShaderVariable, GL_COMPILE_STATUS, &TempValue);
    if (!TempValue)
    {glGetShaderInfoLog(ShaderVariable, 4096, NULL, Log);
            std::cout << "ERROR: shader compilation fail\n";
            std::cout << Log << std::endl;}
    else {std::cout << "Shader compiled\n";}}

void CompileShaders(std::string ShaderFile, int8_t ShaderTypes, GLuint ShaderVariable) 
{
    ShaderVariable = glCreateProgram();
    if ((0b01 & ShaderTypes) > 0) {
        CompileShader(ShaderFile.append(".vsh"), GL_VERTEX_SHADER, Stemp[0]);
        glAttachShader(ShaderVariable, Stemp[0]);
        std::cout << ShaderFile;
        ShaderFile = ShaderFile.substr(0, ShaderFile.size() - 4);}
        CompileShader(ShaderFile.append(".fsh"), GL_FRAGMENT_SHADER, Stemp[2]);
        glAttachShader(ShaderVariable, Stemp[2]);
        std::cout << ShaderFile;

    glLinkProgram(ShaderVariable);
    glGetProgramiv(ShaderVariable, GL_LINK_STATUS, &TempValue);
    if (!TempValue) {
        std::cout << "ERROR: Cant link shaders";
        glGetProgramInfoLog(ShaderVariable, 512, NULL, Log);
        std::cout<<Log;
    }
}

Here is main code:

#include "main.h"
int main()
{
//GLFWInitialization:
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    ResetWindow();

    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    glGenBuffers(1, &VBO);
    glGenVertexArrays(1, &VAO);

    CompileShaders("Data/Shaders/ui", 0b00, MainUiShader);

    while (Window) {
        if (glfwWindowShouldClose(Window)) { glfwTerminate(); return 0; }
        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBindVertexArray(VAO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(position), position, GL_DYNAMIC_DRAW);

        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float),
            (void*)0);
        glEnableVertexAttribArray(0);

        glUseProgram(MainUiShader);

        glBindVertexArray(VAO);
        glDrawArrays(GL_TRIANGLES, 0, 3);
        glfwSwapBuffers(Window);
        glfwPollEvents();
    }
    
}

ui.fsh:

#version 330 core

out vec4 FragColor;

void main()
{
    FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}

ui.vsh:

#version 330 core

layout (location = 0) in vec3 position;

void main()
{
    gl_Position = vec4(position.x + 0.5, position.y, position.z, 1.0);
}

(All variables defined correctly, OpenGL initialized correctly, but if you need something I can send it, or I can send full project).

So I started writing this code from guides, it is can draw 1 triangle. This triangle should be orange colored but it is black colored because fragment shader don't work due to this problem and I have no idea why this happens.


Solution

  • The problem has nothing to do with OpenGL, but with the way how you pass variables to the methods. The handle for the shader is passed by value to the CompileShader method. Changes inside this method will not reflect back to the caller, meaning that Stemp[0] and Stemp[2] are never set. Since they are not set, an invalid shader object is attached to the shader program and linking fails.

    You can change your code to pass a reference similar to:

    void CompileShader(std::string ShaderFile, GLenum ShaderType, GLuint& ShaderVariable)
    

    , if you want the changes to ShaderVariable to be seen from outside.

    Please note, that your CompileShaders method has the same problem.