glVertexAttribPointer 提高 GL_INVALID_OPERATION 版本 330

glVertexAttribPointer raise GL_INVALID_OPERATION version 330

我正在尝试简化示例以显示确切的异常情况。我在 MacOS 10.14.6 上 运行 宁这个例子,编译 clang LLVM 编译器,使用 GLFW3。此外,我正在尝试 运行 使用 SFML 在 Windows 10/64 上使用相同的示例并得到相同的错误,因此问题不在环境中

OpenGL version 4.1 ATI-2.11.20 
Shading language version 4.10

问题所在的确切代码

glUseProgram(id_shader);
glEnableVertexAttribArray(param_Position);
//HERE IS ERROR "OpenGL ERROR: 0x00000502 GL_INVALID_OPERATION" RAISED
glVertexAttribPointer(param_Position, 3, GL_FLOAT, (GLboolean) false, 0, vertices);

这里是完整的源代码

#include <stdlib.h>
#include <OpenGL/gl3.h>
#include <GLFW/glfw3.h>

#include "engine/Camera.h"

static const char *get_error_string_by_enum(GLenum err)
{
    switch (err) {
        case GL_INVALID_ENUM :
            return "GL_INVALID_ENUM";
        case GL_INVALID_VALUE :
            return "GL_INVALID_VALUE";
        case GL_INVALID_OPERATION :
            return "GL_INVALID_OPERATION";
        case GL_STACK_OVERFLOW :
            return "GL_STACK_OVERFLOW";
        case GL_STACK_UNDERFLOW :
            return "GL_STACK_UNDERFLOW";
        case GL_OUT_OF_MEMORY :
            return "GL_OUT_OF_MEMORY";
#ifdef GL_INVALID_FRAMEBUFFER_OPERATION
        case GL_INVALID_FRAMEBUFFER_OPERATION :
            return "GL_INVALID_FRAMEBUFFER_OPERATION";
#endif
        default: {
            return "UNKNOWN";
        }
    }
}

static void check_gl()
{
    char line[300];
    GLenum err;

    err = glGetError();
    if (err != GL_NO_ERROR) {
        sprintf(line, "OpenGL ERROR: 0x%.8X %s", err, get_error_string_by_enum(err));
        printf("%s\n", line);
        exit(-1);
    }
}

int main()
{
    char line[2000];
    unsigned int windowWidth = 1024;
    unsigned int windowHeight = 1024;

    GLFWwindow* window;

    //SETUP WINDOW AND CONTEXT
    if (!glfwInit()){
        fprintf(stdout, "ERROR on glfwInit");
        return -1;
    }
    glfwWindowHint(GLFW_SAMPLES, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    window = glfwCreateWindow(windowWidth, windowHeight, "OpenGL", NULL, NULL);
    if (!window)
    {
        fprintf(stderr, "Unable to create window.");
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);

    sprintf(line, "OpenGL version %s\n", (const char *) glGetString(GL_VERSION));
    fprintf(stdout, line);
    sprintf(line, "Shading language version %s\n", (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION));
    fprintf(stdout, line);

    //SETUP OPENGL
    glViewport(0, 0, windowWidth, windowHeight);
    glEnable(GL_BLEND);
    glEnable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glDepthMask(true);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    //SETUP SHADER PROGRAM
    GLint success;
    GLuint id_v = glCreateShader(GL_VERTEX_SHADER);
    GLuint id_f = glCreateShader(GL_FRAGMENT_SHADER);

    const char *vertex_shader_source = "#version 330\n"
                                       "precision mediump float;\n"
                                       "\n"
                                       "in vec4 Position;\n"
                                       "uniform mat4 MVPMatrix;\n"
                                       "\n"
                                       "void main()\n"
                                       "{\n"
                                       "\tgl_Position = MVPMatrix * Position;\n"
                                       "\tgl_PointSize = 10.0;\n"
                                       "}";
    const char *fragment_shader_source = "#version 330\n"
                                         "precision mediump float;\n"
                                         "\n"
                                         "uniform vec4 Color;\n"
                                         "out vec4 FragCoord;\n"
                                         "\n"
                                         "void main()\n"
                                         "{\n"
                                         "  FragCoord = Color;\n"
                                         "}";

    glShaderSource(id_v, 1, &vertex_shader_source, NULL);
    glCompileShader(id_v);
    glGetShaderiv(id_v, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(id_v, 2000, NULL, line);
        fprintf(stderr, line);
        exit(-1);
    }

    glShaderSource(id_f, 1, &fragment_shader_source, NULL);
    glCompileShader(id_f);
    glGetShaderiv(id_f, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(id_f, 2000, NULL, line);
        fprintf(stderr, line);
        exit(-1);
    }

    GLuint id_shader = glCreateProgram();
    glAttachShader(id_shader, id_v);
    glAttachShader(id_shader, id_f);
    glLinkProgram(id_shader);
    glGetProgramiv(id_shader, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(id_shader, 2000, NULL, line);

        fprintf(stderr, "program link error");
        fprintf(stderr, line);
        exit(-1);
    }
    GLuint param_Position = glGetAttribLocation(id_shader, "Position");
    GLuint param_MVPMatrix = glGetUniformLocation(id_shader, "MVPMatrix");
    GLuint param_Color = glGetUniformLocation(id_shader, "Color");
    sprintf(line, "Params: param_Position=%d param_MVPMatrix=%d param_Color=%d\n", param_Position, param_MVPMatrix, param_Color);
    fprintf(stdout, line);

    //SETUP MATRIX
    Camera *c = new Camera();
    c->setCameraType(CameraType::PERSPECTIVE);
    c->setWorldSize(100, 100);
    c->lookFrom(5, 5, 5);
    c->lookAt(0, 0, 0);
    c->setFOV(100);
    c->setUp(0, 0, 1);
    c->calc();
    c->getResultMatrix().dump();

    //SETUP TRIANGLE
    float vertices[] = {
            0, 0, 0,
            1, 0, 0,
            1, 1, 0
    };

    while (!glfwWindowShouldClose(window))
    {
        //CLEAR FRAME
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glClearColor(0.3f, 0.3f, 0.3f, 1.0f);

        //RENDER TRIANGLE
        glUseProgram(id_shader);
        glUniformMatrix4fv(param_MVPMatrix, 1, (GLboolean) false, c->getResultMatrix().data);
        glUniform4f(param_Color, 1.0f, 0.5f, 0.0f, 1.0f);
        glEnableVertexAttribArray(param_Position);
        check_gl();
        //HERE IS ERROR "OpenGL ERROR: 0x00000502 GL_INVALID_OPERATION" RAISED
        glVertexAttribPointer(param_Position, 3, GL_FLOAT, (GLboolean) false, 0, vertices);
        check_gl();
        glDrawArrays(GL_TRIANGLES, 0, 3);

        glfwSwapBuffers(window);

        glfwPollEvents();
    }

    glfwTerminate();

    return 0;
}

行前

glVertexAttribPointer(param_Position, 3, GL_FLOAT, (GLboolean) false, 0, vertices);

在引发此行 GL_INVALID_OPERATION 之前和之后未检测到任何错误。

程序输出为:

环境版本:

OpenGL version 4.1 ATI-2.11.20
Shading language version 4.10

着色器参数名称:

Params: param_Position=0 param_MVPMatrix=1 param_Color=0

矩阵

-0.593333 -0.342561 -0.577350 -0.577350 
0.593333 -0.342561 -0.577350 -0.577350 
0.000000 0.685122 -0.577350 -0.577350 
0.000000 0.000000 8.640252 8.660253 

错误

OpenGL ERROR: 0x00000502 GL_INVALID_OPERATION

我已经在这个问题上花了几天时间了,不知道该把它放在哪里。如果有任何建议和说明,我将不胜感激。

P.S。这是我系统的 glfwinfo 输出

/glfwinfo -m3 -n2 --profile=compat
GLFW header version: 3.4.0
GLFW library version: 3.4.0
GLFW library version string: "3.4.0 Cocoa NSGL EGL OSMesa"
OpenGL context version string: "4.1 ATI-2.11.20"
OpenGL context version parsed by GLFW: 4.1.0
OpenGL context flags (0x00000001): forward-compatible
OpenGL context flags parsed by GLFW: forward-compatible
OpenGL profile mask (0x00000001): core
OpenGL profile mask parsed by GLFW: core
OpenGL context renderer string: "AMD Radeon R9 M370X OpenGL Engine"
OpenGL context vendor string: "ATI Technologies Inc."
OpenGL context shading language version: "4.10"
OpenGL framebuffer:
 red: 8 green: 8 blue: 8 alpha: 8 depth: 24 stencil: 8
 samples: 0 sample buffers: 0
Vulkan loader: missing

由于您使用核心配置文件上下文 (GLFW_OPENGL_CORE_PROFILE),因此默认 Vertex Array Object 0 is not valid further you've to use Vertex Buffer Object.

glVertexAttribPointer被调用时,顶点数组规范存储在当前绑定的顶点数组对象的状态向量中。当前绑定到目标的缓冲区 ARRAY_BUFFER 与属性关联,对象的名称(值)存储在 VAO 的状态向量中。
在兼容性配置文件中存在默认的顶点数组对象 0,它可以在任何时候使用,但这在核心配置文件上下文中是无效的。此外,在兼容性配置文件中没有必要使用 VBO,glVertexAttribPointer 的最后一个参数可以是指向顶点数据的指针。

最简单的解决方案是切换到兼容性配置文件GLFW_OPENGL_COMPAT_PROFILE:

glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);

如果您不想这样做或您的系统不提供该功能,那么您必须阅读 Vertex Specification。在程序循环之前创建一个顶点缓冲对象一个顶点数组对象:

// vertex buffer object
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

// vertex array object
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo); // this is not necessary, because "vbo" is still bound 
glVertexAttribPointer(param_Position, 3, GL_FLOAT, (GLboolean) false, 0, nullptr);

// the following is not necessary, you can let them bound
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);

并在循环中使用它绘制网格:

glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 3);