Qt + OpenGL4 : glBindVertexArray() 在绘图时创建一个GL_INVALID_OPERATION

Qt + OpenGL4 : glBindVertexArray() creates a GL_INVALID_OPERATION when drawing

提问人:Thibault de Villèle 提问时间:1/13/2021 更新时间:6/11/2021 访问量:323

问:

正如标题所暗示的那样,我正在尝试找到程序中错误的原因。 在我的程序中绘制场景时创建一个GL_INVALID_OPERATION,即使我事先已经正确初始化了它。glBindVertexArray()

该程序使用 Qt 5.15,并借助 libQGLViewer 库。它由同一屏幕上的多个QGLViewer实例组成,并使用底层类从多个Qt小部件中的相同缓冲区/纹理/VBO中绘制相同的内容。Scene

该类继承自该类,使其符合 OpenGL 4.0,因此能够使用 VAO/VBO。问题来了:我有几个绘制函数,具体取决于要求绘制的小部件的类型。以下是触发绘制的代码的概述:SceneQOpenGLFunction_4_0_Core

// in viewer1.hpp :

class Viewer1 : public QGLViewer {
    // ...
    virtual void initGL() override; // Overrides QGLViewer's initGL function, similar to the QOpenGLWidget function of the same name
    virtual void draw() override; // Overrides QGLViewer's draw function
  protected:
    Scene* scene;
    // ...
}

// In viewer2.hpp :

class Viewer2 : public QGLViewer {
    // ...
    virtual void initGL() override; // Overrides QGLViewer's initGL function, similar to the QOpenGLWidget function of the same name
    virtual void draw() override; // Overrides QGLViewer's draw function
  protected:
    Scene* scene;
    // ...
}

// In scene.hpp :

void GetOpenGLError(); // <- Checks OpenGL error(s) and prints them, clearing the error state

class Scene : public QOpenGLFunctions_4_0_Core {
    // ...
    void initScene();
    void drawFromViewer1(GLfloat* vMat, GLfloat* pMat);
    void drawFromViewer2(GLfloat* vMat, GLfloat* pMat);
  protected:
    bool isInitialized;
    GLuint vaoHandle;
    // I have a special technique of volumetric drawing with difficult
    // requirements which cannot be handled with the other VAO :
    GLuint vaoHandle_volumetric;
    // other opengl 'handles' (OpenGL names/IDs) to VBOs, textures ...
}

在我的函数中,它唯一要做的一件事就是调用该函数,该函数检查场景是否已经使用布尔成员初始化(或开始初始化)(因此场景不会初始化两次)。在函数中,我调用是为了让 Qt 提供的 OpenGL 函数指针初始化为正确的值,这将允许我在不同的查看器中绘制场景。说到这里,以下是不同绘制函数的代码概述:initGL()initScene()Scene::isInitializedinitScene()this->initializeOpenGLFunctions()

void Scene::initScene() {
    // ...
    glGenVertexArrays(1, &this->vaoHandle);
    GetOpenGLError(); // <- Prints nothing
    glBindVertexArray(this->vaoHandle);
    GetOpenGLError(); // <- Prints nothing
    if (glIsVertexArray(this->vaoHandle) == GL_FALSE) {
        throw std::runtime_error("VAO error in initScene()"); // <- doesn't get triggered
    }
    // Specify VAO state and pointers (...)
    // ...
}

void Scene::drawFromViewer1(GLfloat* vMat, GLfloat* pMat) {
    // Set the uniforms for the draw
    glBindVertexArray(this->vaoHandle);
    GetOpenGLError(); // <- Prints GL_INVALID_OPERATION !!!
    // Draw after binding index buffer ...
    // ...
}

void Scene::drawFromViewer2(GLfloat* vMat, GLfloat* pMat) {
    // Set the uniforms for the draw
    glBindVertexArray(this->vaoHandle);
    GetOpenGLError(); // <- Prints GL_INVALID_OPERATION !!!
    // Draw after binding index buffer ...
    // ...
}

没有意义的是,在 VAO 的创建/规范时,手柄是有效的,但在绘图时就不再有效了!

我确实在创建我的 / 之前调用了 opengl 查看器,以便 OpenGL 查看器共享相同的上下文,但这并没有改变任何事情,每次绑定 VAO 时,操作总是返回,根据 OpenGL 规范,这只有在 VAO 未创建时才会发生之前对 / 的调用!QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);QMainWindowQApplicationGL_INVALID_OPERATIONglGenVertexArrays()glBindVertexArrays()

我已经断断续续地尝试了几天来解决这个问题,但我似乎无法解决它。以前有没有人有过调试OpenGL / Qt程序的经验?在帮助论坛上,似乎没有多少人使用最新的桌面OpenGL版本和Qt......

C++ QT5 OpenGL-4 QOpenGL函数

评论

0赞 G.M. 1/13/2021
您确定在调用时有与当前线程关联的有效 OpenGL 上下文吗?glBindVertexArray
0赞 Thibault de Villèle 1/13/2021
@G是的,我忘了提到它,但在函数中,我传递了一个指向 的指针,而该指针又通过使用该函数进行检查。由于此指针来自查看器的函数,因此它是否使上下文成为当前线程的当前状态。initScene()QOpenGLContextisValid()QOpenGLWidget::context()

答:

1赞 Kim 6/11/2021 #1

尽管顶点缓冲区对象可以在 OpenGL 上下文之间共享, 顶点数组对象不能: https://www.khronos.org/opengl/wiki/Vertex_Specification#Vertex_Array_Object