无法在OpenGL中将id分配给属性

时间:2013-11-20 14:07:03

标签: c++ c opengl glsl shader

我试图让OpenGL自动为glsl-attribute分配一个ID,但它失败了。

我的主要计划:

#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();
}

程序输出:

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

着色器加载器:

#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;
}

顶点着色器:

#version 130

in vec4 position;
in vec3 color;

out vec3 f_color;

void main() {
    f_color = color;

    gl_Position = position * gl_ModelViewProjectionMatrix;
}

片段着色器:

#version 130

in vec3 color;

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

出于某种原因,我只获得-1作为两个属性的位置。显然其余的错误是由无效的位置索引引起的?

来自OpenGL文档:
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.

名称不以gl_开头,并且它们在着色器中使用,因此我不应该获得-1的值。我错过了什么?

1 个答案:

答案 0 :(得分:3)

您未能获得color的属性位置,因为它不是 有效 。虽然在此示例中color用于计算f_color,但片段着色器不使用f_color,因此链接器确定名为color的顶点属性为不活动的。

解决方案非常简单,真的:

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);
}

在“顶点着色器”( 输入顶点属性 )和“片段着色器”( 输入顶点属性 )中重复使用名称color并不是错误strong> 输入不同的 )阶段,因此编译器/链接器不会抱怨。如果您尝试执行类似inout color的操作,那将是一个错误,因此这就是您必须使用不同命名的变量将顶点属性传递给几何/曲面细分/片段着色器的原因。如果阶段之间的输入/输出名称不匹配,那么原始顶点属性将被视为 非活动 的可能性非常大。


此外,除非您要移调ModelViewProjection矩阵,否则您的顶点着色器中的矩阵乘法会向后移动。 OpenGL使用的列主矩阵乘法应从右向左阅读。也就是说,您从对象空间位置(最右侧)开始并转换为剪辑空间(最左侧)。

换句话说,这是转换顶点的正确方法......

gl_Position = gl_ModelViewProjectionMatrix * position;

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