從頂點和索引緩衝區渲染 (Direct3D 9)
Direct3D 支援已編製索引和非索引的繪圖方法。 索引方法會針對所有頂點元件使用單一索引集。 頂點數據會儲存在頂點緩衝區中,而索引數據會儲存在索引緩衝區中。 以下是使用頂點和索引緩衝區繪製基本類型的一些常見案例。
這些範例會比較使用 IDirect3DDevice9::DrawPrimitive 和 IDirect3DDevice9::DrawIndexedPrimitive
案例 1:繪製兩個三角形而不編製索引
假設您想要繪製下圖所示的四邊形。
如果您使用三角形清單基本類型來轉譯兩個三角形,則每個三角形都會儲存為3個個別頂點,產生與下圖類似的頂點緩衝區。
繪圖呼叫非常簡單;從頂點緩衝區內的位置 0 開始,繪製兩個三角形。 如果啟用擷取,頂點的順序將會很重要。 此範例假設預設的逆時針撲殺狀態,因此可見的三角形必須依順時針順序繪製。 三角形清單基本類型只會從每個三角形的緩衝區以線性順序讀取三個頂點,因此此呼叫會繪製三角形 (0, 1, 2) 和 (3, 4, 5):
DrawPrimitive( D3DPT_TRIANGLELIST, // PrimitiveType
0, // StartVertex
2 ); // PrimitiveCount
案例 2:使用索引繪製兩個三角形
如您所注意到,頂點緩衝區包含位置 0 和 4、2 和 5 中的重複數據。 這很合理,因為兩個三角形共用兩個常見的頂點。 這個重複的數據是浪費的,而頂點緩衝區可以使用索引緩衝區來壓縮。 較小的頂點緩衝區會減少必須傳送至圖形配接器的頂點數據量。 更重要的是,使用索引緩衝區可讓配接器將頂點儲存在頂點快取中;如果繪製的基本類型包含最近使用的頂點,則可以從快取擷取該頂點,而不是從頂點緩衝區讀取,這會導致大幅提升效能。
索引緩衝區會將索引指向頂點緩衝區,因此每個唯一的頂點只需在頂點緩衝區中儲存一次。 以下圖表展示了一種索引化的方式,應用於先前的繪圖情境。
索引緩衝區會儲存 VB 索引值,其會參考頂點緩衝區內的特定頂點。 頂點緩衝區可以視為頂點陣列,因此 VB 索引只是目標頂點頂點的頂點緩衝區索引。 同樣地,IB 索引是索引緩衝區中的索引。 如果您不小心,這很快就會變得非常令人困惑,因此請確保您已清楚理解所用的詞彙:VB 索引值表示為頂點緩衝區的索引,IB 索引值表示為索引緩衝區的索引,索引緩衝區內部會儲存 VB 索引值。
繪圖呼叫如下所示。 下一個繪圖案例將詳述所有參數的意義;現在,請注意,此函數呼叫再次指示 Direct3D 自索引緩衝區的位置 0 開始轉譯包含兩個三角形的三角形列表。 此呼叫會以與之前完全相同的順序繪製相同的兩個三角形,以確保適當的順時針方向:
DrawIndexedPrimitive( D3DPT_TRIANGLELIST, // PrimitiveType
0, // BaseVertexIndex
0, // MinIndex
4, // NumVertices
0, // StartIndex
2 ); // PrimitiveCount
案例 3:使用索引繪製一個三角形
假設您現在只想要繪製第二個三角形,但您想要使用繪製整個四邊形時所使用的相同頂點緩衝區和索引緩衝區,如下圖所示。
第二個三角形的索引緩衝區和頂點緩衝區圖表
針對此繪圖呼叫,使用的第一個 IB 索引為 3;此值稱為 StartIndex。 使用的最低 VB 索引為 0;此值稱為 MinIndex。 即使只有三個頂點需要繪製三角形,這三個頂點會分散到頂點緩衝區中的四個相鄰位置:繪圖呼叫所需頂點緩衝區內存連續區塊內的位置數目稱為 NumVertices,而且在此呼叫中會設定為 4。 MinIndex 和 NumVertices 值實際上只是協助 Direct3D 在軟體頂點處理期間優化記憶體取的提示,而且可能只是設定為以效能代價包含整個頂點緩衝區。
以下是單一三角形案例的繪圖指令;接下來將說明BaseVertexIndex參數的意義:
DrawIndexedPrimitive( D3DPT_TRIANGLELIST, // PrimitiveType
0, // BaseVertexIndex
0, // MinIndex
4, // NumVertices
3, // StartIndex
1 ); // PrimitiveCount
案例 4:使用位移索引繪製一個三角形
BaseVertexIndex 是一個值,可有效地新增至儲存在索引緩衝區中的每個 VB 索引。 例如,如果我們在上一次呼叫期間傳入BaseVertexIndex的值為50,其功能上會與在 DrawIndexedPrimitive 呼叫期間使用下圖中的索引緩衝區相同:
這個值通常設定為 0,不過如果您需要將索引緩衝區與頂點緩衝區分離,這個設定可能會有用:若在填入特定網格的索引緩衝區時,尚未知道網格在頂點緩衝區中的位置,您可以假設網格頂點位於頂點緩衝區的開頭。當需要呼叫繪圖指令時,只需將實際的起始位置作為 BaseVertexIndex 來傳遞即可。
使用單一索引緩衝區繪製網格的多個實例時,也可以使用這項技術;例如,如果頂點緩衝區包含兩個網格具有相同繪製順序,但頂點稍有不同(或許不同的擴散色彩或紋理座標),則這兩個網格都可以使用不同的BaseVertexIndex值來繪製。 進一步採取這個概念,您可以使用一個索引緩衝區來繪製多個網格實例,每個實例都包含在不同的頂點緩衝區中,只要迴圈哪個頂點緩衝區作用中,並視需要調整BaseVertexIndex。 請注意,BaseVertexIndex 值也會自動新增至 MinIndex 自變數,當您查看其使用方式時,這很合理:
假設現在我們又想僅使用與之前相同的索引緩衝區來繪製四方形的第二個三角形;然而,這次使用一個不同的頂點緩衝區,其中四方形位於 VB 索引 50。 四邊形頂點的相對順序保持不變,頂點緩衝區內的起始位置不同。 索引緩衝區和頂點緩衝區看起來會像下圖。
這是合適的繪圖呼叫;請注意,BaseVertexIndex 是唯一已從先前案例變更的值:
DrawIndexedPrimitive( D3DPT_TRIANGLELIST, // PrimitiveType
50, // BaseVertexIndex
0, // MinIndex
4, // NumVertices
3, // StartIndex
1 ); // PrimitiveCount
相關主題