处理顶点——使用索引移除冗余顶点
問(wèn)題
你要繪制的三角形共享了很多頂點(diǎn),如圖5-7所示。
圖5-7 可以從使用索引中受益的結(jié)構(gòu)
如圖5-7所示的八個(gè)三角形在使用TriangleList的情況下需要8*3 = 24個(gè)頂點(diǎn),從這個(gè)圖中可以看到實(shí)際上只有9個(gè)獨(dú)立的頂點(diǎn),所以其余15個(gè)頂點(diǎn)會(huì)浪費(fèi)顯卡的內(nèi)存,帶寬和處理能力。
解決方案
好的辦法是將這9個(gè)獨(dú)立頂點(diǎn)存儲(chǔ)在數(shù)組中并將這個(gè)數(shù)組傳遞到顯卡。然后創(chuàng)建一個(gè)包含24個(gè)數(shù)字的集合,作為這9個(gè)頂點(diǎn)的引用。圖5-8左邊是包含24個(gè)頂點(diǎn)的大集合,右邊是包含9個(gè)頂點(diǎn)和24個(gè)索引的小集合,注意每個(gè)索引都對(duì)應(yīng)一個(gè)頂點(diǎn)。
圖5-8 由24個(gè)頂點(diǎn)繪制的8個(gè)三角形(左)或24個(gè)指向9個(gè)頂點(diǎn)的索引(右)
這樣做可以帶來(lái)很大的益處。因?yàn)樗饕皇菙?shù)字,所以相對(duì)于包含一個(gè)Vector3,一個(gè)顏色,一個(gè)紋理坐標(biāo),可能還有其他信息的頂點(diǎn)來(lái)說(shuō),索引是很小的。這可以節(jié)省顯存和帶寬。而且顯卡上的vertex shader只需處理9個(gè)頂點(diǎn)而不是24個(gè),當(dāng)處理由上千個(gè)三角形構(gòu)成的復(fù)雜結(jié)構(gòu)時(shí)這樣做的好處是非常明顯的。
每個(gè)索引指向9個(gè)頂點(diǎn)之一,所以三角形實(shí)際上是基于索引繪制的。使用TriangleList時(shí),你需要24個(gè)索引用來(lái)繪制8個(gè)三角形。
工作原理
首先你需要定義獨(dú)立頂點(diǎn)的數(shù)組。這個(gè)數(shù)組對(duì)應(yīng)圖5-7中的結(jié)構(gòu):
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); }現(xiàn)在你需要定義使用哪個(gè)頂點(diǎn)創(chuàng)建三角形,每個(gè)三角形需要三個(gè)索引。
接下來(lái),你將創(chuàng)建索引集合對(duì)應(yīng)這些頂點(diǎn)。首先添加一個(gè)數(shù)組保存這些索引:
private int[] indices;下面的方法將索引添加到新定義的數(shù)組中:
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; }我將代碼按每三個(gè)索引一組分成代碼塊,每個(gè)塊對(duì)應(yīng)一個(gè)三角形,這個(gè)集合也對(duì)應(yīng)圖5-7中的灰色數(shù)字。例如,左上角的三角形由索引12至14定義,對(duì)應(yīng)頂點(diǎn)3,6,7。
注意:三角形頂點(diǎn)是按順時(shí)針?lè)较蚨x的,要知道為什么可見(jiàn)教程5-6. 別忘了調(diào)用這個(gè)方法,例如在Initialize方法中: InitIndices();
定義了頂點(diǎn)和索引,你就可以將這些數(shù)據(jù)發(fā)送到顯卡繪制三角形了:
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倍,表明所有頂點(diǎn)位置都乘以2。這樣網(wǎng)格會(huì)從0擴(kuò)展到4,關(guān)于世界矩陣更多的信息可見(jiàn)教程4-2。
第二第二行代碼使用DrawUserIndexedPrimitives方法表示你使用索引數(shù)組繪制三角形。你需要聲明頂點(diǎn)數(shù)組和需要繪制多少個(gè)頂點(diǎn)以及從哪個(gè)頂點(diǎn)開(kāi)始繪制。接下來(lái),需要指定包含索引的數(shù)組和從哪個(gè)索引開(kāi)始繪制。最后一個(gè)參數(shù)指定繪制多少個(gè)圖元,本例中圖元是三角形。
注意:這個(gè)方法支持教程5-1中討論過(guò)的所有圖元類型。例如,可以使用索引繪制 TriangleStrip或LineList,但是,使用索引繪制點(diǎn)是毫無(wú)用處的。
何時(shí)使用索引?
使用索引不見(jiàn)得都能優(yōu)化性能,所以在使用索引前,你應(yīng)該首先不使用索引繪制三角形。
有些情況中使用索引反而會(huì)使性能降低。例如,有五個(gè)三角形并不共享一個(gè)頂點(diǎn)。不使用索引,你需要使用15個(gè)頂點(diǎn),而使用索引,你仍要定義15個(gè)頂點(diǎn),因?yàn)檫@些頂點(diǎn)是獨(dú)立的!而且還要定義15個(gè)索引,每個(gè)索引對(duì)應(yīng)一個(gè)頂點(diǎn),這種情況下,傳遞到顯卡的數(shù)據(jù)反而變多了!
作為一個(gè)規(guī)律,你可以將(獨(dú)立頂點(diǎn)的數(shù)量) 除以(三角形的數(shù)量)。如果沒(méi)有共享頂點(diǎn),那么這個(gè)值是3,如果有共享,這個(gè)值會(huì)小于3。這個(gè)值越小,,使用索引提升的性能就越多。例如在圖5-7中,這個(gè)值是9/8 = 1.125,這表示使用索引可以極大地提升性能。
代碼
前面已經(jīng)包含了所有的代碼,這里我就不重復(fù)寫(xiě)了。
轉(zhuǎn)載于:https://www.cnblogs.com/AlexCheng/archive/2011/01/25/2120118.html
總結(jié)
以上是生活随笔為你收集整理的处理顶点——使用索引移除冗余顶点的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 79式冲锋枪的升级改造
- 下一篇: jquery 获得鼠标指针 X/Y 值