Search code examples
c++openglglslshader

OpenGL can't send variables from vertex shader to fragment shader


I'm pretty new to OpenGL and just started with a basic program that has a vertex shader and a fragment shader. Everything worked until I tried to send data from the vertex shader to the fragment shader. I use out in the vertex shader and in in the fragment shader.

Here are the shaders.

The Vertex:

#version 120
varying vec4 ourColor;
attribute vec3 position;

void main()
{
gl_Position = vec4(position, 1.0);
ourColor = vec4(1.0,0.1,0.2,0.5);
}

And the Fragment:

#version 120 
varying vec4 ourColor;

void main()
{
gl_FragColor = ourColor;
}

The error is:

Fragment Shader contains a user varying but is linked without a vertex shader.

I tried using the flat keyword, and the varying keyword, same result. Also I've tried changing the version and then using in and out, same error.

Here is the Shader code (it's in a shader class, this is Shader.cpp):

     Shader::Shader(const std::string & fileName)
    {
    m_program = glCreateProgram();
    //vertex shader
    m_shaders[0] = CreateShader(LoadShader(fileName + ".vs"), GL_VERTEX_SHADER); 
    m_shaders[0] = CreateShader(LoadShader(fileName + ".fs"),       
            GL_FRAGMENT_SHADER); 

    
    for(unsigned int i = 0; i < NUM_SHADERS; i++)
        glAttachShader(m_program, m_shaders[i]);

    
    glBindAttribLocation(m_program, 0, "position");

    
    glLinkProgram(m_program);
    CheckShaderError(m_program, GL_LINK_STATUS, true, "Error: Program linking failed. ");

    glValidateProgram(m_program);
    CheckShaderError(m_program, GL_VALIDATE_STATUS, true, "Error: Program is invalid. ");
}
//-----------
Shader::~Shader(void)
{
    for(unsigned int i = 0; i < NUM_SHADERS; i++)
    {
        glDetachShader(m_program, m_shaders[i]);
        glDeleteShader(m_shaders[i]);
    }

    glDeleteProgram(m_program);

}
//----------
void Shader::Bind()
{
    glUseProgram(m_program);
}
static GLuint CreateShader(const std::string & text, GLenum shaderType)
{
    GLuint shader = glCreateShader(shaderType);
    if(shader == 0)
    {
        std::cerr << "Error: Shader creation failed! " << std::endl;
    }
    const GLchar* ShaderSourceStrings[1];
    GLint ShaderSourceStringsLengths[1];
    ShaderSourceStrings[0] = text.c_str();
    ShaderSourceStringsLengths[0] = text.length();
    glShaderSource(shader, 1, ShaderSourceStrings, ShaderSourceStringsLengths);
    glCompileShader(shader);
    CheckShaderError(shader, GL_COMPILE_STATUS, false, "Error: Shader compilation failed");
    return shader;
}
//-----------
static std::string LoadShader(const std::string & fileName)
{
    std::ifstream file;
    file.open((fileName).c_str());
    std::string output;
    std::string line;
    if(file.is_open())
    {
        while(file.good())
        {
            getline(file, line);
            output.append(line + "\n");
        }
    }
    else
    {
        std::cerr << "unable to load shader file: " << fileName << std::endl;
    }
    return output;
}
//-----------
static void CheckShaderError(GLuint shader, GLuint flag, bool isProgram, const std::string & errorMessage)
{
    GLint success = 0;
    GLchar error[1024] = {0};
    if(isProgram)
        glGetProgramiv(shader, flag, &success);
    else
        glGetShaderiv(shader, flag, &success);
    if(success == GL_FALSE)
    {
        if(isProgram){
            glGetProgramInfoLog(shader, sizeof(error), NULL, error);
        std::cout << "error from program" << std::endl;
        }
        else{
            glGetShaderInfoLog(shader, sizeof(error), NULL, error);
            std::cout << "error from shader" << std::endl;
        }
            std::cerr << errorMessage << ": '"  << error << "'" << std::endl;
        }
    }

Solution

  • Here's the error.

    m_shaders[0] = 
    m_shaders[0] = 
    

    Fragment Shader contains a user varying but is linked without a vertex shader.

    Linked without a vertex shader? That would definitely cause problems. The code should look something vaguely like this:

    GLuint load_shader(GLenum shader_type, ...) {
        GLuint shader = glCreateShader(shader_type);
        ... load shader source code ...
        glCompileShader(shader);
        GLint success;
        glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
        if (!success) {
            // boom
        }
        ... glGetShaderInfoLog ...
        return shader;
    }
    
    GLuint load_program(...) {
        GLuint prog = glCreateProgram();
        // Attach both fragment and vertex shader
        glAttachShader(prog, load_shader(GL_VERTEX_SHADER, ...));
        glAttachShader(prog, load_shader(GL_FRAGMENT_SHADER, ...));
        // Then link them together
        glLinkProgram(prog);
        GLint success;
        glGetProgramiv(program, GL_LINK_STATUS, &success);
        if (!success) {
            // boom
        }
        ... glGetProgramInfoLog ...
    }
    

    It's a fair bit of boilerplate code, and there are a lot of opportunities for the code to contain errors, so it's common for something to be wrong, especially since practically everything in OpenGL is just typedef int GLxxx; or something like that.


    In GLSL 120, in and out are not storage qualifiers. Use varying instead.

    // Same in vertex and fragment shader.
    varying vec4 ourColor;
    

    Alternatively, use a newer GLSL version.

    #version 330
    out vec4 ourColor;
    in vec3 position;
    
    #version 330
    in vec4 ourColor;
    out vec4 fragColor;