处理顶点——使用索引移除冗余顶点
問題
你要繪制的三角形共享了很多頂點,如圖5-7所示。
圖5-7 可以從使用索引中受益的結構
如圖5-7所示的八個三角形在使用TriangleList的情況下需要8*3 = 24個頂點,從這個圖中可以看到實際上只有9個獨立的頂點,所以其余15個頂點會浪費顯卡的內存,帶寬和處理能力。
解決方案
好的辦法是將這9個獨立頂點存儲在數組中并將這個數組傳遞到顯卡。然后創建一個包含24個數字的集合,作為這9個頂點的引用。圖5-8左邊是包含24個頂點的大集合,右邊是包含9個頂點和24個索引的小集合,注意每個索引都對應一個頂點。
圖5-8 由24個頂點繪制的8個三角形(左)或24個指向9個頂點的索引(右)
這樣做可以帶來很大的益處。因為索引只是數字,所以相對于包含一個Vector3,一個顏色,一個紋理坐標,可能還有其他信息的頂點來說,索引是很小的。這可以節省顯存和帶寬。而且顯卡上的vertex shader只需處理9個頂點而不是24個,當處理由上千個三角形構成的復雜結構時這樣做的好處是非常明顯的。
每個索引指向9個頂點之一,所以三角形實際上是基于索引繪制的。使用TriangleList時,你需要24個索引用來繪制8個三角形。
工作原理
首先你需要定義獨立頂點的數組。這個數組對應圖5-7中的結構:
private void InitVertices() {vertices = new VertexPositionColor[9]; vertices[0]= new VertexPositionColor(new Vector3(0, 0, 0), Color.Red); vertices[1]= new VertexPositionColor(new Vector3(1, 0, 0), Color.Green); vertices[2]= new VertexPositionColor(new Vector3(2, 0, 1), Color.Blue); vertices[3]= new VertexPositionColor(new Vector3(0, 1, -1), Color.Orange); vertices[4]= new VertexPositionColor(new Vector3(1, 1, 0), Color.Olive); vertices[5]= new VertexPositionColor(new Vector3(2, 1, 0), Color.Magenta); vertices[6] = new VertexPositionColor(new Vector3(0, 2, 0), Color.Yellow); vertices[7] = new VertexPositionColor(new Vector3(1, 2, 1), Color.Tomato); vertices[8] = new VertexPositionColor(new Vector3(2, 2, -1), Color.Plum); myVertexDeclaration = new VertexDeclaration(device, VertexPositionColor.VertexElements); }現在你需要定義使用哪個頂點創建三角形,每個三角形需要三個索引。
接下來,你將創建索引集合對應這些頂點。首先添加一個數組保存這些索引:
private int[] indices;下面的方法將索引添加到新定義的數組中:
private void InitIndices() {indices = new int[24]; indices[0] = 0; indices[1] = 3; indices[2] = 1; indices[3] = 1; indices[4] = 3; indices[5] = 4; indices[6] = 1; indices[7] = 4; indices[8] = 5; indices[9] = 1; indices[10] = 5; indices[11] = 2; indices[12] = 3; indices[13] = 6; indices[14] = 7; indices[15] = 3;indices[16] = 7; indices[17] = 4; indices[18] = 4; indices[19] = 7; indices[20] = 5; indices[21] = 5; indices[22] = 7; indices[23] = 8; }我將代碼按每三個索引一組分成代碼塊,每個塊對應一個三角形,這個集合也對應圖5-7中的灰色數字。例如,左上角的三角形由索引12至14定義,對應頂點3,6,7。
注意:三角形頂點是按順時針方向定義的,要知道為什么可見教程5-6. 別忘了調用這個方法,例如在Initialize方法中: InitIndices();
定義了頂點和索引,你就可以將這些數據發送到顯卡繪制三角形了:
basicEffect.World = Matrix.CreateScale(2.0f); basicEffect.View = fpsCam.ViewMatrix; basicEffect.Projection = fpsCam.ProjectionMatrix; basicEffect.VertexColorEnabled = true; basicEffect.Begin(); foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes) {pass.Begin(); device.VertexDeclaration = myVertexDeclaration; device.DrawUserIndexedPrimitives<VertexPositionColor>(PrimitiveType.TriangleList, vertices, 0, 9, indices, 0, 8); pass.End(); } basicEffect.End();除了有兩行代碼,上面的代碼段與教程5-1中的是相同的。第一行代碼將世界矩陣縮放到2倍,表明所有頂點位置都乘以2。這樣網格會從0擴展到4,關于世界矩陣更多的信息可見教程4-2。
第二第二行代碼使用DrawUserIndexedPrimitives方法表示你使用索引數組繪制三角形。你需要聲明頂點數組和需要繪制多少個頂點以及從哪個頂點開始繪制。接下來,需要指定包含索引的數組和從哪個索引開始繪制。最后一個參數指定繪制多少個圖元,本例中圖元是三角形。
注意:這個方法支持教程5-1中討論過的所有圖元類型。例如,可以使用索引繪制 TriangleStrip或LineList,但是,使用索引繪制點是毫無用處的。
何時使用索引?
使用索引不見得都能優化性能,所以在使用索引前,你應該首先不使用索引繪制三角形。
有些情況中使用索引反而會使性能降低。例如,有五個三角形并不共享一個頂點。不使用索引,你需要使用15個頂點,而使用索引,你仍要定義15個頂點,因為這些頂點是獨立的!而且還要定義15個索引,每個索引對應一個頂點,這種情況下,傳遞到顯卡的數據反而變多了!
作為一個規律,你可以將(獨立頂點的數量) 除以(三角形的數量)。如果沒有共享頂點,那么這個值是3,如果有共享,這個值會小于3。這個值越小,,使用索引提升的性能就越多。例如在圖5-7中,這個值是9/8 = 1.125,這表示使用索引可以極大地提升性能。
代碼
前面已經包含了所有的代碼,這里我就不重復寫了。
轉載于:https://www.cnblogs.com/AlexCheng/archive/2011/01/25/2120118.html
總結
以上是生活随笔為你收集整理的处理顶点——使用索引移除冗余顶点的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 79式冲锋枪的升级改造
- 下一篇: HTML转PDF(C#---itexts