varesa
varesa

Reputation: 2419

Can't get ids assigned to an attribute in OpenGL

I am trying to have OpenGL automatically assign an ID to a glsl-attribute, but it is failing.

My main program:

#include <iostream>

#include <GL/glew.h>
#include <GL/glfw3.h>

#include "test.h"
#include "shader_utils.h"

static void error_callback(int error, const char* description) {
    std::cout << description << std::endl;
}

static void key_callback(GLFWwindow* window, int a, int b) {
    if (a == GLFW_KEY_ESCAPE && b == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, GL_TRUE);
    }
}

void test()
{
    std::cout << "Starting up" << std::endl;
    init();
    run();
}

GLFWwindow *window;
GLuint shaders;
GLuint vertexBuffer;

int init() {
    glfwSetErrorCallback(error_callback);

    if(!glfwInit()) {
        return -1;
    }

    window = glfwCreateWindow(640, 480, "GLFW test", NULL, NULL);
    if (!window)  {
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    glfwSetKeyCallback(window, key_callback);

    glewExperimental = true;
    glewInit();

    shaders = LoadShaders("vertex.glsl", "fragment.glsl");

    GLuint vao_id;
    glGenVertexArrays(1, &vao_id);
    glBindVertexArray(vao_id);


    static const GLfloat vertex_data[] = {
        // Bottom
        -.5f, -.5f, -.5f,   1.f, 0.f, 0.f,
        -.5f, -.5f,  .5f,   1.f, 0.f, 0.f,
         .5f, -.5f,  .5f,   1.f, 0.f, 0.f,
    };

    glGenBuffers(1, &vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
}

void checkE() {
    std::cout << "Checking for errors: ";
    int err;
    int a = 0;
    while((err = glGetError()) != GL_NO_ERROR) {
        std::cout << "Error: " << err << std::endl;
        a = 1;
    }

    if(a == 0) {
        std::cout << "no errors" << std::endl;
    }
    std::cout.flush();
}

int run() {
    GLfloat angle = 0;

    while(!glfwWindowShouldClose(window)) {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glUseProgram(shaders);

        glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);

        GLuint attrLocation = glGetAttribLocation(shaders, "location");
        GLuint attrColor = glGetAttribLocation(shaders, "color");

        std::cout << "AttribLocation('location'): ";
        std::cout << glGetAttribLocation(shaders, "location") << std::endl;
        std::cout << "AttribLocation('color'): ";
        std::cout << glGetAttribLocation(shaders, "color") << std::endl;

        checkE();
        std::cout << std::endl;

        std::cout << "glEnableVertexAttribArray()" << std::endl;
        glEnableVertexAttribArray(attrLocation);
        glEnableVertexAttribArray(attrColor);

        checkE();
        std::cout << std::endl;

        std::cout << "glVertexAttribPointer();" << std::endl;

        glVertexAttribPointer(
                        glGetAttribLocation(shaders, "location"), // Attribute
                        3, // Size
                        GL_FLOAT, // Size
                        GL_FALSE, // Normalized
                        24, // Stride
                        (GLvoid*) 0 // Offset
                    );

        checkE();
        std::cout << std::endl;


        std::cout << "glVertexAttribPointer();" << std::endl;
        glVertexAttribPointer(
                        glGetAttribLocation(shaders, "color"),
                        3,
                        GL_FLOAT,
                        GL_FALSE,
                        24,
                        (GLvoid*) (3*sizeof(GLfloat))
                    );
        checkE();
        std::cout << std::endl;

        glDrawArrays(GL_TRIANGLES, 0, 3);

        checkE();
        std::cout << std::endl;

        glDisableVertexAttribArray(attrLocation);
        glDisableVertexAttribArray(attrColor);

        checkE();
        std::cout << std::endl;

        glfwSwapBuffers(window);
        glfwPollEvents();

        glfwSetWindowShouldClose(window, GL_TRUE);
    }

    glfwDestroyWindow(window);
    glfwTerminate();
}

Output from program:

Starting up
Compiling shader : vertex.glsl

Compiling shader : fragment.glsl

Linking program

AttribLocation('location'): -1
AttribLocation('color'): -1
Checking for errors: no errors

glEnableVertexAttribArray()
Checking for errors: Error: 1281

glVertexAttribPointer();
Checking for errors: Error: 1281

glVertexAttribPointer();
Checking for errors: Error: 1281

Checking for errors: no errors

Checking for errors: Error: 1281

Shader loader:

#include "shader_utils.h"

#include <string>
#include <iostream>
#include <fstream>
#include <vector>

#include "GL/glew.h"
#include "GL/glfw3.h"


GLuint LoadShaders(const char * vertex_file_path, const char * fragment_file_path){

    // Create the shaders
    GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
    GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

    // Read the Vertex Shader code from the file
    std::string VertexShaderCode;
    std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
    if(VertexShaderStream.is_open())
    {
        std::string Line = "";
        while(getline(VertexShaderStream, Line))
            VertexShaderCode += "\n" + Line;
        VertexShaderStream.close();
    } else {
        std::cout << "could not open\n";
    }

    // Read the Fragment Shader code from the file
    std::string FragmentShaderCode;
    std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
    if(FragmentShaderStream.is_open()){
        std::string Line = "";
        while(getline(FragmentShaderStream, Line))
            FragmentShaderCode += "\n" + Line;
        FragmentShaderStream.close();
    }

    GLint Result = GL_FALSE;
    int InfoLogLength;

    // Compile Vertex Shader
    printf("Compiling shader : %s\n", vertex_file_path);
    char const * VertexSourcePointer = VertexShaderCode.c_str();
    glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
    glCompileShader(VertexShaderID);

    // Check Vertex Shader
    glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
    glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
    std::vector<char> VertexShaderErrorMessage(InfoLogLength);
    glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
    fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]);

    // Compile Fragment Shader
    printf("Compiling shader : %s\n", fragment_file_path);
    char const * FragmentSourcePointer = FragmentShaderCode.c_str();
    glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
    glCompileShader(FragmentShaderID);

    // Check Fragment Shader
    glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
    glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
    std::vector<char> FragmentShaderErrorMessage(InfoLogLength);
    glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
    fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]);

    // Link the program
    fprintf(stdout, "Linking program\n");
    GLuint ProgramID = glCreateProgram();
    glAttachShader(ProgramID, VertexShaderID);
    glAttachShader(ProgramID, FragmentShaderID);
    glLinkProgram(ProgramID);

    // Check the program
    glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
    glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
    std::vector<char> ProgramErrorMessage( std::max(InfoLogLength, int(1)) );
    glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
    fprintf(stdout, "%s\n", &ProgramErrorMessage[0]);

    glDeleteShader(VertexShaderID);
    glDeleteShader(FragmentShaderID);

    std::cout.flush();

    return ProgramID;
}

Vertex shader:

#version 130

in vec4 position;
in vec3 color;

out vec3 f_color;

void main() {
    f_color = color;

    gl_Position = position * gl_ModelViewProjectionMatrix;
}

Fragment shader:

#version 130

in vec3 color;

void main() {
    gl_FragColor = vec4(color, 1);
}

For some reason I get just -1 as the location for both the attributes. Obviously the rest of the errors are caused by invalid location indices?

From OpenGL docs:
If the named attribute variable is not an active attribute in the specified program object or if name starts with the reserved prefix "gl_", a value of -1 is returned.

The names do not begin with gl_ and they are in use in the shaders, so I shouldn't get a value of -1. What am I missing?

Upvotes: 1

Views: 1897

Answers (1)

Andon M. Coleman
Andon M. Coleman

Reputation: 43319

You are failing to get an attribute location for color because it is not active. While it is true that color is used to calculate f_color in this example, the fragment shader does not use f_color so the linker determines that the vertex attribute named: color is inactive.

The solution is quite simple, really:

Fragment Shader:

#version 130

in vec3 f_color; // RENAMED from color, so that this matches the output from the VS.

void main() {
    gl_FragColor = vec4(f_color, 1);
}

It is not an error to re-use the name color for different purposes in the Vertex Shader (input vertex attribute) and Fragment Shader (input varying) stages so the compiler/linker will not complain. It would be an error if you tried to do something like inout color though, so this is why you have to pass vertex attributes to geometry/tessellation/fragment shaders using a differently named varying. If the input/output names between stages do not match then chances are quite good that the original vertex attribute will be considered inactive.


Also, unless you are transposing your ModelViewProjection matrix, you have the matrix multiplication in your vertex shader backwards. Column-major matrix multiplication, as OpenGL uses, should read right-to-left. That is, you start with an object space position (right-most) and transform to clip space (left-most).

In other words, this is the proper way to transform your vertices...

gl_Position = gl_ModelViewProjectionMatrix * position;

~~~~~~~~~~~   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~   ~~~~~~~~~
 clip space    object space to clip space    obj space

Upvotes: 3

Related Questions