我正在尝试使用本教程在OpenGL中进行水模拟。
到目前为止,它的进展相当不错,我正在努力使其效率尽可能高效,因此,我不像以前那样使用Glbufferdata,而是尝试使用Glbuffersubdata。这很棒,因为我唯一需要更新的是顶部水位的y坐标,所以我跳过了很多数据。
但是,由于水模拟有液滴,因此我遇到了一个问题。似乎您在使用glbuffersubdata时无法添加新数据,而且由于液滴经常出现并消失,我似乎找不到一种添加到缓冲区的方法。
我在水和液滴中都使用单个VBO,因为唯一的其他选项似乎是使用索引的VAO,但是由于没有任何重复的顶点,这似乎毫无意义。
有其他我不知道的方式会对我有所帮助,还是我永远使用Glbufferdata来永远使用所有数据?
调整缓冲区的大小通常是一个不存在的概念。您不知道需要增加的缓冲区之后是否有空间,或者是否有可用的存储空间。所有似乎具有此选项的操作实际上会检查这些异常并在需要时重新分配缓冲区。
但是,在您的情况下,GPU上的缓冲区非常接近设备内存中的缓冲区。您甚至可以映射内存以使用glMapBuffer
接收void*
指针,但请检查整个过程。
结合这些事实,您独自一人来管理缓冲区中的数据。如果缓冲区需要充气,则应创建一个新数据,然后将旧数据复制到其中。其中一种方法是在需要时以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;
};
然后在您的对象中具有单个段的S结构:
struct Drop {
MyVertex vertices[6]; // or wahtever
}
现在,您需要在哪里为属性设置指针,您需要添加另一个可丢弃的属性(在glAttributePointer
中)。对于位置,您使用的是NULL+offsetof(MyVertex, x)
,用于丢弃NULL+offsetof(MyVertex, discarded)
。对于步幅sizeof(MyVertex)
...
现在,在片段着色器中检查丢弃的值并丢弃片段(如果它具有一定的值)(您可以选择任何含义任何值的值)。
现在,每当您添加一个滴水时,您都可以在内存中浏览数组,并检查其中一个滴剂是否被丢弃并使用该滴剂。因此,您为所有顶点设置drops[index].vertices[i].discarded = 0.0
,并使用缓冲区子数据程序更新缓冲区的此部分。
当您要删除它时,需要将丢弃的丢弃到1.0
(或您想要的任何内容),但请记住将顶点设置为等值(例如,所有0)。这样做的原因是您减少生成的片段数量。如果您只生成一些完全的屏幕坐标,那将是最佳的。
如果可能的话,切勿使用魔术数字,切勿使用固定值。sizeof
,offsetof
,struct
和union
应足以有效地管理原始数据。通过使用此更改的结构将永远不会破坏您的逻辑。