【问题标题】:Can't get ids assigned to an attribute in OpenGL无法获取分配给 OpenGL 中属性的 id
【发布时间】:2013-11-20 14:07:02
【问题描述】:

我试图让 OpenGL 自动为 glsl 属性分配一个 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 的值。我错过了什么?

【问题讨论】:

  • 从显而易见的开始:第一个属性在着色器中称为“位置”,而您在 C 代码中要求一个称为“位置”的属性。
  • 您还应该检查编译/链接值的 *_STATUS 值。
  • @FabioCeconello 修复了第一个属性。您对第二个 (color) 有任何想法吗?令人惊讶的是,您对自己代码中的简单错误视而不见。我用了四个小时来寻找那个问题,问题中的一个是我写的第三个“测试用例”......
  • @BrettHale 是否存在 ShaderInfoLog 什么都不显示,但 _RESULT 显示失败的情况?
  • @varesa - OpenGL 对着色器/程序日志的内容没有任何要求,AFAIK - 所以是的,您应该检查 Result 值。即使编译成功,GL 实现仍可能提供日志 - 警告、有用的提示、生命的秘密等。

标签: c++ c opengl glsl shader


【解决方案1】:

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

解决方案很简单,真的:

片段着色器:

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

在顶点着色器(输入顶点属性)和片段着色器( 输入不同的)阶段,因此编译器/链接器不会抱怨。但是,如果您尝试执行inout color 之类的操作,那将是一个错误,因此这就是您必须使用不同名称的变量将顶点属性传递给几何/细分/片段着色器的原因。如果阶段之间的输入/输出名称不匹配,则很有可能原始顶点属性将被视为inactive


此外,除非您要转置 ModelViewProjection 矩阵,否则您的顶点着色器中的矩阵乘法是向后的。 OpenGL 使用的列主矩阵乘法应该从右到左读取。也就是说,您从一个对象空间位置(最右边)开始,然后转换到剪辑空间(最左边)。

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

gl_Position = gl_ModelViewProjectionMatrix * position;

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

【讨论】:

  • 那个命名是另一种对你自己的错误视而不见的东西......我以为它们是一样的所以我没有注意到
猜你喜欢
  • 2018-01-08
  • 2020-11-09
  • 1970-01-01
  • 2017-02-28
  • 2017-10-21
  • 1970-01-01
  • 1970-01-01
  • 2022-07-14
  • 1970-01-01
相关资源
最近更新 更多