c++ - glUniformMatrix4fv 失败,错误代码为 GL_INVALID_OPERATION

标签 c++ opengl glsl

我在尝试绑定(bind)统一的 4x4 矩阵时运气不佳。我的目标是使用这个程序的 OpenGL 3.3,但我的环境是 OpenGL 4.2。我有一个函数可以简单地将单位矩阵绑定(bind)到我的顶点着色器中的制服,但是对 glUniformMatrix4fv 的调用因 GL_INVALID_OPERATION 而失败。

这是我的顶点着色器:

#version 330
in vec4 in_vertex;
uniform mat4 mvMatrix;
void main(void) {
    gl_Position = mvMatrix * in_vertex;
}

我知道矩阵转置和左/右乘法的缺陷,但我认为这是一场我何时能够真正传递统一矩阵的战斗。

这是一个在我遇到问题的函数中引用的简单函数。我现在只使用它来尝试确定错误发生的位置。由于glUniformMatrix4fv的评估都是在服务器端,所以我没有办法使用断点等。

inline void die_on_gl_error(const char* location) {
    GLenum error = GL_NO_ERROR;
    error = glGetError();
    if (GL_NO_ERROR != error) {
        printf("GL Error %x encountered in %s.\n", error, location);
        exit(1);
    }
}

SDK docs说 glMatrixUniform4fv 可以设置 GL_INVALID_OPERATION 有几个原因:

  1. 如果没有当前程序对象,则生成 GL_INVALID_OPERATION。
  2. 如果着色器中声明的统一变量的大小与 glUniform 命令指示的大小不匹配,则会生成 GL_INVALID_OPERATION。
  3. 如果此函数的整数变体之一用于加载 float、vec2、vec3、vec4 或这些类型的数组的统一变量,或者此函数的浮点变体之一,则会生成 GL_INVALID_OPERATION用于加载 int、ivec2、ivec3 或 ivec4 类型的统一变量,或这些类型的数组。
  4. 如果 location 是当前程序对象的无效统一位置且 location 不等于 -1,则生成 GL_INVALID_OPERATION。
  5. 如果 count 大于 1 并且指示的统一变量不是数组变量,则会生成 GL_INVALID_OPERATION。
  6. 如果使用 glUniform1i 和 glUniform1iv 以外的命令加载采样器,则会生成 GL_INVALID_OPERATION。
  7. 如果在 glBegin 的执行和 glEnd 的相应执行之间执行 glUniform,则生成 GL_INVALID_OPERATION。

对于上下文,调用此函数的对象有一个名为 active_program 的参数,该参数存储当前激活的 GLSL 程序的编号。 identity_matrix 声明为:

float identity_matrix[16];

并定义为:

identity_matrix = {
            1.0f, 0.0f, 0.0f, 0.0f,
            0.0f, 1.0f, 0.0f, 0.0f,
            0.0f, 0.0f, 1.0f, 0.0f,
            0.0f, 0.0f, 0.0f, 1.0f
};

事不宜迟,这就是给我带来麻烦的地方:

void VSGL::load_identity_matrix() {
// GL_INVALID_OPERATION is generated if there is no current program object.
if (!glIsProgram(active_program)) {
    printf("Active program is not valid.\n");
    exit(1);
}

// ... active_program is a program, but is it valid?
GLint program_valid = 0;
glValidateProgram(active_program);
glGetProgramiv(active_program, GL_VALIDATE_STATUS, &program_valid);
if (GL_TRUE != program_valid) {
    printf("Program validation failed.\n");
    exit(1);
}
die_on_gl_error("GetProgram (Validate Status)");

// ... makes sure there is a program active, and the current program matches
// the value stored in active_program.
GLint current_program = 0;
glGetIntegerv(GL_CURRENT_PROGRAM, &current_program);
if (0 == current_program) {
    printf("Error, no current program is set.\n");
    exit(1);
} else if (current_program != active_program) {
    printf("Error, current program doesn't match active_program!\n");
}
die_on_gl_error("GetInteger");

// ... ensures the program actually has an active uniform, as the docs
// say that uniforms can be optimized out if they don't contribute to
// out results.
GLint num_active_uniforms = 0;
glGetProgramiv(active_program, GL_ACTIVE_UNIFORMS, &num_active_uniforms);
if (0 == num_active_uniforms) {
    printf("There are 0 uniforms active in program %d.\n", active_program);
    exit(1);
} else {
    printf("There are %d uniform(s) active in program %d.\n", num_active_uniforms, active_program);
}
die_on_gl_error("GetProgram (Active Uniforms)");

// GL_INVALID_OPERATION is generated if the size of the uniform variable
// declared in the shader does not match the size indicated by the glUniform
// command.

// GL_INVALID_OPERATION is generated if location is an invalid uniform location
// for the current program object and location is not equal to -1.

// ... gets some basic information about the active uniforms, of which there
// should be only one, a FLOAT_MAT4 of size 1.
const GLchar *uniform_name = "mvMatrix";
GLint location = glGetUniformLocation(active_program, uniform_name);
die_on_gl_error("GetUniformLocation");

GLchar *message;
GLint max_uniform_length;
glGetProgramiv(active_program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_length);
message = new GLchar[max_uniform_length];
GLint size;
GLenum type;
glGetActiveUniform(active_program, location, max_uniform_length, NULL, &size, &type, message);
printf("Uniform %s:\tType:%x\tSize:%d\n", message, type, size);
if (GL_FLOAT_MAT4 != type) {
    printf("Active uniform at location is not a 4x4 float matrix.\n");
}
die_on_gl_error("GetActiveUniform");

// GL_INVALID_OPERATION is generated if count is greater than 1 and the indicated
// uniform variable is not an array variable.

// GL_INVALID_OPERATION is generated if a sampler is loaded using a command other than
// glUniform1i and glUniform1iv.

// GL_INVALID_OPERATION is generated if glUniform is executed between the execution
// of glBegin and the corresponding execution of glEnd.

// None of the above are true, and yet the following dies with GL_INVALID_OPERATION?
glUniformMatrix4fv(location, 1, false, identity_matrix);
die_on_gl_error("UniformMatrix4f");
}

毕竟,这是输出:

There are 1 uniform(s) active in program 3.
Uniform mvMatrix:   Type:8b5c   Size:1
GL Error 502 encountered in UniformMatrix4f.

类型8b5c当然是GL_FLOAT_MAT4,大小当然是1,所以看不出是哪个无效操作条件在咬我!

编辑:

这是调用 UseProgram 和此函数的 main 循环:

    while (wm->update()) {
        wm->poll_input();
        handle_input(viewingmatrix);
        if (!gl->use_program(program))
            exit(-1);
        gl->load_identity_matrix();
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glDrawArrays(GL_TRIANGLES, 0, bananaNumVerts);
        glFlush();
        usleep(16667);
    }

gl->use_program(program) 只是一个包装器,它检查传入的 int 的有效性并更新对象的 active_program 参数。

编辑 2: 感谢 luke将我指向 gDEBugger,它也检测到了 GL 错误。在 gDEBugger 的调用信息中,我注意到只列出了三个参数。虽然我认为这可能是因为第四个是指向数组的指针(它是否驻留在客户端,还是每次调用 glUniform 时它都会传递给服务器端?),但它让我想到了还有什么可能是原因。

如果可以证明的话,glUniformMatrix4fv 当然实际上是一个获取其地址的函数指针,如下所示:

声明:

PFNGLUNIFORMMATRIX4FV glUniformMatrix4fv;

作业:

glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)glXGetProcAddress((const GLubyte*)"glUniform4fv");

这是我出于学术原因避免使用 GLEW。然而,当我浏览 gext.h 时,我注意到还有一个 PFNGLUNIFORMMATRIX4FVARBPROC,我认为它只是用于在此函数被采用到核心之前编写的代码库.如果不是这样,请告诉我。

最佳答案

看看你的 glXGetProcAddress 调用:

glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)glXGetProcAddress((const GLubyte*)"glUniform4fv");

您请求的是 glUniform4fv 而不是 glUniformMatrix4fv !

我知道你说过你没有出于学术原因使用扩展包装库,但我仍然强烈推荐它们。

关于c++ - glUniformMatrix4fv 失败,错误代码为 GL_INVALID_OPERATION,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9661049/

相关文章:

c++ - 本地餐厅自动早餐计费的问题 (c++)

c++ - 在 C++ 中访问姐妹对象的成员变量

c++ - 在库中强制内联 C++17 中的回调 (lambda)

opengl - 曲面分割着色器 - OpenGL

opengl - 如何使用GLSL在现代OpenGL中渲染文本

c++ - 将倒置场景渲染到帧缓冲区

C++ 前向声明和 'Incomplete type is not allowed' 错误

c - 使用顶点缓冲区和纹理缓冲区的 OpenGL C++ 顺序

GLSL channel 选择

c++ - glBindImageTexture 的 GL_TEXTURE_BINDING_2D?