簡體   English   中英

更新Direct3D網格的頂點緩沖區的最快方法?

[英]Fastest way to update a Direct3D mesh's vertex buffer?

我有一個地形網格物體,其中每個頂點僅需要更新每個幀的Z值。 我當前的方法如下所示:

int stepping = CustomVertex.PositionNormalTextured.StrideSize / 4;

//ZPtr points to the Z value of the first PositionNormalTextured in the mesh.  
//This way we don't have to dereference ->Z for each vertex.
float* ZPtr = &(((CustomVertex.PositionNormalTextured*)
    TerrainMesh.LockVertexBuffer(LockFlags.NoOverwrite).InternalDataPointer)->Z);

float* DPtr = TerrainHeight; //point to begin scanning result
float* EndPtr = DPtr + TerrainMesh.NumberVertices; //point to stop scanning result

do { *ZPtr = *DPtr; ZPtr += stepping; } while (++DPtr < EndPtr); //copy data
TerrainMesh.UnlockVertexBuffer(); //unlock

在這里,TerrainHeight是使用Marshal.AllocHGlobal創建的表示地形高度的浮點數組。 基本上,它會掃描整個TerrainHeight數組,並將每個值復制到網格中相應的PositionNormalTextured的Z值。 我使用LockFlags.NoOverwrite來避免創建數組的新副本,盡管這看上去並不比LockFlags.Discard快。

更新網格所需的時間比計算CPU中新地形所需的時間更長或更長時間,這使我相信應該有一種更快的方法。 我一直無法在Google上找到有關此信息。 有沒有更好的方法來更新頂點緩沖區? 萬一重要,用戶可以設置網格的大小,並且可以包括一百萬個頂點(這是使用多個網格完成的),但是默認設置為32k頂點,這是單個D3D網格的最大值。

看來您不了解DiscardNoOverwrite標志的后果。 閱讀DirectX SDK幫助中“ 性能優化”下的“ 使用動態頂點和索引緩沖區 ”一節。 假設您使用的是動態頂點緩沖區,則Discard表示“我正在替換整個緩沖區”,而NoOverwrite表示“我正在寫入緩沖區的未使用部分,並且保證不會更改我已經使用的任何部分” ”。

無論使用哪個標志,您都必須編寫地形頂點的每個組成部分,即使是在新框架中未更改的部分。

如果您不使用動態頂點緩沖區,那么如果您的GPU仍在使用它,則在嘗試鎖定下一幀的頂點緩沖區時可能會遇到停頓。 在這種情況下,您將需要使用多個頂點緩沖區,並在地形高度變化的每個幀中使用不同的緩沖區鎖定,更新,解鎖和渲染。 您還必須使用所有地形頂點數據來初始化所有這些緩沖區。

我建議將網格物體的z值分離到它們自己的頂點緩沖區中-假設您不更新x和y的位置,法線(如果z更改可能不正確)或紋理坐標。 這樣,您可以使用每幀都未觸及的PositionNormalTextured (無位置z)頂點緩沖區,並從一開始就使用Discard標志填充動態z位置緩沖區的每一幀,而不會跨步到每個Z值。 由於步幅已消失,因此可以使用平面內存副本進行操作。

您將使用SetStreamSource( 1, ZPositionVB, ... )您的頂點着色器提供z位置值。 您需要調整頂點聲明以從流1中讀取z位置值,並且需要使用頂點着色器在變換之前合並z位置值。

抱歉,如果其中有些不適合C#。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM