2013-08-18 117 views
4

所以我有一個系統(使用OpenGL 4.x的)我在哪裏接收點(潛在地與顏色和/或正常)的流,從外部源。我需要將這些點繪製爲GL_POINTS,運行用於着色的自定義可切換着色器(可以程序化地生成顏色,或者來自頂點顏色或正常方向)。最快方式,以及去除偶爾

該流包括以相當規律的間隔(4到10赫茲)接收任意數量(典型的從1k到70k點)的一組點(有或沒有正常或顏色),我需要添加這些指向我目前的分數,並畫出迄今得分的所有分數。我保證我的頂點類型不會改變,我在流媒體開始時會告訴我,所以我要麼使用交錯頂點:pos + normal + color,pos + normal,pos +顏色,或只是pos。

我當前的解決方案是分配交織頂點維也納各組織(包括周圍VAOs)在一個配置文件中的相應頂點類型的指定的最大頂點計數(與動態分配的提示)。

進來我作爲新的點填滿我通過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

我不強烈建議你使用'glDrawElements(...)'來代替未使用的頂點。然後你傳遞一個實際上有數據的所有點的數組。您可以在內部保留未使用或自由頂點的列表,但是您絕對會浪費總線帶寬來清除自由頂點。只是讓他們像他們一樣,但承認他們不會被渲染/包含垃圾:) –

+0

所以你建議我創建一個刪除並創建一個新的VBO填充索引(或真正的IBO),每次說4點需要刪除緩衝區中的300k?然後用glDrawElements繪製,與glDrawArrays一樣? – Ryan

+0

不完全。我建議你給頂點緩衝區分配一個大小相等的IBO,最初它會依次填充0-n(其中n是你的VBO大小)的值。當你想在一個隨機位置或者一系列連續頂點上移除一個頂點時,只需使用'glBufferSubData(...)'並用指向有效頂點的索引替換IndexArray [n]處的值即可。通過這種方式,不必重新定義頂點位置,或者添加一個32位的w座標以便在渲染時「隱藏」去除的頂點,那麼您只需重新定義16位索引即可脫身。 –

回答

4

映射可以比glBufferSubData更有效,具有「刪除」點時尤其如此。顯式刷新可能會有特別的幫助。此外,映射允許您將緩衝區的填充卸載到另一個線程。
務必確保訪問位正確(或性能不佳),尤其是不要將區域映射爲「讀取」(如果所有操作都是寫入)。

從頂點緩衝區刪除點不容易實現,因爲你可能知道。對於「少數」點(例如10或20)我只會設置w = 0,這會將它們移動到無窮遠處,並像以前一樣繼續繪製整個事物。如果你的剪輯平面不是無限的,這隻會丟棄它們。使用明確的清除功能,您甚至不需要在內存中保留單獨的副本。
對於「許多」點(例如1,000),您可以考慮使用glCopyBufferSubData來消除「漏洞」。在GPU上移動內存很快,而且對於數千個點來說,這可能是值得的。然後,您需要爲每個頂點緩衝區保留一個計數,因此在刪除一些點後可以繪製更少的點。

要「刪除」整個頂點緩衝區,你應該只是孤立它們(並重用)。 OpenGL將以自己的名義爲用戶做正確的事情,並且這是保持繪圖和重用內存的最有效方式。

在這種情況下使用glDrawElements代替glDrawArrays在安東M.科爾曼的評論建議通常是一個很好的建議,但將不會幫助你。人們想要這樣做的原因是,轉換後緩存的作用是通過索引標記頂點,因此繪圖元素利用後轉換高速緩存而繪圖數組不能。但是,轉換後緩存僅適用於複雜的幾何體,如三角形列表或三角形條。您正在繪製點,所以在任何情況下都不會使用轉換後緩存 - 但使用索引可以增加GPU和PCIe總線上的內存帶寬。

+0

「......但在這種情況下**不會幫助你。」是這樣嗎?我的想法是在元素數組中設置一個16位索引(可以存儲在VBO中)比在頂點緩衝區中將32位浮點元素(w)設置爲0.0便宜(或者最差如問題所述,將整個頂點歸零)。在每次繪製調用時,元素數組都不得不被映射到GPU,因此用虛擬值替換元素索引(類似於原始重啓索引的工作方式)似乎(對我而言),就像總線開銷少。 –

+0

@ AndonM.Coleman:好的,你必須上傳不同的索引集以「零點」,這與上傳新緩衝區相同。 PCIe帶寬非常大,但延遲的固定最小值非常「非零」,這意味着進行任何類型的轉換都是痛苦的,但是否上傳稍微更多或更少的數據影響不大。另一方面,如果你使用它們(即使是沒有「漏洞」的完整緩衝區),你必須總是上傳索引,而不是每次繪製調用時都要上傳索引,而索引則佔用GPU上的內存。只要我確信他們比幫助更有害處。 – Damon

+0

因此,在我只是添加點到我的邊境VBO的情況下。它已經包含了10k點(100k)(我強加的),我想在這個更新中增加60k點。你會說映射是最好的,而不是緩衝區的子數據。什麼時候適用於孤立(刪除並立即重新創建)添加更新的緩衝區(如果有的話)。 – Ryan