OpenGL 3.3:调用 glBindBuffer 时 GL_INVALID_OPERATION

OpenGL 3.3: GL_INVALID_OPERATION when calling glBindBuffer

好的,所以我在设置 OpenGL 代码时遇到了一个非常棘手的问题。我正在尝试将我的图形代码重构为渲染器对象,但我似乎无法深入了解棘手的 GL_INVALID_OPERATION 错误(代码 1282)。

我首先创建一个网格对象,该对象初始化松散定义的 OpenGL 对象集合,并以 RAII 风格管理它们的生命周期:

struct OpenGLMesh
{
   OpenGLMesh(OpenGLRenderer& renderer, 
              int shader_index, 
              const char* fpath);

   ~OpenGLMesh();

   GLuint vbo_;
   GLuint ebo_;
   GLuint texture_;
   std::vector<float> vertices_;
   std::vector<unsigned int> indices_;
   GLuint shader_id_;
   GLuint mvp_id_;
};

OpenGLMesh::OpenGLMesh(OpenGLRenderer& renderer, int shader_index, const char* fpath)
{
   glGenBuffers(1, &vbo_);
   glGenBuffers(1, &ebo_);
   glGenTextures(1, &texture_);
   renderer.loadTexture(*this, fpath);

   const std::vector<GLuint>& shaders = renderer.getShaders();
   shader_id_ = shaders.at(shader_index);
   mvp_id_ = glGetUniformLocation(shader_id_, "MVP");
}

OpenGLMesh::~OpenGLMesh()
{
   glDeleteBuffers(1, &vbo_);
   glDeleteBuffers(1, &ebo_);
   glDeleteTextures(1, &texture_);
}

同时我有一个渲染器对象,它拥有大部分初始化和渲染函数。例如,上面构造函数中的 loadTexture 函数是我的 OpenGLRenderer class:

的一部分
OpenGLRenderer::OpenGLRenderer()
{
   glGenVertexArrays(1, &vao_); // allocate + assign a VAO to our handle
   shaders_.push_back(loadShaders("shaders/texture.vert", "shaders/texture.frag"));
}

OpenGLRenderer::~OpenGLRenderer()
{
   std::vector<GLuint>::iterator it;
   for (it = shaders_.begin(); it != shaders_.end(); ++it)
   {
      glDeleteProgram(*it);
   }
   glDeleteVertexArrays(1, &vao_);
}

我首先担心的是,这些函数调用的划分可能以某种方式使我的 OpenGL 设置调用的某些部分无效。但是,在我尝试绑定网格的 VBO 之前,错误不会出现。

下面是我为调试此问题而构建的精简测试模块中的代码:

// create the renderer object
OpenGLRenderer renderer;

// create and store a mesh object
std::vector<OpenGLMesh> meshes;
meshes.push_back(OpenGLMesh(renderer, 0, "./assets/dune_glitch.png"));

// SDL Event handling loop

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glBindVertexArray(vao_);
glBindBuffer(GL_ARRAY_BUFFER, mesh.vbo_);
printOpenGLError(); // prints out error code 1282

我已经确认每次都是这条线中断,尽管它似乎直到循环的下一次迭代才发出终止信号。

我无法找到关于此问题的任何见解 - 似乎 glBindBuffer 通常不会生成此类错误。我还确保 mesh.vbo_ ID 仍指向同一位置。

出于某种原因,我的应用程序的堆栈跟踪不能很好地与 GDB 配合使用,因此我无法像往常一样查看跟踪。任何建议都会有所帮助,从调试技巧到可能的故障源 - 提前致谢!

(这是我的第一个真正的 post,如果我搞砸了什么,请告诉我!)

它是 calss 的构造函数 OpenGLMesh 生成对象缓冲区 (glGenBuffers)。在析构函数中 OpenGLMesh::~OpenGLMesh 对象缓冲区被销毁 (glDeleteBuffers).

在下一行中:

meshes.push_back(OpenGLMesh(renderer, 0, "./assets/dune_glitch.png"));

push_back OpenGLMesh来了std::vector。这意味着生成了一个临时 OpenGLMesh 对象,并在其构造函数中生成了对象缓冲区。此时所有数据都是有效的,并且生成了对象缓冲区(GPU)。当调用std::vector::push_back时,会在std::vector中生成一个新的OpenGLMesh对象。该对象由默认的复制构造函数构造,并获得第一个 OpenGLMesh 对象的所有成员的副本。完成后,临时 OpenGLMesh 对象立即被销毁,对象缓冲区被临时对象的析构函数 OpenGLMesh::~OpenGLMesh 删除 (glDeleteBuffers)。此时所有数据都没有了。

参见 std::vector::push_back。在析构函数中打个断点OpenGLMesh::~OpenGLMesh,然后就可以简单的跟踪过期了。

您应该使 class not 可复制且 not 可复制构造,但指定移动构造函数和移动运算符。

class OpenGLMesh 
{
    OpenGLMesh(const OpenGLMesh &) = delete;
    OpenGLMesh & operator = (const OpenGLMesh &) = delete;

    OpenGLMesh( OpenGLMesh && );
    OpenGLMesh & operator = ( OpenGLMesh && );

    ....
};

出于调试原因,您可以通过替换

来快速修复此行为
meshes.push_back(OpenGLMesh(renderer, 0, "./assets/dune_glitch.png"));

来自

meshes.emplace_back(renderer, 0, "./assets/dune_glitch.png");

(参见 std::vector::emplace_back


有关移动构造函数和移动运算符的实现,请参阅: