无法获取分配给 OpenGL 中属性的 ID

Can't get ids assigned to an attribute in OpenGL

本文关键字:属性 ID OpenGL 获取 分配      更新时间:2023-10-16

我试图让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 openn";
    }
    // 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 : %sn", 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, "%sn", &VertexShaderErrorMessage[0]);
    // Compile Fragment Shader
    printf("Compiling shader : %sn", 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, "%sn", &FragmentShaderErrorMessage[0]);
    // Link the program
    fprintf(stdout, "Linking programn");
    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, "%sn", &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的值。我错过了什么?

您无法获取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);
}

在"顶点着色器"(输入顶点属性)和"片段着色器"(输入不同)阶段中,将名称color重复用于不同目的并非错误,因此编译器/链接器不会抱怨。但是,如果尝试执行类似inout color的操作,则会出现错误,因此,必须使用不同名称的variation将顶点属性传递给几何体/镶嵌/片段着色器。如果阶段之间的输入/输出名称不匹配,则原始顶点属性很可能被视为不活动


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

换句话说,这是变换顶点的正确方法。。。

gl_Position = gl_ModelViewProjectionMatrix * position;
~~~~~~~~~~~   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~   ~~~~~~~~~
 clip space    object space to clip space    obj space