4

所以我有一个系统(使用 OpenGL 4.x),我从外部源接收点流(可能带有颜色和/或正常)。我需要将这些点绘制为 GL_POINTS,运行自定义可切换着色器进行着色(颜色可以通过程序生成,或者来自顶点颜色或法线方向)。

流包括以相当规则的间隔(4 到 10 hz)接收任意计数(通常从 1k 到 70k 点)的一组点(有或没有正常或颜色),我需要将这些点添加到我的当前点并绘制所有点到目前为止收到的点。

我保证我的顶点类型不会改变,我在流式传输开始时被告知,所以我要么使用交错的顶点:pos+normal+color、pos+normal、pos+color,或者只是位置

我当前的解决方案是在指定最大顶点数的配置文件中分配适当顶点类型的交错顶点 VBO(与周围的 VAO)(使用 DYNAMIC 提示分配)。

随着新点的出现,我通过 glBufferSubData 填充了我当前未填充的 VBO。我保留了当前边界 VBO 到目前为止有多少个顶点的计数(activePoints),如果我当前的更新组的顶点数超过我的边界缓冲区(因为我限制每个 VBO 的顶点数),然后我分配一个新的 VBO 并填充从 0 开始并以我的更新组中剩余的点数(未添加到最后一个缓冲区)结束的范围,如果我还有剩余点我一次又一次地这样做。很少有更新组跨越 2 个以上的缓冲区。

渲染时,我使用 glDrawArrays(m_DrawMode,0,numVertices) 渲染我的所有 VBO (-1),其中 numVertices 等于最大缓冲区允许大小,我的边界缓冲区使用 glDrawArrays(m_DrawMode,startElem,numElems) 来说明它没有被有效顶点完全填充。

当然,在某些时候,我会得到比交互式绘制更多的点,所以我有一个 LRU 机制,可以根据需要释放最旧的(根据 LRU alg)VBO 集。

有没有更优化的方法来做到这一点?缓冲区孤儿?流媒体提示?地图与子数据?还有什么?

第二个问题是我现在被要求删除点(不定期),一次从 10 到 2000 不等。但是这些点在我最初收到它们的顺序中是不规则的。我可以找出它们当前退出的缓冲区中的偏移量,但它更多的是分散而不是范围。我一直在“删除它们”,方法是找到它们在正确缓冲区中的偏移量,并一个接一个地调用范围为 1 的 glBufferSubData(它们很少在缓冲区中彼此并排),并将 pos 更改为远离的某个地方他们永远不会被看到。最终我猜应该从这些删除请求中删除缓冲区,但我目前不这样做。

有什么更好的方法来处理它?

4

1 回答 1

4

映射可能比 更有效glBufferSubData,尤其是在必须“删除”点时。显式刷新可能特别有帮助。此外,映射允许您将缓冲区的填充卸载到另一个线程。
务必确保访问位正确(或性能极差),特别是如果您所做的只是写入,则不要映射“读取”区域。

正如您可能知道的那样,从顶点缓冲区中删除点并不容易。对于“少数”点(例如 10 或 20),我只需设置w = 0,这会将它们移动到无穷大并像以前一样继续绘制整个事物。如果您的剪辑平面不是无限远,这只会丢弃它们。通过显式刷新,您甚至不需要在内存中保留单独的副本。
对于“很多”点(例如 1,000),您可以考虑使用glCopyBufferSubData删除“孔”。在 GPU 上移动内存速度很快,对于数千个点来说,这可能是值得的。然后,您需要为每个顶点缓冲区维护一个计数,以便在删除一些点后绘制更少的点。

要“删除”整个顶点缓冲区,您应该孤立它们(并重用)。OpenGL 将代表它自己做正确的事情,这是保持绘制和重用内存的最有效方式。

按照 Andon M. Coleman 的评论中的建议使用glDrawElements代替glDrawArrays通常是一个很好的建议,但在这种情况下对您没有帮助。想要这样做的原因是转换后缓存通过按索引标记顶点来工作,因此绘图元素利用了转换后缓存,而绘图数组则没有。但是,转换后缓存仅对复杂几何图形有用,例如三角形列表或三角形条带。您正在绘制点,因此在任何情况下都不会使用转换后缓存——但使用索引会增加 GPU 和 PCIe 总线上的内存带宽。

于 2013-08-18T21:09:30.973 回答