C++ 删除不可见的面孔 VBO
Posted
技术标签:
【中文标题】C++ 删除不可见的面孔 VBO【英文标题】:C++ Remove invisible faces VBO 【发布时间】:2014-04-19 14:13:19 【问题描述】:我前段时间做了一个 VBO 立方体,效果很好,但性能欠佳。 如何删除 VBO 中的不可见面孔?
我的纹理也有问题,它们似乎被搞砸了:/ 如果有人知道可以解决这个问题,那就太好了!
我的代码:
#include <windows.h>
#include <iostream>
#include <glew.h>
#include <GL/gl.h>
#include <GL/glu.h>
#define OFFSET_BUFFER(bytes) ((GLfloat *)NULL + bytes)
PFNGLGENBUFFERSARBPROC glGenBuffers = NULL;
PFNGLBINDBUFFERPROC glBindBuffer = NULL;
PFNGLBUFFERDATAPROC glBufferData = NULL;
GLfloat vertex[];
GLuint m_vertexBuffer;
GLuint m_textureBuffer;
void VBOinit()
#ifdef _WIN32
glGenBuffers = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffers");
glBindBuffer = (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer");
glBufferData = (PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData");
#else
glGenBuffers = (PFNGLGENBUFFERSARBPROC)glXGetProcAddress((const GLubyte*)"glGenBuffers");
glBindBuffer = (PFNGLBINDBUFFERPROC)glXGetProcAddress((const GLubyte*)"glBindBuffer");
glBufferData = (PFNGLBUFFERDATAPROC)glXGetProcAddress((const GLubyte*)"glBufferData");
#endif
if (!glGenBuffers || !glBindBuffer || !glBufferData)
std::cerr << "VBOs are not supported by your graphics card" << std::endl;
return;
// TEXTURE VBO
GLfloat texture[] =
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1,
0, 0,
1, 0,
1, 1,
0, 1
;
glGenBuffers(1, &m_textureBuffer);
glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(texture), &texture, GL_STATIC_DRAW);
// GEOMETRIC VBO
GLfloat vertex[] =
0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, // v0-v0.5f-v2 (front)
-0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, // v2-v3-v0
0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, -0.5f, // v0-v3-v4 (right)
0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, // v4-v5-v0
0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, // v0-v5-v6 (top)
-0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, // v6-v0.5f-v0
-0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, -0.5f, // v0.5f-v6-v7 (left)
-0.5f, -0.5f, -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, // v7-v2-v0.5f
-0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, // v7-v4-v3 (bottom)
0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, // v3-v2-v7
0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, // v4-v7-v6 (back)
-0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f // v6-v5-v4
;
glGenBuffers(1, &m_vertexBuffer); //Generate a buffer for the vertices
glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer); //Bind the vertex buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), &vertex[0], GL_STATIC_DRAW); //Send the data to OpenGL
void VBOrender(int x, int y, int z)
glBindTexture(GL_TEXTURE_2D, Texture::textures[0]);
glTranslatef(x, y, z);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);
glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer);
glTexCoordPointer(2, GL_FLOAT, 0, OFFSET_BUFFER(0));
//glPolygonMode(GL_FRONT, GL_LINE);
glDrawArrays(GL_TRIANGLES, 0, 36);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glTranslatef(-x, -y, -z);
感谢您的阅读:)
【问题讨论】:
你如何定义“缺乏表现”?现代 GPU 甚至感觉不到一个立方体,它更像是“哈,你注意到什么了吗?”。 渲染 16*16*16 块时它给了我 30+/- fps;渲染 32*32*32 块给我 4 fps 不,我的 gpu 还不错,实际上我有一个很好的 GPU (2gb NVidia GForce gt440) 你的问题不是几何数量,而是API调用开销。对于每个多维数据集,您都调用glDrawArrays
;正是这些调用让性能变得糟糕。尝试将更多几何图形批处理到单个 glDrawArrays
调用中。在现代 GPU 上,当涉及到开销时,即使单个 glDrawArrays
调用会导致至少约 200 个三角形被绘制出来,也能达到收支平衡。如果你能把超过 1000 个装进去,事情就开始看起来不错了。在您的情况下,您可以使用 instance 来绘制所有立方体,只需一个 glDraw…
调用。
我该怎么做?我是 VBO 的新手 :) 但是在 VBO 中移除面孔是如何工作的?还是没搞清楚。
您不会从 VBO 中删除面孔。您可以做的最好的事情是从您传递给glDrawElements
(而不是glDrawArrays
)的索引列表中省略它们。许多新手将 OpenGL 与场景图混淆,即跟踪几何图形的系统。但这不是 OpenGL 的工作方式。 OpenGL 是一个绘图 API,它一次将点、线和三角形绘制到帧缓冲区,一个点、线或三角形。一个它已经画了它已经忘记了。这就是为什么 OpenGL 不做隐藏表面移除之类的事情。它为您提供深度测试和背面剔除,但仍会处理所有内容。
【参考方案1】:
添加关于我们在上面的 cmets 中开始的内容的详细信息,以及更多内容。
如前所述,添加glEnable(GL_CULL_FACE)
。我怀疑它是否解决了您的瓶颈,但它不会受到伤害。
您通常应该做的另一件事是将位置和纹理坐标交错存储在单个缓冲区中,而不是将它们存储在单独的缓冲区中。同样,我认为您现在在其他地方受到限制,只是一般性建议。
为了说明我在评论中关于避免在循环中设置冗余状态的建议。现在你的伪代码结构如下所示:
loop over x, y, z
VBOrender(x, y, z)
end loop
相反,我会这样构建它:
VBObind()
loop over x, y, z
VBOrender(x, y, z)
end loop
VBOunbind()
并像这样在您当前的VBOrender
函数中拆分代码:
void VBObind()
glBindTexture(GL_TEXTURE_2D, Texture::textures[0]);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);
glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer);
glTexCoordPointer(2, GL_FLOAT, 0, OFFSET_BUFFER(0));
void VBOunbind()
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
void VBOrender(int x, int y, int z)
glTranslatef(x, y, z);
glDrawArrays(GL_TRIANGLES, 0, 36);
glTranslatef(-x, -y, -z);
我希望这会给您带来显着的性能提升。为了获得更好的性能,你需要一些更引人注目的东西,比如将所有的立方体打包在一个绘图调用中。不过,这看起来有点棘手,因为从我在your code on pastebin 中可以看到,每个立方体的渲染都是有条件的。
如果您愿意编写自己的着色器,可以将平移设为属性,这样更新速度会比固定函数变换矩阵快得多。
【讨论】:
嗯,还有另一个选项,删除面孔。 (删除一些顶点指针)但是我知道如何:/ 编辑:对不起,它有效,这是我的块数组。但是我怎样才能“删除面孔” 任何人都知道如何通过删除部分顶点数组来“删除面”。还是排除他们?【参考方案2】:您可以通过调用打开背面剔除:
glFrontFace(GL_CCW); // <- says faces are defined in counter-clockwise order. Change if yours are in clockwise order
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
至于您的纹理,看起来您已经为 11 个立方体面定义了纹理坐标,但您正在绘制 36 个三角形。 36 个三角形就是 18 个四边形,所以我认为你需要更多的纹理坐标。
【讨论】:
以上是关于C++ 删除不可见的面孔 VBO的主要内容,如果未能解决你的问题,请参考以下文章
如何在行删除期间处理不可见的行。 (UITableViews)