在前面的文章有稍微介紹了XNA的XNA Rendering Pipeline
現在,讓我們開始從頭了解吧!!
(也許有人會好奇,怎麼會要講這個...因為這個部分是很重要的,所以我才特別在往回寫,熟悉Vertex buffer與index buffer,在後面處理一些模型的幾何會很有幫助)
使用環境:
Visual Studio C# 2008任意版本
XNA 3.1
新增完畢XNA GS(game studio,以後簡稱CS) 3.1的專案以後,開啟Game1.cs的程式碼
在rendering pipeline中,我們知到頂點的資訊(包含position、normal、texture coordniate等),都是被儲存在Vertex Buffer中,然後再送進Vertex Processing處理一些轉換(包含將Local Coordniate轉換到World Coordniate等)。
而我們第一步就是要建立Vertex Buffer!!
宣告一個變數Vertex Buffer:
VertexBuffer mVertexBuffer;
(這邊建議讀者命名方式使用"匈牙利命名法則")
接下來宣告幾項變數:
- VertexDeclaration mDeclaration;
-
說明: 我們需要告知Pipeline現在我們的頂點包含哪些資料。(像是包含位置跟顏色等)
- VertexPositionColor[] mVertex;
-
說明: 宣告頂點,而頂點結構的內容指包含位置和顏色。這邊有多個選擇頂點的結構,像是VertexPositionColor、VertexPositionColorTexture、VertexPositionNormalTexture和VertexPositionTexture四種。
-
VertexPositionColor: 可以宣告頂點位置和頂點顏色。
-
VertexPositionColorTexture: 可以宣告頂點位置、顏色和貼圖座標。
-
VertexPositionNormalTexture: 可以宣告頂點位置、法像量和貼圖座標。
-
VertexPositionTexture: 可以宣告頂點位置和貼圖座標。
- BasicEffect basicEffect;
- 說明: 使用基本的特效,包含一些打光和一些矩陣(View matrix、projection matrix等)
設定完變數以後,接下來就可以設定頂點的資料
在建構子當中,建立頂點資訊,如下
mVertex = new VertexPositionColor[4];
mVertex[0].Position = new Vector3(-1, 1, 0);
mVertex[0].Color = Color.Blue;mVertex[1].Position = new Vector3(-1, -1, 0);
mVertex[1].Color = Color.Red;mVertex[2].Position = new Vector3(1, -1, 0);
mVertex[2].Color = Color.Orange;mVertex[3].Position = new Vector3(1, 1, 0);
mVertex[3].Color = Color.MediumPurple;這邊我們宣告的四個頂點,VertexPositionColor.Position設定頂點位置,是一個三維的座標。
VertexPositionColor.Color設定頂點顏色。
- 設定完畢以後,在Initialize函數中,初始化一些變數和設定一些相關的矩陣。
mDeclaration = new VertexDeclaration(GraphicsDevice, VertexPositionColor.VertexElements);
說明: 告知Pipeline現在的頂點結構,第一個參數傳入現在的GraphicsDevice,第二個參數傳入結構的型態,在面所說的四個頂典型態都會有一個VertexElements的成員,將它設定為那個即可。
mVertexBuffer = new VertexBuffer(GraphicsDevice, VertexPositionColor.SizeInBytes * mVertex.Length, BufferUsage.None);
說明: 建立VertexBuffer,第一個參數為GraphicsDevice,第二個參數設定就是現在Vertex Buffer的大小(取得頂點結構的大小以後,在乘上頂點數量),第三個參數設定Buffer的存取模式。
mVertexBuffer.SetData<VertexPositionColor>(mVertex);
說明: 設定VertexBuffer的頂點資料。
Matrix view = Matrix.CreateLookAt(new Vector3(0, 0, 1), Vector3.Zero, Vector3.Up);
說明: 設定View matrix,第一個參數為Camera的位置,第二個參數為Camera觀察的點,第三個參數為向上的方向,第三個參數用來告知,現在哪邊為上方,如果設定錯誤,可能會看到不是預期想看到的結果。)
Matrix project = Matrix.CreateOrthographic(5, 5, 0, 1);
說明: 設定投影矩陣,這邊使用平行投影。
basicEffect = new BasicEffect(GraphicsDevice, null);
說明: 建立一個BasicEffect的物件。
basicEffect.VertexColorEnabled = true;
說明: 開起頂點顏色
basicEffect.World = Matrix.Identity;
說明: 設定世界矩陣(包含旋轉、平移、縮放,這些稱為世界矩陣)
basicEffect.View = view;
說明: 設定視野矩陣(一般可能會看到一個詞,叫做ModelView matrix,這是因為world matrix可以直接跟view matrix相乘,這結果是相同的)
basicEffect.Projection = project;
說明: 設定投影矩陣。
設定完以上參數以後,接下來我們就可以準備畫出結果了
在Draw的函數中,打入下面程式碼
GraphicsDevice.VertexDeclaration = mDeclaration;
說明: 設定頂點結構
GraphicsDevice.RenderState.PointSize = 10;
說明: 設定頂點的點大小。
GraphicsDevice.RenderState.CullMode = CullMode.None;
說明: 設定Culling Mode,在Rendering pipeline中,先剃除掉看不到的面,這邊是指不開啟Culling,因為每個人設定頂點的方式不同,像是順時鐘設定或是逆時鐘設定等等(像這個範例我就是使用逆時鐘設定頂點),XNA預設是順時鐘為front face,所以我用逆時鐘的方式設定的話,是看不到結果的。
basicEffect.Begin();
basicEffect.CurrentTechnique.Passes[0].Begin();
GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleFan, mVertex, 0, 2);
說明: 將幾何圖形畫出,第一個參數為設定幾何模型的型態,像是點、線、三角形等,第二個參數為頂點的資料,第三個參數起始位置,第四個參數是說現在要畫幾個,第四個參數比較值得注意就是,你需要知道現在你要畫幾個,如果設定錯誤程式就會crush掉。
basicEffect.CurrentTechnique.Passes[0].End();
basicEffect.End();
執行結果如下
使用triangle fan建立的結果
使用Line list結果(GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineList, mVertex, 0, 2))
使用Line Strip結果(GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineStrip, mVertex, 0, 3))
上面三個結果請注意第四個參數。
最後跟大家補充一個填塞的方式,以第一張圖片來說,我們可以看到明明就是指有設定四個頂點,為什麼其他地方沒有設定的他也會有顏色那些!?
原因是因為預設的參數中,填寫模式(Fill mode)為solid所以他會將顏色和點頂內插,當然我們也可以不指定。
只要打入一行指令即可
GraphicsDevice.RenderState.FillMode = FillMode.Point;
FillMode一共有三個選擇
1. 點
2. 網格
3. 填滿
結果如下(使用triangle fan的連結方式)
點
網格
填滿
使用VertexBuffer來繪製簡單的幾何形狀的說明就到此結束..
這邊各位可能會發現我沒有使用到Index Buffer來建立。
沒有使用Index buffer的壞處就是我需要大量的點頂來描述現在的3D物件,而那些頂點,很多都是有可能重複到的!!
像1.4和2.6這兩個點根本就是重複的點,如果我知道連接的方式是怎麼樣的話,那我就可以自己指定連結,就不會使用XNA預設的方式填寫。而這就是Index Buffer的好處。
留言列表