1. 程式人生 > >【D3D學習記錄】DrawIndexedPrimitive函式的詳細解釋

【D3D學習記錄】DrawIndexedPrimitive函式的詳細解釋

為了便於說明,首先假設存在下列的頂點緩衝和索引緩衝    vb=    {     {-1.0, 1.0, 0.0}, index 0     { 1.0, 1.0, 0.0}, index 1     { 1.0,-1.0, 0.0}, index 2     {-1.0,-1.0, 0.0}, index 3

    {-2.0, 2.0, 0.0}, index 4

    { 2.0, 2.0, 0.0}, index 5

   }    和對應該頂點緩衝的一組索引緩衝ib           初學D3D,DrawIndexedPrimitive這個函式是個難點,主要是MSDN中的解釋不是很明確,這個函式共6個引數,下面對這6個引數進行一下詳細的解釋。

   引數1:D3DPRIMITIVETYPE type-圖元型別    使用的圖元型別,這個比較好理解,D3D只能繪製三種圖元-點、線和三角形,其中線和三角形又細分為線列表(LINELIST)、線條帶(LINESTRIP)、三角列表(TRIANGLELIST)、三角條帶(TRIANGLESTRIP),根據實際需要選擇使用某一種圖元,這不會影響最終的繪製效果,但理論上講,同樣多邊形數目的物體,使用三角形要比使用線繪製效率高(一個三角形=3條線),而條帶比列表要節省頂點數量,同樣n個頂點,線列表能繪製n/2條線,線條帶能繪製n-1條線,同樣,三角列表能繪製n/3個三角形,而三角條帶能繪製n-2個三角形,不過經過D3D最優化處理後,繪製條帶或列表的效能差別並不大。

   引數2:INT BaseVertexIndex-起始頂點索引    MSDN中的原話是這樣:Offset from the start of the vertex buffer to the first vertex.     “從頂點緩衝的起始位置到第一個頂點的偏移量”,第一個頂點不就是起始位置麼?不一定是,DrawIndexedPrimitive這個函式接受從頂點緩衝的任何一個位置開始讀入頂點資料,你可以從index0的位置開始讀取頂點資料,那這時BaseVertexIndex就是0,也可以從index2的位置開始讀取資料,那這時BaseVertexIndex就是2,如此類推。

   引數3:UINT MinVertexIndex-最小頂點索引(這裡MSDN應該是個筆誤,寫成MinIndex了,應該是MinVertexIndex)    MSDN:Minimum vertex index for vertices used during this call. This is a zero based index relative to BaseVertexIndex.     本次函式呼叫中,頂點緩衝中最小的頂點索引。MSDN解釋中我認為最關鍵的一句是“relative to BaseVertexIndex”-“相對與起始頂點”,即MinVertexIndex實際上也是個相對偏移量,例如,起始頂點是index2,MinVertexIndex是0,那麼實際是從index2讀入資料,起始頂點是index1,MinVertexIndex是1,那麼實際也是從index2讀入資料,即實際上的第一個頂點位置在BaseVertexIndex+MinVertexIndex處,最終偏移量=BaseVertexIndex+MinVertexIndex,這裡很容易產生誤解,就是認為MinVertexIndex是指頂點索引的最小值,即總是0,如果這樣那MinVertexIndex這個引數就沒有意義了。當初MS如果把這形參宣告為OffsetRelativeToBaseVertexIndex應該是更明確一點,不會讓人產生誤解。    另一個問題就是,理論上這個偏移量如果是負值也可能是有意義的,例如BaseVertexIndex是1,而MinVertexIndex是-1就是指的頂點緩衝中的第一個頂點,這是有意義的,但實際中如果給MinVertexIndex賦負值我沒有試驗過。一般情況下MinVertexIndex都是0。        引數4:UINT NumVertices-頂點數量    MSDN:Number of vertices used during this call. The first vertex is located at index: BaseVertexIndex + MinIndex.    本次呼叫所使用的頂點數量。MSDN的解釋依然(依舊)模糊,第一個頂點位於BaseVertexIndex + MinIndex這個我已經知道啦,還寫這個幹什麼?這裡的頂點數量不是指的頂點緩衝中的頂點總數量,如vb有6個頂點,“The first vertex is located at index: BaseVertexIndex + MinIndex”這句話是要告訴我們,計算頂點數量是要從BaseVertexIndex + MinIndex開始的,例如,我要畫一條從頂點index4到頂點index5的線段,那麼引數應該是這樣的:    BaseVertexIndex=4

   MinVertexIndex=0    NumVertices=2    NumVertices是2而不是6,即NumVertices不是頂點總數,而總是你繪製圖元實際需要的頂點數,注意這個“實際需要”,指的是你用到了幾個頂點,這取決於索引緩衝的繪製這個圖形所使用的不同的頂點個數(可能不太好理解,看下面的例子就明白了)。1條線段需要2個頂點,所以就是2,也許這形參宣告為NumVerticesUsedForDrawing更明確一些。

   引數5:UINT StartIndex-起始索引    又是一個Index,如果把這個形參宣告為StartIndexOfIndexBuffer,我想就不會頭暈了,這個起始索引指的是索引緩衝中的起始索引,也就是指索引緩衝陣列的下標(頂點緩衝和索引緩衝都是用陣列表示)-ib[StartIndex]。

   引數6:UINT PrimitiveCount-圖元數量    這個沒什麼難度,有一點要注意,對於繪製的幾何圖形而言,n-2和n/3指的都是索引的數量而不是頂點的數量,也就是說n是索引緩衝中索引的數量。

   好了,所有引數都明確了,現在終於可以自由運用DrawIndexedPrimitive繪製圖形了!

   先等一下,還有問題,怎麼說好呢?DrawIndexedPrimitive這個函式依然存在邏輯陷阱,而這個問題的最大問題就是,雖然你寫了有問題的程式碼,但在HAL裝置下沒有任何錯誤提示,編譯執行沒有任何問題,甚至有可能你的繪製結果和你的預期也是一樣的,這個問題只有在REF裝置下才能被發現。例如下面的例子:

   頂點緩衝如同文章頂部的定義,我要使用vb前4個頂點繪製2個三角形,最後2個頂點繪製1條線段,所以我這樣定義索引緩衝

   ib={0,1,2,0,2,3,4,5,},0-5號索引繪製2個三角形,6、7兩個索引繪製一條線段

   進行編碼,

   DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,4,0,2);//繪製2個三角形

   DrawIndexedPrimitive(D3DPT_LINELIST,4,0,2,6,1);//繪製1條線段

   先看第一條繪製程式碼,根據索引緩衝的定義可以知道,前6個索引使用了4個頂點(0,1,2,3),所以NumVertices引數為4,起始索引為0,繪製2個三角形,沒有任何問題。再看第二條繪製程式碼,線段的頂點資料是從vb中的第5個頂點開始的,所以起始頂點索引是4,最小頂點索引為0,使用了2個頂點(4和5)所以NumVertices為2,因為索引緩衝中的線段索引是從第7個索引開始的,所以起始索引是6,繪製1條線段,也沒有任何問題。

   執行,2個三角形出現了,線段呢?線段怎麼沒了?顯然,第二個條繪製程式碼不正確,可引數完全是按照規則定義的啊,為什麼不正確呢?原因在於,當第一個頂點的位置不是0時,也就是說起始頂點索引+最小頂點索引大於0時,且NumVertices值如果為實際需要的頂點數而不是頂點總數的時候,索引緩衝中對應頂點索引需要減去這個偏移量。回到上面的程式碼為例,當繪製線段的時候,第一個頂點被移動到了第5個位置(總偏移量為4+0),NumVertices為2是實際需要的頂點數,索引緩衝中的索引從第7(偏移量為6)個開始,對應index4號頂點,而這時index4號頂點對於索引緩衝來說已經不是4了,而是0,同樣index5號頂點也不是5而是1,所以需要修改索引緩衝資料。另一種辦法是不修改索引緩衝資料,指定總偏移量為0,NumVertices是全部頂點數。正確的程式碼應該是這樣,上面說的有些繞,結合程式碼就明白了,

修改方法1:

   ib={0,1,2,0,2,3,0,1,}//將以前的4、5修改為0、1

   DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,4,0,2);//繪製2個三角形

   DrawIndexedPrimitive(D3DPT_LINELIST,4,0,2,6,1);//繪製1條線段

修改方法2:

   ib={0,1,2,0,2,3,4,5,}//保持索引緩衝資料不變

   DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,4,0,2);//繪製2個三角形

   DrawIndexedPrimitive(D3DPT_LINELIST,0,0,5,6,1);//NumVertices修改為頂點總數

   上面那段錯誤程式碼HAL裝置中是無法被觸發的(池型別為託管池),在REF裝置中會觸發記憶體讀寫違例。為何HAL無法觸發原因不明,可能資料寫入視訊記憶體後硬體會忽略這個錯誤,必定REF是用來除錯的而HAL不是。

    由於本人也是剛剛開始學習D3D,以上如果存在描述性或概念性錯誤,歡迎指正。 ---------------------  作者:不若人生一場醉  來源:CSDN  原文:https://blog.csdn.net/bluekitty/article/details/6068093  版權宣告:本文為博主原創文章,轉載請附上博文連結!