OpenGL ES 2.0:缓冲区大小调整

时间:2017-03-02 10:19:35

标签: ios opengl-es

我尝试使用this tutorial在OpenGL中进行水模拟。

到目前为止它已经相当顺利了,我试图让它尽可能高效,所以不要像我之前那样使用每个帧的glBufferData,而是试图使用它glBufferSubData。这很好,因为我真正需要更新的唯一事情是顶部水位的Y坐标,所以我跳过了很多数据。

然而,由于水模拟有水滴,我遇到了问题。在使用glBufferSubData时似乎无法添加新数据,并且由于液滴经常出现和消失,我似乎无法找到将任何数据添加到缓冲区的方法。

我使用单个VBO用于水和水滴,因为唯一的其他选择似乎是使用索引的VAO,但由于没有任何重复的顶点,这似乎毫无意义。

还有另一种我不知道的方式可以帮助我解决这个问题,还是我一直坚持使用glBufferData来获取所有数据?

1 个答案:

答案 0 :(得分:1)

调整缓冲区大小通常是不存在的概念。您不知道在需要增加的缓冲区之后是否有空间,或者存储是否可用。似乎具有此选项的所有操作实际上都会检查这些异常,并在需要时重新分配缓冲区。

但在你的情况下,GPU上的缓冲区非常接近设备内存中的缓冲区。您甚至可以使用void*映射内存以接收glMapBuffer指针,但请检查整个过程。

结合这些事实,您可以独自管理缓冲区中的数据。如果缓冲区需要膨胀,则应创建一个新缓冲区,然后将旧数据复制到其中。其中一个程序是在需要时将缓冲区膨胀2倍:

  • 从一些固定的缓冲区大小开始,比方说currentSize = sizof(GLfloat*3*1000)
  • 继续填写数据并跟踪您拥有多少空间。当缓冲区充满时会膨胀它
  • newSize = currentSize*2以2
  • 膨胀
  • 使用新尺寸
  • 分配新缓冲区
  • 映射两个缓冲区
  • 将第一个currentSize个字节复制到新缓冲区(memcpy
  • currentSize设置为newSize

但现在这很容易。您的问题还包含可能丢弃缓冲区块的情况。所以你需要跟踪这些人。这是我能想到的几种方式:

  • 将屏幕上的坐标设为
  • 将其标记为可废弃的
  • 每次删除一个
  • 时推回数据

问题是他们每个人都有缺点。我个人会选择丢弃:

假设您正在使用ObjectiveC / C(如果您使用的是Swift,请不要打扰)。你会有一个顶点结构:

struct MyVertex {
   GLfloat x,y;
   // Add additional values here like color or whatever
   GLfloat discarded;
};

然后在对象中有一个单独的段结构:

struct Drop {
    MyVertex vertices[6]; // or wahtever
}

现在,您可以在其中设置属性的指针,您需要添加另一个可丢弃的指针(在glAttributePointer中)。对于您使用NULL+offsetof(MyVertex, x)的位置,可放弃NULL+offsetof(MyVertex, discarded)。对于步幅sizeof(MyVertex) ......

现在在片段着色器中检查丢弃的值并丢弃片段(如果它有一些值)(你可以选择任何值意味着什么)。

所以现在每当你添加一个drop时,你都可以在内存中查看你的数组并检查其中一个drop是否被丢弃并使用那个。因此,为所有顶点设置drops[index].vertices[i].discarded = 0.0,并使用缓冲区子数据过程来更新缓冲区的这一部分。

当您想要删除它时,您需要将丢弃设置为1.0(或任何您想要的),但也要记住将顶点设置为相等的值(例如,全部为0)。这样做的原因是减少了生成的片段数量。如果你只是生成一些完全屏幕外的坐标,这是最佳的。

如果可能,永远不要使用幻数,不要使用固定值。 sizeofoffsetofstructunion应足以有效管理原始数据。通过使用这种改变结构永远不会破坏你的逻辑。