【问题标题】:OpenGL 3.3: GL_INVALID_OPERATION when calling glBindBuffer [duplicate]OpenGL 3.3:调用 glBindBuffer 时的 GL_INVALID_OPERATION [重复]
【发布时间】:2018-04-01 00:41:38
【问题描述】:

好的,所以我在设置 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 类的一部分:

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 配合使用,因此我无法像通常希望的那样查看跟踪。任何建议都会有所帮助,从调试提示到可能的故障来源 - 提前致谢!

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

【问题讨论】:

标签: c++ opengl graphics opengl-3


【解决方案1】:

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

在下面一行:

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

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

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

您应该使类 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


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

【讨论】:

  • 酷,这已经消除了 glBindBuffer 的错误。我会接受这个,因为它解决了我眼前的问题,但我也想用它来尝试修复我的项目代码 - 你介意我回来看看吗?另外,为了确认一下,如果我将 Mesh obj 作为参数传递给构造函数,也会发生这种解构吗?无论如何,感谢您的快速响应!
  • 酷,我会检查这些。我不知道复制构造函数调用了析构函数,但它是有道理的。那是我在之前的调试中没有检查的少数几个地方之一,因为我认为它是安全的。再次感谢您的帮助。
  • 刚刚弄明白 - 这是这个提示和我的 GL_ELEMENT_ARRAY_BUFFER 数据上的不正确大小参数的组合。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多