所以我有一个系统(使用OpenGL 4.x),我从外部源接收点流(可能有颜色和/或正常)。我需要将这些点绘制为GL_POINTS,运行自定义可切换着色器进行着色(颜色可以是程序生成的,或者来自顶点颜色或法线方向)。
流包括以相当规律的间隔(4到10赫兹)接收一组任意点(有或没有正常或颜色)的点(通常从1k到70k点),我需要添加这些点到目前的积分并绘制到目前为止得到的所有积分。
我保证我的顶点类型不会改变,我在流媒体的开头告诉我,所以我要么使用交错的顶点:pos + normal + color,pos + normal,pos + color ,或只是pos。
我目前的解决方案是在指定的最大顶点数(通过DYNAMIC提示分配)的配置文件中分配适当顶点类型的交错顶点VBO(带有周围的VAO)。
随着新点的出现,我通过glBufferSubData填充当前未填充的VBO。我保持当前边界VBO到目前为止有多少顶点的计数(activePoints),并使用glBufferSubData填充以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(它们很少在缓冲区中彼此相邻),并且在那里改变位置远离某处他们永远不会被看见。最终我猜缓冲区应该从这些删除请求中删除,但我目前不这样做。
处理这个问题的更好方法是什么?
答案 0 :(得分:4)
映射可能比glBufferSubData
更有效,尤其是在必须“删除”点时。明确的冲洗可能会有特别的帮助。此外,映射允许您将缓冲区的填充卸载到另一个线程
确保访问位正确(或性能极差),特别是如果您所做的只是写,请不要映射区域“读取”。
您可能知道,不容易从顶点缓冲区中删除点。对于“少数”点(例如10或20),我只需设置 w = 0 ,将它们移动到无穷大并继续绘制整个事物。如果您的剪裁平面不在无穷大,这将丢弃它们。通过显式刷新,您甚至不需要在内存中保留单独的副本
对于“很多”点(例如1,000),您可以考虑使用glCopyBufferSubData
删除“漏洞”。在GPU上移动内存很快,对于数千个点来说,这可能是值得的。然后,您需要为每个顶点缓冲区维护一个计数,这样在删除一些顶点缓冲区后就可以绘制更少的点。
要“删除”整个顶点缓冲区,您应该只是孤立它们(并重复使用)。 OpenGL将代表自己做正确的事情,这是继续绘制和重用内存的最有效方式。
根据Andon M. Coleman的评论建议使用glDrawElements
代替glDrawArrays
通常是一个很好的建议,但在这种情况下不会帮助您。人们想要这样做的原因是后变换缓存通过索引标记顶点来工作,因此绘图元素利用了后变换缓存,而绘图数组则没有。但是,变换后缓存仅适用于复杂几何体,例如三角形列表或三角形条带。您正在绘制点,因此在任何情况下都不会使用变换后缓存 - 但使用索引会增加GPU和PCIe总线上的内存带宽。