iOS 上的 OpenGL ES 多个没有索引的 VBO

Posted

技术标签:

【中文标题】iOS 上的 OpenGL ES 多个没有索引的 VBO【英文标题】:OpenGL ES on iOS Multiple VBOs without Indices 【发布时间】:2013-07-28 21:50:17 【问题描述】:

在我的应用程序中,我有一个呈现 STL 文件的视图。 STL 文件本质上是一个带有法线的三角形顶点列表,它们没有索引。

我找到的每个教程都解释了如何使用多个 VBO,但使用索引,当我尝试使用 drawArrays 而不是 drawElements 时,它不起作用。我是 OpenGL 的新手,如果有人可以提供代码示例来使用多个 VBO 进行设置并在没有索引的情况下绘制它们,我将不胜感激。

这就是我现在尝试这样做的方法,但无济于事。设置GL:

[EAGLContext setCurrentContext:self.context];

[self loadShaders];

self.effect = [[GLKBaseEffect alloc] init];
self.effect.light0.enabled = GL_TRUE;
self.effect.light0.diffuseColor = GLKVector4Make(.05f, .55f, 1.0f, 1.0f);

glEnable(GL_DEPTH_TEST);
glClearColor(0.88f, 0.88f, 0.88f, 1.0f);

//---- First Vertex Array Object --------
glGenVertexArraysOES(1, &_vertexArray);
glBindVertexArrayOES(_vertexArray);

glBindVertexArrayOES(_vertexArray);

glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, vertCount*sizeof(verticesBuff) * 3 * 2, verticesBuff, GL_STATIC_DRAW);

glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0));
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12));

//----- Second Vertex Array Object ----------
glGenBuffers(1, &_gridVertexBuffer);

glBindBuffer(GL_ARRAY_BUFFER, _gridVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, gridVertCount*sizeof(gridVerticesBuff) * 3 * 2, NULL, GL_STATIC_DRAW);

glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0));
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12));

glBindBuffer(GL_ARRAY_BUFFER,0);
glBindVertexArrayOES(0);

这是我的绘制代码:

glBindVertexArrayOES(_vertexArray);

glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glUseProgram(_program);
glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
glDrawArrays(GL_TRIANGLES, 0, vertCount);

///////// second VBO and shader program:
glBindBuffer(GL_ARRAY_BUFFER, _gridVertexBuffer);
glUseProgram(_program);
glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
glDrawArrays(GL_TRIANGLES, 0, 108);

另外,这是我之前使用的代码,它不会渲染两个数组,但会渲染一个(verticesBuff)。设置GL:

[EAGLContext setCurrentContext:self.context];

[self loadShaders];

self.effect = [[GLKBaseEffect alloc] init];
self.effect.light0.enabled = GL_TRUE;
self.effect.light0.diffuseColor = GLKVector4Make(.05f, .55f, 1.0f, 1.0f);

glEnable(GL_DEPTH_TEST);
glClearColor(0.88f, 0.88f, 0.88f, 1.0f);

glGenVertexArraysOES(1, &_vertexArray);
glBindVertexArrayOES(_vertexArray);

glGenBuffers(1, &_gridVertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _gridVertexBuffer);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0));
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12));
glBufferData(GL_ARRAY_BUFFER, 108 * sizeof(gridVerticesBuff), NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(gridVerticesBuff) * 108, gridVerticesBuff);


glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0));
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12));
glBufferData(GL_ARRAY_BUFFER, vertCount*sizeof(verticesBuff) * 3 * 2, NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(verticesBuff) * vertCount * 3, verticesBuff);

glBindVertexArrayOES(0);

这里是绘制代码:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

if (loaded) 
    // Render the object with GLKit
    [self.effect prepareToDraw];


    glBindVertexArrayOES(_gridVertexArray);
    glBindBuffer(GL_ARRAY_BUFFER, _gridVertexBuffer);
    glDrawArrays(GL_TRIANGLES, 0, 108);

    glBindVertexArrayOES(_vertexArray);
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
    glDrawArrays(GL_TRIANGLES, 0, vertCount);
 

【问题讨论】:

就像你做的那样。也可以像使用索引一样做所有事情,只是没有索引缓冲区,而是使用glDrawArrays(当然,顶点以三角形顺序排列)。请放心,这确实可以正常工作。如果它不适合您,请发布您的实际代码并描述更多以哪种方式“不起作用” 好的,我已经发布了我的代码的 2 个版本,它们都不能与多个 VBO 一起使用,但是其中一个会呈现其中的 1 个。 【参考方案1】:

不看代码就很难确切地知道哪里出了问题,但是如果您按照这些一般步骤操作,您应该能够弄清楚。索引数据和平面数据之间几乎没有区别。如果您了解它们在做什么,使用 VBO 会更容易。本质上,VBO 允许您将公共顶点数据预上传到显卡上,因此不必在每次绘制调用时重新加载。考虑到这一点,您需要考虑如何将正常绘制调用中使用的所有顶点数据打包到单个内存缓冲区中。

创建缓冲区:

glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, totalBufferSize, NULL, GL_STATIC_DRAW); /* totalBufferSize is sizeof vertices buffer + sizeof normals buffer */
glBufferSubData(GL_ARRAY_BUFFER, 0, vertexBufferSize, vertexBuffer); /* offset 0 */
glBufferSubData(GL_ARRAY_BUFFER, vertexBufferSize, normalBufferSize, normalBuffer); /* offset vertexbufferSize */

绘制缓冲区:

 glBindBuffer(GL_ARRAY_BUFFER, vbo);
 glVertexAttribPointer(VERTEX_ATTRIB ..., ((char*)NULL) + 0); /* start at beginning (0 offset) of the vertex buffer */
 glVertexAttribPointer(NORMAL_ATTRIB ..., ((char*)NULL) + vertexBufferSize); /* start at normal subdata (offset vertexBufferSize) of the vertex buffer */ 

 glDrawArrays(..., vertexCount);

(char*)NULL 的东西可能看起来有点奇怪。不是将指针传递到 RAM 中的缓冲区,而是将偏移量传递到当前绑定的 VBO。函数的参数仍然需要一个指针,因此指针的地址用作偏移量。理解 NULL 为 0 并将代码视为(char*)NULL + 不存在。

【讨论】:

好的,我添加了代码来显示我现在在做什么。我还用我的变量尝试了你的代码,但这些变量不起作用。它只是没有渲染任何东西。 @harry1795671 你没提到VAO,我看看。 @harry1795671 vertCount*sizeof(verticesBuff) * 3 * 2 这看起来不对,在堆栈数组的情况下 sizeof 会给你整个数组的大小。在指针方面会给你一个指针的大小。顶点是否紧密排列?如果是,你确定步幅是正确的吗? 我想是的。我刚刚发布了我的旧代码仍然试图解决这个问题,但它仍然呈现了 verticesBuff。

以上是关于iOS 上的 OpenGL ES 多个没有索引的 VBO的主要内容,如果未能解决你的问题,请参考以下文章

iOS上的OpenGL ES 1.1:没有剪裁平面?

iOS 上的 OpenGL ES 1.1:没有剪切平面?

iPhone 上的 OpenGL ES 2.0:无法超过小索引/顶点数

OpenGL ES显示白色或黑色屏幕

iOS OpenGL ES 逻辑缓冲区加载

Iphone 上的多个 OpenGL ES 视图是不是有高效且标准化的代码?