目錄數組 |
1 渲染事物微信 2 建立頂點網格app 3 建立Mesh框架 4 生成附加頂點數據性能 |
本文主要內容:學習
一、建立一個點陣網格測試
二、用協程分析點陣網格的位置flex
三、用三角形定義表面編碼
四、自動生成法線url
五、增長紋理座標和切線
在本教程中,咱們將建立一個由頂點和三角形組成的簡單網格。
本教程假設你已經熟悉Unity Scripting的基本知識了。若是不清楚的能夠看 時鐘 的章節學習Unity的基礎知識。而 構建分形 的章節裏也提供了協程的基本介紹。
這個章節的示例是用Unity5.0.1製做的,可是能夠向上兼容更高的版本。
本教程是CatLikeCoding系列的一部分,原文地址見文章底部。「原創」標識意爲原創翻譯而非原創教程。
(複雜的外表下面是簡單的幾何學)
1 渲染事物
Unity是基於mesh去作渲染的,也就是說你想在Unity裏看見東西的話,就必需要使用mesh。它能夠來自於其餘軟件製做的3D模型進行導入,能夠是由代碼動態生成出來的,也能夠是一個sprite、UI元素或者是粒子系統,這些通通都是要用到mesh的,就連一些屏幕的後處理特效都須要使用mesh來渲染。
因此,那麼到底Mesh是什麼呢?從概念上講,mesh是圖形硬件用來繪製復瑣事物的的框架。它至少包含一個頂點集合(這些頂點是三維空間中的一些座標,)以及鏈接這些點的一組三角形(最基本的2D形狀)。這些三角形集合在一塊兒就構成任何mesh所表明的表面形狀。
因爲三角形是平的,是直線的邊,因此它們能夠用來完美地顯示平面和直線的事物,就好比一個立方體的表面。而曲面或圓曲面只能用許多小三角形來逼近的模擬。若是三角形足夠小(好比小於一個像素),那麼你就看不出來這是一個近似的模擬值。但一般,這是在當下的硬件設備上是不可能的,由於性能不容許。因此你看到的3D物體表面老是會出現必定程度的鋸齒狀。
(Unity的默認的 膠囊,立方體,球體的陰影與線框展現)
怎麼顯示 線框模式?(Wireframe)
在Scene的視窗下面有個下拉菜單,點擊以後能夠在Scene的視窗裏看到不一樣的渲染模式。
若是你想用一個GameObject展現一個3D的模型,那麼它必需要兩個components才能夠。第一個是mesh filter,它決定了你想展現那個mesh;第二個是mesh renderer,它決定了你應該如何渲染mesh,好比使用什麼材質球,是否接受陰影或者投影等等。
(Unity默認的 cube 物體)
爲何materials是複數的?
mesh renderer能夠有多個materials。這主要用於繪製具備多個獨立三角形集的mesh,稱爲subMesh。這些subMesh來自於導入的3D模型,本教程將不討論這些內容。
經過調整mesh的material,能夠徹底改變mesh的表現。Unity的默認材料是純白色的,你能夠經過 _Assets Create Material來建立一個新的材質球,並將其拖到遊戲對象上來替換它。新的材質球使用的是Unity的標準着色器,它會開放一組設置參數來讓你調整不一樣的視覺效果。
向mesh中添加大量細節的一個快速方法是提供一個albedo maps。這是一個紋理貼圖,用來表示一個材質球的基本顏色。紋理貼圖只有長和寬2個維度,而mesh每每是一個三維物體,因此要達到這個目的,咱們須要知道如何將這個紋理投射到mesh的三角形上。這實際上是經過向頂點添加二維紋理座標來完成的。
紋理空間的兩個維度被稱爲U和V,這就是爲何它們被稱爲UV座標。這些座標一般位於(0,0)和(1,1)之間,覆蓋整個紋理圖。根據紋理設置,該範圍外的座標要麼被收緊,要麼致使tiled。
(一個用來測試Unity mesh的UV測試紋理)
2 建立頂點網格
因此除了導入3D模型,以及使用Unity默認的以外,咱們怎麼建立本身的Mesh呢。這裏咱們就開始生產一些簡單的規則的網格試一試。生成的網格將由單位長度的方形Tiled(四邊形)組成。
建立一個新的C#腳本,並將其轉換爲具備水平和垂直大小的網格組件。
爲何要在代碼里加 using System.Collections; ?
這段代碼裏並不須要這個using,可是稍後咱們須要使用到coroutine。
當咱們將這個組件添加到遊戲對象中時,咱們也須要給它一個mesh filter 和一個 mesh renderer。這裏有個快捷的方式,向咱們的類添加一個屬性,以便使Unity自動爲咱們添加它們。
如今你能夠建立一個新的 空的game object,將grid 組件添加到它上面,它就會自動添加其餘兩個組件。設置mesh renderer 的材質,讓mesh filter保持 mesh 未引用狀態。這裏咱們把grid的大小設爲10和5。
(grid object)
當腳本Awake的時候,咱們就讓它自動生成這些網格。Awake是在Unity Editor點擊播放的時候調用的。
首先咱們須要先知道全部頂點的位置,因此能夠把三角形留到後面再處理。保存頂點,就須要持有一個三維的矢量的陣列來存儲點,頂點的數量則取決於grid的大小。咱們須要一個頂點在每一個四邊形的四個角上,但相鄰的四邊形能夠共享相同的頂點。鑑於此,咱們多定義一個維度的長度,好過每一個頂點都發生冗餘。
即 一個2X4的矩形,咱們其實只要定義3X5的頂點便可,以下。
(#x+1)(#y+1)
頂點維度定義以下:
頂點定義了以後,它只是數據,並不能直觀的看到,這裏咱們可讓這些頂點可視化,這樣咱們就能夠檢查它們的位置是否正確。而方法就是經過添加一個OnDrawGizmos方法,並在場景視圖中爲每一個頂點繪製一個小的黑色球體。
(gizmo)
在遊戲模式下,咱們只看到了一個黑點的球體。這是由於咱們尚未給頂點設置位置,因此它們重疊在一塊兒了。咱們必須遍歷全部的位置,給它們設置好座標。
(grid 的 頂點集合)
如今咱們能看到了頂點,可是它們放置的順序是不可見的。這裏有兩個方法,第一咱們能夠用不一樣的顏色來區分,第二咱們也能夠經過使用協程來減緩這一輩子成的過程。這就是爲何前面的腳本中包括使用System.Collection的緣由。
(頂點集合出現的順序)
3 建立Mesh
到這裏咱們已經能知道頂點的位置以及順序是正確的了,那麼咱們就能夠處理實際的mesh了。除了在咱們本身的組件中保存對它的引用以外,還必須將它分配給mesh filter才行。一旦處理好了頂點,就能夠把它們交給網格了。
(mesh在運行時出現了)
這樣,咱們就能從mesh Filter裏看到mesh的實例了。可是咱們還不能在遊戲裏看到它,由於咱們尚未給它定義三角形。
三角形是經過一系列頂點索引來定義的。因爲每一個三角形有三個點,三個連續的索引就描述了一個三角形。讓咱們從一個三角形開始。
咱們如今有一個三角了,可是要注意,這裏咱們使用的三個點是一條直線上的。這會致使程序產生一個不可見的退化三角形,其實就是一條直線。這裏前兩個頂點很好,可是最後一個咱們應該跳到下一行的第一個頂點纔對。
這確實給了咱們一個三角形,但它只從一個方向可見。在這種狀況下,只有當觀察到Z軸的相反方向時,它纔是可見的。所以,你可能須要旋轉視圖的方向才能看到它。
三角形的哪一邊可見是由它的頂點順序的時鐘方向決定的。默認狀況下,若是它們按順時針方向排列,則三角形被認爲是前向的和可見的,逆時針方向的三角形會被丟棄。另外咱們也不會花時間渲染對象的內部,由於這些東西一般不會被看到。
(兩種時鐘方向的三角形)
所以,當咱們向下看Z軸時,要使三角形出現,咱們必須改變其頂點被遍歷的順序。咱們能夠經過交換最後兩個索引來實現。
(第一個三角形)
如今有了一個三角形了,位置咱們網格的第一塊瓷磚的一半位置。爲了能覆蓋整個瓷磚,咱們所須要的第二個三角形。
(由兩個三角形組成的正方形)
因爲這些三角形共享兩個頂點,因此咱們能夠將其簡化爲四行代碼,只顯式地提到每一個頂點索引一次。
(第一個正方形)
這樣每一個三角形的頂點都用一行代碼,效率過低了,咱們能夠經過將整個第一行瓷磚轉換成一個循環來建立整個第一行。但按照咱們如今的代碼,在遍歷頂點和三角形索引時,咱們必須同時追蹤這兩個數據指標才行。這裏咱們能夠把建立頂點的協程去掉,而後加載建立tiled的表現上。
表明頂點的小圓點如今當即出現了,全部的三角形都在短暫的等待後當即出現。要看到這些塊一個一個地出現,咱們必須在每次迭代以後更新mesh,而不是隻在循環以後更新才行。
如今,經過將單循環轉換爲一個雙循環來填充整個grid 。
請注意,移動到下一行的時候,須要將頂點索引遞增一下,由於每一行有一個頂點比Tiles的索引多一個。
正如你所看到的,整個網格如今充滿了三角形,一次一行。若是你對此該效果滿意了,就能夠刪除全部協程代碼,mesh會被當即建立出來的。
下面給一下完成的代碼展現:
爲何不用正方形做爲基礎繪製單元?
當咱們建立一個扁平的矩形平面的時候,咱們只須要兩個三角形就足夠了。這是絕對沒問題的。但更多更復雜的結構的由最基礎的幾何面來定義才能更好的控制和表現。
4 生成附加頂點數據
咱們目前實現的方案是在一種極端的狀況下完成的,由於咱們的mesh沒有給出任何的法線。默認的法線方向是 (0, 0, 1) ,但這不必定是咱們想要的。
法線是如何做用的?
法線是一個垂直於表面的矢量。咱們老是使用單位長度的法線,並用它們指向表面的外部,從而區分表面的內外。
法線還能夠用來肯定光線擊中表面的角度(若是有的話)。它的具體使用方式取決於shader。
因爲三角形老是在一個平面上的,因此不須要提供的單獨的法線信息。可是,咱們能夠經過提供法線來達到一些「做弊」行爲。在現實中,頂點是沒有法線的,但三角形有。可是,經過在頂點上附加自定義法線並在它們之間進行三角插值,就能夠僞裝咱們有一個平滑的曲面而不是一堆平坦的三角形。這種錯覺是可以欺騙普通人的感官的,可是一些Mesh的銳利輪廓可能下降這一表現。
法線是每一個頂點單獨定義的,因此咱們必須填充另一個向量數組。或者,咱們能夠要求網格根據其三角形來肯定法線自己。此次咱們偷下懶。
法線是怎麼計算的?
Mesh.RecalculateNormals 計算每一個頂點的法線是經過計算哪些三角形與該頂點相連,先肯定這些平面三角形的法線,對它們進行平均,最後對結果進行歸一化處理。
(沒有法線的vs有法線的表現)
接下來是UV座標。你確定已經在想了,爲何它使用的材料具備albedo紋理,Mesh當前仍是隻有一個顏色呢。這是有緣由的,由於若是咱們本身不提供UV座標,那麼它們都是默認的零。
要使紋理適合咱們的整個網格,只需將頂點的位置除以網格尺寸便可。
(不正確的UV座標, clamping vs. wrapping 紋理.)
紋理如今顯示了,但它沒有覆蓋整個mesh。它的確切外觀取決於紋理的包裝模式是設置爲clamp 仍是repeat。這是由於咱們目前正在用整數除以整數,這會產生另外一個整數。爲了在整個網格中得到零到一之間的正確座標,咱們必須確保咱們使用的是浮點數。
紋理如今投射到整個mesh上了。因爲咱們已經將網格的大小設置爲10乘5,紋理會顯示爲水平拉伸。這能夠經過調整材質的貼圖設置來抵消。經過將其設置爲(2,1),U座標將加倍。若是紋理被設置爲重複,那麼咱們將看到它的兩個方形瓦片。
(正確的UV座標, tiling 1,1 vs. 2,1.)
另外一種向表面添加更明顯細節的方法是使用法線紋理。這個紋理上包含以顏色編碼的法線向量。將它們應用到表面會產生比單用頂點法線更詳細的光效應。
(凹凸不平的表面,使金屬產生戲劇性的效果)
但只將這種材質球應用到咱們的網格中會產生凸起,是不正確的。咱們須要在網格中添加切線向量來正確地定位它們。
切線是如何做用的?
法線映射是在切線空間中定義的。這是一個在物體表面流動的三維空間。這種方法容許咱們在不一樣的地方和方向應用相同的法線映射。
表面法線在這個空間上是向上的,可是哪條路是正確的呢?這是由切線定義的。理想狀況下,這兩個矢量之間的夾角爲90°。它們的交叉積產生定義三維空間所需的第三個方向。
在現實中,角度每每不是90°,但結果仍然夠好。因此切線是一個三維向量,可是Unity實際上使用了一個4D向量。它的第四個份量老是−1或1,用於控制第三切線空間維的方向--前向或後向。這方便對法線映射進行鏡像,這種映射常常用於像人這樣具備雙邊對稱性三維模型中。
Unity的着色器執行此計算的方式要求咱們使用−1。
由於咱們是一個平面,因此全部的切線都指向相同的方向,也就是右邊。
(平坦的表面僞裝凹凸不平)
如今,你已經知道了如何建立一個簡單的mesh,並使它看起來像是使用了很複雜的材質。mesh須要頂點位置和三角形,一般也須要UV座標--最多四組(常常是切線)。其實你還能夠添加頂點顏色,雖然Unity的標準着色器不使用它們。但你能夠在本身建立的着色器裏使用這些顏色,但這是另外一個教程了。
若是你對這個章節的熟練程度滿意了,就能夠轉到 圓角立方體 教程了。
本文翻譯自 Jasper Flick的系列教程
原文地址:
https://catlikecoding.com/unity/tutorials
本文分享自微信公衆號 - 壹種念頭(OneDay1Idea)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。