尝试使用 VBO 时出错“必须禁用数组 vertex_buffer_object 才能调用此方法”

Posted

技术标签:

【中文标题】尝试使用 VBO 时出错“必须禁用数组 vertex_buffer_object 才能调用此方法”【英文标题】:Error when trying to use VBO "array vertex_buffer_object must be disabled to call this method" 【发布时间】:2011-12-06 10:44:44 【问题描述】:

编辑

我已经有效地重写了这个问题以大大提高它的质量 - 如果你必须查看修订日志

当我尝试创建顶点缓冲区时,我已将问题缩小到程序的初始化阶段。我目前使用的代码是...

vaoID = new int[1];
gl.glGenVertexArrays(1, vaoID, 0);
gl.glBindVertexArray(vaoID[0]);
vboID = new int[1];
gl.glGenBuffers(1, vboID, 0);
gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, vboID[0]);
FloatBuffer vData = FloatBuffer.allocate(vertexData.length);
vData.put(vertexData);
vData.rewind();
gl.glBufferData(GL4.GL_ARRAY_BUFFER, vData.capacity() * (Float.SIZE / 8), vData, GL4.GL_STATIC_DRAW);
gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, 0); // With out this line my code throws the exception
gl.glEnableVertexAttribArray(0);
gl.glVertexAttribPointer(0, 4, GL.GL_FLOAT, false, 0, null); // This is the line where the exception is thrown
gl.glBindVertexArray(0);

所以是的,目前我的代码能够在不崩溃的情况下运行,但它一定有一个错误,因为我无法让它呈现。对于缓冲索引数据,我使用了这段代码,它在运行时成功完成

gl.glGenBuffers(1, bufferIDs, 0);
gl.glBindBuffer(GL4.GL_ELEMENT_ARRAY_BUFFER, bufferIDs[0]);
ShortBuffer iData = ShortBuffer.allocate(indexData.length);
iData.put(indexData);
iData.rewind();
indexCount = iData.capacity();
gl.glBufferData(GL4.GL_ELEMENT_ARRAY_BUFFER, indexCount * (Short.SIZE / 8), iData, GL4.GL_STATIC_DRAW);
gl.glBindBuffer(GL4.GL_ELEMENT_ARRAY_BUFFER, 0);

然后在绘图方面,我执行以下步骤,我认为这并不重要,因为我确信我仍然没有正确缓冲

// first I bind my VAO
gl.glBindVertexArray(vaoID[0]);
// then bind, draw, unbind the index buffer
gl.glBindBuffer(GL4.GL_ELEMENT_ARRAY_BUFFER, bufferIDs[0]);
gl.glDrawElements(GL4.GL_POINT, indexCount, GL4.GL_UNSIGNED_SHORT, 0);
gl.glBindBuffer(GL4.GL_ELEMENT_ARRAY_BUFFER, 0);
// finally I unbind the VAO
gl.glBindVertexArray(0);

我相当确定这是渲染缓冲几何的正确过程。我已经通过使用一些即时绘图命令确认我的着色器代码是正确且有效的,所以我有完整的管道,只是似乎我没有向其中输入数据。作为一个兴趣点,我还尝试编辑我的顶点着色器以将所有点设置为(0,0,0,1),这样如果有任何点被传入,我应该看到它们,但这不起作用,我这意味着我一开始没有将数据传递到我的着色器中。

【问题讨论】:

您的初始化代码是否完整发布?你似乎是 glDisabling 东西而没有 glEnabling 它。 【参考方案1】:

glVertexAttribPointer 有两种操作模式。如果没有 VBO 绑定,它将指向数据的指针作为最后一个参数。如果有一个 VBO 绑定,则最后一个参数是缓冲区的整数偏移量。在 C 中,无论如何都必须将此整数转换为指针,但如果存在 VBO 绑定,则不会将其视为指针。

在 JOGL 中,这两种模式通过两个重载实现:one that takes a Buffer(而不是指针)和one that takes a long(而不是将偏移量转换为指针)。

如果您使用第一个带有 VBO 限制的模式,则会引发错误,因为这种模式仅在没有 VBO 限制的情况下才有效。如果您取消绑定您的 VBO 并将 null 传递给最后一个参数,您仍然调用第一个重载:null 可以匹配 Buffer 参数,但不能匹配 long。 JOGL 似乎对这种情况没有类似的验证。这可能会将其视为偏移量 0,但它也会将 0 存储为 VBO 以查找数据。也就是说,根本没有 VBO。

您需要做的是,使用您的原始代码,即使用 VBO 绑定,调用采用偏移量的重载:

//pass a long instead of a null Buffer
gl.glVertexAttribPointer(0, 4, GL.GL_FLOAT, false, 0, 0L);

还有另一个问题是不让任何东西渲染。您将GL4.GL_POINT 传递给glDrawElements。这不是有效的组装模式。我不知道它是干什么用的(我的 OpenGL 4 知识让我失望了)。点集合模式的常量命名为GL_POINTS

gl.glDrawElements(GL.GL_POINTS, indexCount, GL4.GL_UNSIGNED_SHORT, 0);

【讨论】:

AFAIR glVertexAttribPointer 要求仅当最后一个参数不为空时才绑定 VBO。但这听起来确实像一个错误。 @CatPlusPlus 你说得对,它不需要绑定!我完全忘记了这一点。最后一个参数是 1) 指向数据的指针,如果没有绑定 VBO,或 2) 偏移量,(可笑地转换为指针)如果绑定了 VBO。这让我想到了如何将随机整数转换为 Java 中的“指针”,并导致在非常糟糕的 JOGL 文档中进行探索。感谢您触发此发现! 这确实奏效了,尽管 Martin 在聊天中花了很多时间帮助我解决其他问题。主要是 GL_POINTS 不是 GL_POINT【参考方案2】:

我认为问题在于,当您进行 VA 抽签时,您的 VBO 仍然受到约束。确保每当您使用 glBindBuffer 为绘图调用绑定 VBO 时,在完成绘图后,将 ARRAY/ELEMENT_ARRAY 缓冲区绑定回 0。还要确保禁用您之后启用的任何客户端状态或属性数组你已经完成了抽奖。

// vbo draw
gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, bufferID[0]);
gl.glEnableVertexAttribArray(0);
gl.glVertexAttribPointer(0, 4, GL.GL_FLOAT, false, 0, null); // I know that this should be changed, but can't get code to run to this as can't buffer data in first place
gl.glDisableVertexAttribArray(0);
gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, 0);

// ibo draw
gl.glBindBuffer(GL4.GL_ELEMENT_ARRAY_BUFFER, bufferIDs[0]);
gl.glDrawElements(GL4.GL_POINT, indexCount, GL4.GL_UNSIGNED_SHORT, 0);
gl.glBindBuffer(GL4.GL_ELEMENT_ARRAY_BUFFER, 0);

您可能还必须在初始化方法中执行这些操作(在完成生成内容后禁用您启用的所有内容,并在传递数据后将内容绑定回零)。否则,当它开始绘制 VA 时,就会启用 VBO 的东西,所以 GL 会感到困惑,因为它认为它必须对 VBO 做一些事情,因为它已启用,但实际上你只是想使用 VA。

这是我对您问题的最佳猜测。如果我的帖子没有解决,请随时评论。

【讨论】:

对不起,如果这看起来很无知,但您已建议更改绘制代码,但最初缓冲我的顶点数据的代码引发了错误。另外,我想如果我在哪里使用VAO,当我绘制时,我只需要绑定那个VAO,并且恢复VBO和相关的atrtrib指针。 我的回答确实适用于初始化方法。在开始使用 vbo 之前尝试将顶点数组绑定到 0:glBindVertexArray(0);(就在 vboID = new int[1]; 之前) 我想我发现我只能在致电gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, 0); 后致电glVertexAttribPointer 更新问题以反映我的发现......但现在不知道该怎么办:S 我真的不明白你为什么在初始化代码中调用 glVertexAttribPointer。那是绘制代码,不是吗? @arasmussen 如果他正确使用了VAO,这将属于初始化代码,在这种情况下,他应该只在draw方法中调用glBindVertexArray而不是其他任何东西。但目前他的 VAO 只是没用。【参考方案3】:

也许你可以试试这个? 只是猜测

vaoID = new int[2];
gl.glGenVertexArrays(1, vaoID[0], 0);
gl.glBindVertexArray(vaoID[0]);
gl.glGenBuffers(1, vboID[1], 0);
gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, vboID[1]);
FloatBuffer vData = FloatBuffer.allocate(vertexData.length);
vData.put(vertexData);
vData.position(0);
gl.glBufferData(GL4.GL_ARRAY_BUFFER, vData.capacity() * (Float.SIZE / 8), vData, GL4.GL_STATIC_DRAW);
gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, 0); // With out this line my code throws the exception
gl.glEnableVertexAttribArray(0);
gl.glVertexAttribPointer(0, 4, GL.GL_FLOAT, false, 0, null); // This is the line where the exception is thrown
gl.glBindVertexArray(0);

【讨论】:

我明白你在想什么......但是像glGenVertexArray 这样的函数需要int[] 而不仅仅是int。我确实尝试过使用position(0) 而不是rewind(),但没有任何区别。

以上是关于尝试使用 VBO 时出错“必须禁用数组 vertex_buffer_object 才能调用此方法”的主要内容,如果未能解决你的问题,请参考以下文章

GL 错误:尝试使用 VBO 渲染时内存不足

OpenGL - 尝试使用 VBO 会导致错误

当我尝试从 vbo 获取颜色时,glDrawElements 没有输出

OpenGL:尝试使用 VBO(顶点缓冲区对象)绘制线条,它不显示

使用带有 glew 的 VBO 访问冲突

不使用 VBO 时 OpenGL 应用程序崩溃