我尝试使用this tutorial在OpenGL中进行水模拟。
到目前为止它已经相当顺利了,我试图让它尽可能高效,所以不要像我之前那样使用每个帧的glBufferData,而是试图使用它glBufferSubData。这很好,因为我真正需要更新的唯一事情是顶部水位的Y坐标,所以我跳过了很多数据。
然而,由于水模拟有水滴,我遇到了问题。在使用glBufferSubData时似乎无法添加新数据,并且由于液滴经常出现和消失,我似乎无法找到将任何数据添加到缓冲区的方法。
我使用单个VBO用于水和水滴,因为唯一的其他选择似乎是使用索引的VAO,但由于没有任何重复的顶点,这似乎毫无意义。
还有另一种我不知道的方式可以帮助我解决这个问题,还是我一直坚持使用glBufferData来获取所有数据?
答案 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)。这样做的原因是减少了生成的片段数量。如果你只是生成一些完全屏幕外的坐标,这是最佳的。
如果可能,永远不要使用幻数,不要使用固定值。 sizeof
,offsetof
,struct
和union
应足以有效管理原始数据。通过使用这种改变结构永远不会破坏你的逻辑。