opengl交错vbo不渲染到屏幕

Posted

技术标签:

【中文标题】opengl交错vbo不渲染到屏幕【英文标题】:opengl interleaving vbo not rendering to screen 【发布时间】:2016-01-16 21:06:02 【问题描述】:

opengl 文档说交错数据并使用步幅和偏移量将多个顶点属性打包到一个缓冲区中。

apireference here 列出这种格式。

void glVertexAttribPointer( GLuint index,
    GLint size,
    GLenum type,
    GLboolean normalized,
    GLsizei stride,
    const GLvoid * pointer);

我在使用这种格式渲染东西时遇到了一些麻烦。我可以使用三个单独的缓冲区渲染场景并将数据放入其中,但使用一个缓冲区渲染的是空白屏幕。

数据结构。

typedef struct 
    vec3 angles;
    GLshort vertex_count;
    GLfloat vertices[12];
    GLfloat colors[16];
    GLshort indices[6];
    GLfloat tex_coords[8];
 cg_sprite;

glGenVertexArrays(1, &big_vao);
glGenBuffers(1, &big_vbo);
glGenBuffers(1, &big_ibo);

glBindVertexArray(big_vao);

glBindBuffer(GL_ARRAY_BUFFER, big_vbo);
glBufferData(GL_ARRAY_BUFFER, big_vbo_size, big_v_buff, GL_STREAM_DRAW);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, big_ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, big_ibo_total, big_i_buff,
             GL_STREAM_DRAW);

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(GLfloat),
                      (GLvoid*)0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 9 * sizeof(GLfloat),
                      (GLvoid*)(4 * sizeof(float)));
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 9 * sizeof(GLfloat),
                      (GLvoid*)(7 * sizeof(float)));


glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);

像这样设置我的 vbo 后,我在渲染循环中执行此操作。在 cpu 上平移、旋转和缩放顶点后,我将它们打包到巨大的缓冲区中,如下所示:

cg_sprite_back_2_front(sprites, sprite_count);
for (int i = 0; i < sprite_count; i++) 
    //--------------- start packing data into buffers----------------
    sp = sprites[i];

    // v0
    idx = 0;
    big_v_buff[(i * 36) + idx++] = ov0.x;
    big_v_buff[(i * 36) + idx++] = ov0.y;
    big_v_buff[(i * 36) + idx++] = ov0.z;

    big_v_buff[(i * 36) + idx++] = sp->quad->colors[0];
    big_v_buff[(i * 36) + idx++] = sp->quad->colors[1];
    big_v_buff[(i * 36) + idx++] = sp->quad->colors[2];
    big_v_buff[(i * 36) + idx++] = sp->quad->colors[3];

    big_v_buff[(i * 36) + idx++] = sp->quad->tex_coords[0];
    big_v_buff[(i * 36) + idx++] = sp->quad->tex_coords[1];

    // v1
    big_v_buff[(i * 36) + idx++] = ov1.x;
    big_v_buff[(i * 36) + idx++] = ov1.y;
    big_v_buff[(i * 36) + idx++] = ov1.z;

    big_v_buff[(i * 36) + idx++] = sp->quad->colors[4];
    big_v_buff[(i * 36) + idx++] = sp->quad->colors[5];
    big_v_buff[(i * 36) + idx++] = sp->quad->colors[6];
    big_v_buff[(i * 36) + idx++] = sp->quad->colors[7];

    big_v_buff[(i * 36) + idx++] = sp->quad->tex_coords[2];
    big_v_buff[(i * 36) + idx++] = sp->quad->tex_coords[3];

    // v2
    big_v_buff[(i * 36) + idx++] = ov2.x;
    big_v_buff[(i * 36) + idx++] = ov2.y;
    big_v_buff[(i * 36) + idx++] = ov2.z;

    big_v_buff[(i * 36) + idx++] = sp->quad->colors[8];
    big_v_buff[(i * 36) + idx++] = sp->quad->colors[9];
    big_v_buff[(i * 36) + idx++] = sp->quad->colors[10];
    big_v_buff[(i * 36) + idx++] = sp->quad->colors[11];

    big_v_buff[(i * 36) + idx++] = sp->quad->tex_coords[4];
    big_v_buff[(i * 36) + idx++] = sp->quad->tex_coords[5];

    // v3
    big_v_buff[(i * 36) + idx++] = ov3.x;
    big_v_buff[(i * 36) + idx++] = ov3.y;
    big_v_buff[(i * 36) + idx++] = ov3.z;

    big_v_buff[(i * 36) + idx++] = sp->quad->colors[12];
    big_v_buff[(i * 36) + idx++] = sp->quad->colors[13];
    big_v_buff[(i * 36) + idx++] = sp->quad->colors[14];
    big_v_buff[(i * 36) + idx++] = sp->quad->colors[15];

    big_v_buff[(i * 36) + idx++] = sp->quad->tex_coords[6];
    big_v_buff[(i * 36) + idx++] = sp->quad->tex_coords[7];

    idx = 0;
    big_i_buff[(i * 6) + idx++] = i * 4 + sp->quad->indices[0];
    big_i_buff[(i * 6) + idx++] = i * 4 + sp->quad->indices[1];
    big_i_buff[(i * 6) + idx++] = i * 4 + sp->quad->indices[2];

    big_i_buff[(i * 6) + idx++] = i * 4 + sp->quad->indices[3];
    big_i_buff[(i * 6) + idx++] = i * 4 + sp->quad->indices[4];
    big_i_buff[(i * 6) + idx++] = i * 4 + sp->quad->indices[5];
    idx = 0;
  

然后渲染调用

  glBindBuffer(GL_ARRAY_BUFFER, big_vbo);
    glBufferData(GL_ARRAY_BUFFER, big_vbo_total, big_v_buff, GL_STREAM_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, big_ibo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, big_ibo_total, big_i_buff,
                 GL_STREAM_DRAW);

glDrawElements(GL_TRIANGLES, sprite_count* 6, GL_UNSIGNED_SHORT, 0);

这将绘制到空白屏幕。我不知道哪里可能出错了。

好吧,这有点疯狂。我正在使用 amd 的 gpuperf 工作室来调试它,但这会导致更多的混乱。我截取了两张应用运行的屏幕截图。

分析器显示代码应该正在渲染,但无论出于何种原因它都不是。

这里是截图。

您甚至可以从调试器中看到假设四边形的位置有两个三角形。我有一个非常简单的着色器,所有数据都进入了 gpu,但由于某种原因它没有正确渲染,这真的很令人困惑。

现在我真的不明白发生了什么。有人有什么建议吗?

【问题讨论】:

【参考方案1】:

除了调用glVertexAttribPointer,您还必须使用`glEnableVertexAttribArray 来启用顶点属性。此外,纹理坐标的偏移量是错误的。它们必须从第 8 个元素开始,而不是从第 7 个元素开始。

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(GLfloat),
                  (GLvoid*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 9 * sizeof(GLfloat),
                  (GLvoid*)(4 * sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 9 * sizeof(GLfloat),
                  (GLvoid*)(8 * sizeof(float)));
                            ^

接下来的事情:如果你在 vao 仍然被绑定的时候解除GL_ELEMENT_ARRAY_BUFFER 的绑定,它就会从 vao 状态中移除。因此禁用必须按以下顺序发生:

glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

渲染:在初始化顶点属性指针后解除绑定 vao,但看起来好像在发出绘图调用之前忘记绑定它。

旁注:如果 VBO 的数据不是每一帧都在变化,你应该在初始化期间上传一次数据,而不是每一帧。

【讨论】:

我进行了所有这些编辑,但代码仍然绘制了一个空白屏幕。顶点可以旋转和缩放,这可以改变每个场景,精灵的数量也是可变的,因此索引也需要更新。我考虑了仅更新更改部分的方法,但我什至无法让交错的 vbo 渲染工作 atm。 你绘制的元素数量看起来很奇怪。我不确定 144 来自哪里,但它应该是 indexbuffer 中的条目数。 那 144 实际上是一个错字,我会更新它。它是 sprite_count * vertex_count。目前 sprite count = 1 和 vertex_count = 6 所以它应该只渲染 1 个四边形或 2 个三角形。 我刚刚对原来的问题做了一些修改,现在这真的让我很困惑! 您是否启用了背面剔除?如果是这种情况,请检查缠绕顺序是否正确。

以上是关于opengl交错vbo不渲染到屏幕的主要内容,如果未能解决你的问题,请参考以下文章

opengl es VBO用法 - 无几何渲染

Android OpenGL ES 2. 0 VBO 不渲染

使用 VAO/VBO 进行 OpenGL 模型/纹理渲染

切换到使用交错 VBO - 编译但没有绘制 - opengl es 2.0

在 Android 中使用带有 OpenGL ES 的 VBO 性能不佳

C++ 和 OpenGL,VBO 顶点与骨骼信息交错