為什么要介紹VertexHelper(頂點(diǎn)幫助器)這個(gè)類利花。他在UGUI中起到了至關(guān)重要的地位。當(dāng)然不了解這個(gè)類暇赤,對(duì)于使用UGUI沒有任何影響摹迷。他只是看懂UGUI源碼的一個(gè)基礎(chǔ)。不看點(diǎn)源碼孤荣,怎敢說自己精通甸陌。
前言
UGUI是圖形學(xué)渲染和射線檢測(cè)這兩個(gè)技術(shù)結(jié)合的典型例子。圖形學(xué)渲染來處理UI的顯示盐股,射線用來交互钱豁。
今天我們主要看看UI的渲染。
首先介紹一點(diǎn)圖形學(xué)的基礎(chǔ)知識(shí):
1疯汁、所有的渲染對(duì)象都是由網(wǎng)格(Mesh)構(gòu)成牲尺,Mesh的繪制單位是圖元(點(diǎn)、線幌蚊、三角形)谤碳。意思也就是說所有的游戲?qū)ο蠖际窃诶L制一些點(diǎn)、線溢豆、三角形的集合蜒简。
具體是如何一步一步顯示到屏幕上的,可以看之前的一篇博文(實(shí)時(shí)渲染(第四版)_第2章|圖形渲染管線總結(jié)):http://www.reibang.com/p/2d8eeec9d0ef
2漩仙、頂點(diǎn)數(shù)據(jù)中最主要的是位置搓茬,顏色,紋理坐標(biāo)队他,法線等卷仑。也就是說頂點(diǎn)中保存著其位置、顏色麸折、紋理坐標(biāo)系枪、法線信息等。
3磕谅、貼紋理是指,將一張紋理(可以稱為圖片)雾棺,根據(jù)紋理坐標(biāo)膊夹,貼在模型上面。就好比同一個(gè)模型人捌浩,穿上了不同的衣服放刨。紋理坐標(biāo)指的是根據(jù)坐標(biāo)將圖片信息覆蓋在Mesh表面,就相當(dāng)于尸饺,柚子就貼在手腕處进统,褲子就貼在腿上助币。
正文
UGUI提供了我們自己構(gòu)建頂點(diǎn)、三角形的類螟碎,那就是VertexHelper類眉菱。通過這個(gè)類,我們可以創(chuàng)建頂點(diǎn)掉分,構(gòu)成三角形俭缓,填充到一張mesh上,然后用MeshRenderer渲染到屏幕上酥郭,實(shí)際上我們可以直接操作Mesh類添加頂點(diǎn)华坦、三角形等操作,這里的vertexHelper只是UGUI與Mesh之間的一座橋梁不从。
實(shí)踐
接下來 我們嘗試用這種辦法在空物體上畫出一張image圖片惜姐。
首先在Unity中添加一個(gè)空對(duì)象,命名Image椿息,Image對(duì)象需要添加MeshFilter組件歹袁,用來添加Mesh,還需要添加MeshRenderer組件撵颊,用來渲染Mesh宇攻,使其能夠在屏幕中顯示。
創(chuàng)建CreateImage.cs腳本倡勇,并掛載在Image上逞刷。
在腳本中添加Create函數(shù),并有vertexHelper構(gòu)造4個(gè)頂點(diǎn)(矩形):
VertexHelper vp = new VertexHelper();
vp.Clear();
//這里采用的添加頂點(diǎn)函數(shù)妻熊,函數(shù)參數(shù)分別對(duì)應(yīng)了頂點(diǎn)位置夸浅,頂點(diǎn)顏色,紋理坐標(biāo)
vp.AddVert(new Vector3(0, 0, 0), Color.red, new Vector2(0, 0));
vp.AddVert(new Vector3(0, 1, 0), Color.green, new Vector2(0, 1));
vp.AddVert(new Vector3(1, 1, 0), Color.blue, new Vector2(1, 1));
vp.AddVert(new Vector3(1, 0, 0), Color.cyan, new Vector2(1, 0));
接下來扔役,我們用4個(gè)頂點(diǎn)構(gòu)造出矩形的兩個(gè)三角形:
vp.AddTriangle(0, 1, 2);
vp.AddTriangle(2, 3, 0);
我們知道矩形最少是由兩個(gè)三角形構(gòu)成的帆喇,當(dāng)然我們可以構(gòu)造更多的三角形去顯示一個(gè)矩形,但是這樣不僅顯得多余亿胸,而且對(duì)于計(jì)算機(jī)來說計(jì)算量就會(huì)上升坯钦。同時(shí)我們要注意:
Unity默認(rèn)是只渲染物體的正面,背面是不渲染的侈玄。這里就涉及到構(gòu)造三角形的順序婉刀。在Unity中以順時(shí)針方向構(gòu)造三角形,這個(gè)三角形就是正面序仙,就被會(huì)參與渲染的計(jì)算突颊,逆時(shí)針就是背面,最終不會(huì)顯示到屏幕上。
如何看三角形是順時(shí)針還是逆時(shí)針呢律秃。從構(gòu)造三角形的三個(gè)頂點(diǎn)順序(A爬橡、B、C)棒动,第一個(gè)頂點(diǎn)A為基準(zhǔn)糙申,然后指向第二個(gè)頂點(diǎn)B劃線AB,這根線沿著第二個(gè)頂點(diǎn)B到第三個(gè)頂點(diǎn)C的連線BC掃描迁客,掃描的方向是順時(shí)針即為正面郭宝,逆時(shí)針即為背面(當(dāng)然這個(gè)規(guī)定只是Unity的規(guī)定,其他地方要看所用的圖形接口是如何規(guī)定的)掷漱。
接下來粘室,我們填充到一張Mesh上,并將這個(gè)Mesh賦值為空物體Image的MeshFilter上卜范。
meshFilter = this.GetComponent<MeshFilter>();
Mesh mesh = new Mesh();
vp.FillMesh(mesh);
meshFilter.mesh = mesh;
然后我們運(yùn)行游戲:
可以看到有一個(gè)紫色的方塊從無到有衔统。可能有小伙伴就有疑問了海雪,創(chuàng)建的頂點(diǎn)不是紫色的啊锦爵,這是因?yàn)镸eshRender渲染時(shí)候無材質(zhì)的默認(rèn)顏色。在來看看官方的解釋:
意思就是大部分的shder都不會(huì)顯示頂點(diǎn)顏色奥裸,用一個(gè)可以顯示頂點(diǎn)顏色的shader比如险掀, partice shader去觀察頂點(diǎn)顏色。
這時(shí)候隨便用partice下的shader創(chuàng)建一張材質(zhì)湾宙,賦給meshrender樟氢,再運(yùn)行一遍就可以看到頂點(diǎn)顏色了。
頂點(diǎn)效果就出來了:
4個(gè)頂點(diǎn)的顏色是已知的侠鳄,中間的顏色是插值得到的埠啃。具體原理還是在上文鏈接中有詳細(xì)介紹。
當(dāng)然我們也可以用Material中的顏色或者一張圖片伟恶,給mesh貼上紋理碴开,就相當(dāng)于給Mesh穿上純色或者有圖案的衣服。全部代碼如下:
private MeshFilter meshFilter;
private MeshRenderer render;
public Texture tex;
void Start()
{
meshFilter = this.GetComponent<MeshFilter>();
render= this.GetComponent<MeshRenderer>();
CreateAImage();
}
void CreateAImage()
{
VertexHelper vp = new VertexHelper();
vp.Clear();
//這里采用的添加頂點(diǎn)函數(shù)博秫,函數(shù)參數(shù)分別對(duì)應(yīng)了頂點(diǎn)位置潦牛,頂點(diǎn)顏色,紋理坐標(biāo)
vp.AddVert(new Vector3(0, 0, 0), Color.red, new Vector2(0, 0));
vp.AddVert(new Vector3(0, 1, 0), Color.green, new Vector2(0, 1));
vp.AddVert(new Vector3(1, 1, 0), Color.blue, new Vector2(1, 1));
vp.AddVert(new Vector3(1, 0, 0), Color.cyan, new Vector2(1, 0));
vp.AddTriangle(0, 1, 2);
vp.AddTriangle(2, 3, 0);
Mesh mesh = new Mesh();
vp.FillMesh(mesh);
meshFilter.mesh = mesh;
//設(shè)置顏色或者紋理(這里的設(shè)置會(huì)覆蓋Mesh的顏色)
//想象你穿衣服是不是就把你的膚色蓋著了
//render.material.color = Color.red;
render.material.mainTexture = tex;
}
最終效果:
舉一反三:
想象一下圓挡育,他同樣是有三角形來構(gòu)成的罢绽,我們可以用10個(gè)三角形構(gòu)成一個(gè)圓,也可以用1000個(gè)三角形構(gòu)成静盅。下面我們看看三角形數(shù)量有什么差別。
直接上主要代碼:
void CreateCircle()
{
VertexHelper toFill = new VertexHelper();
toFill.Clear();
//首先添加圓心
toFill.AddVert(new Vector3(0, 0, 0), Color.white, new Vector2(0.5f, 0.5f));
//計(jì)算單位三角形的角度
float theta = 2 * Mathf.PI / triCount;
for (int i = 0; i < triCount; i++)
{
//玩的特殊的,頂點(diǎn)顏色都不一樣
Color color = Color.Lerp(Color.blue, Color.red, (float)i / (triCount-1));
//計(jì)算每個(gè)頂點(diǎn)的位置
float X = Mathf.Sin(2 * Mathf.PI-i * theta);
float Y= Mathf.Cos(2 * Mathf.PI-i * theta);
//radius為半徑
toFill.AddVert(new Vector3(X*radius, Y*radius, 0), color, new Vector2(X, Y));
}
//添加三角形
for (int i = 1; i < triCount; i++)
{
toFill.AddTriangle(0, i, i + 1);
}
toFill.AddTriangle(0, triCount, 1);
Mesh mesh = new Mesh();
toFill.FillMesh(mesh);
meshFilter.mesh = mesh;
}
看看效果:
上面分別是10面和1000面的效果蒿叠。
實(shí)際上36個(gè)三角形已經(jīng)可以構(gòu)造出很圓的圓形了明垢。大量的三角形渲染會(huì)增加GPU負(fù)擔(dān)。這也是在游戲開發(fā)中市咽,美術(shù)為什么要限制模型的頂點(diǎn)與三角形數(shù)量的原因痊银。
我們還可以搞點(diǎn)不一樣的。想想下面是如何實(shí)現(xiàn)的施绎。
小結(jié)
知識(shí)點(diǎn):了解VertexHelper的用法溯革。VertexHelper有助于我們理解UGUI源碼。而且我們熟悉了VertexHelper的用法后谷醉,甚至可以隨心所欲的制作出獨(dú)特的UI致稀。