不能混合使用 OpenGL 缓冲区和 CPU 缓冲区

Posted

技术标签:

【中文标题】不能混合使用 OpenGL 缓冲区和 CPU 缓冲区【英文标题】:Can't mix OpenGL buffers and CPU buffers 【发布时间】:2019-12-28 15:27:18 【问题描述】:

我有一些用于体素引擎的代码,它将块的外表面计算为一系列顶点、法线和纹理坐标数组,并将它们存储在 CPU 内存中,以便我可以绘制它们。

画完它们后,我将选定的脸像半透明的红脸一样画在一切之上。

它有效,但随着世界的发展,它变得缓慢;所以我开始做正确的事情,使用glGenBuffers 生成缓冲区。这也有效,但之后我画的那张脸就消失了。我也可能将其移至 GPU 缓冲区,但我想知道为什么会这样。

这大致是我用来从 CPU 内存中绘制的代码(它有效,并且它以红色显示选定的面):

// Drawing the world, this is repeated for each chunk
glVertexPointer(3, GL_FLOAT, 0, &mVertex[0]);
glNormalPointer(GL_FLOAT, 0, &mNormal[0]);
glTexCoordPointer(2, GL_FLOAT, 0, &mTexture[0]);
glDrawArrays(GL_QUADS, 0, cVertex.size()/3);

// Drawing the selected face, face*12 or face*8 gives the correct index
glColor4f(1,0,0,0.2);
glVertexPointer(3, GL_FLOAT, 0, &boxVertex[face*12]);
glNormalPointer(GL_FLOAT, 0, &boxNormal[face*12]);
glTexCoordPointer(2, GL_FLOAT, 0, &boxTextureCord[face*8]);
glDrawArrays(GL_QUADS, 0, 4);

结果(无纹理):

这里我展示了从 GPU 内存中绘制的变化(选定的面停止渲染):

// Drawing the world, this is repeated for each chunk
// Buffers have been previously filled with mVertex, mNormal and mTexture
glBindBuffer(GL_ARRAY_BUFFER , mBuffers[0]);
glVertexPointer(3, GL_FLOAT, 0, nullptr);
glBindBuffer(GL_ARRAY_BUFFER , mBuffers[1]);
glNormalPointer(GL_FLOAT, 0, nullptr);
glBindBuffer(GL_ARRAY_BUFFER, mBuffers[2]);
glTexCoordPointer(2, GL_FLOAT, 0, nullptr);
glDrawArrays(GL_QUADS, 0, cVertex.size()/3);

// Drawing the selected face, face*12 or face*8 gives the correct index
glColor4f(1,0,0,0.2);
glVertexPointer(3, GL_FLOAT, 0, &boxVertex[face*12]);
glNormalPointer(GL_FLOAT, 0, &boxNormal[face*12]);
glTexCoordPointer(2, GL_FLOAT, 0, &boxTextureCord[face*8]);
glDrawArrays(GL_QUADS, 0, 4);

结果(无纹理):

所做的唯一更改是此处显示的更改以及调用 glGenBuffers 然后将缓冲区复制到 GPU 的代码。

【问题讨论】:

【参考方案1】:

OpenGL 是一个状态引擎。一旦设置了一个状态,它就会被保留,直到它再次被改变。

当您调用glBindBuffer(GL_ARRAY_BUFFER, mBuffers[2]) 时,命名缓冲区对象mBuffers[2] 将绑定到目标GL_ARRAY_BUFFER。 以下对glVertexPointerglNormalPointerglTexCoordPointer 的所有调用都使用此缓冲区,并且此函数的最后一个参数被视为缓冲区对象数据存储中的字节偏移量。

如果您想再次使用“CPU”缓冲区并直接将内存地址传递给这些函数,那么您必须通过绑定值零来取消绑定当前缓冲区。将缓冲区与目标GL_ARRAY_BUFFER 解除绑定后,最后一个参数指定了指向数据数组的指针:

glColor4f(1,0,0,0.2);

glBindBuffer(GL_ARRAY_BUFFER, 0); // zero effectively unbinds any buffer object

glVertexPointer(3, GL_FLOAT, 0, &boxVertex[face*12]);
glNormalPointer(GL_FLOAT, 0, &boxNormal[face*12]);
glTexCoordPointer(2, GL_FLOAT, 0, &boxTextureCord[face*8]);

glDrawArrays(GL_QUADS, 0, 4);

【讨论】:

二合一,我也不知道如何使用带偏移量的 OpenGL 缓冲区。现在一切都合适了。我一直在寻找一个 glUnbindBuffer 类型的函数,但是当我没有找到它时,我认为区别在于 nullptr 的使用。

以上是关于不能混合使用 OpenGL 缓冲区和 CPU 缓冲区的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL 四 - 002OpenGL 图形渲染之颜色混合

重构复杂的 opengl 混合

OpenGL ES之混合的概念和使用

iOS离屏渲染

帧缓冲区和在opengl中使用着色器

OpenGL 在单色上混合颜色