Unity UI網格自定義應用

2021-09-12 10:57:00 字數 3447 閱讀 5697

unity ui是unity官方支援的ui框架,在設計上有一定的靈活性和擴充套件性。ugui除了recttransform, canvas,canvasrender稍微底層的元件,主要元件如image,text等都是開源的。

ugui裡面所有可以繪製與響應事件的圖形元件都繼承於graphic。由於基礎元件都支援遮罩層,實際上image,text這些並不直接繼承graphic,而是繼承maskablegraphic。在ugui內部進行graphic網格生成的時候,會去呼叫onpopulatemesh方法。也就是說,當子類需要自定義網格時,只需要過載onpopulatemesh這個方法就可以了。下面是該方法的宣告:

public abstract class graphic

[obsolete("use onpopulatemesh(vertexhelper vh) instead.", false)]

protected virtual void onpopulatemesh(mesh m)

protected virtual void onpopulatemesh(vertexhelper vh)

}

除了graphic子類可以自定義網格外,還可以通過imeshmodifier介面來實現。比如一些效果元件outline, shadow等,就是通過這種方式實現的。下面是imeshmodifier介面的宣告:

public inte***ce imeshmodifier

可以看出modifymesh和onpopulatemesh非常類似,如出一轍。事實上,ugui在執行完onpopulatemesh之後,會檢測同乙個gameobject上有沒有實現了imeshmodifier介面的元件,有的話就會呼叫modifymesh方法的實現。值得注意的是,元件的掛載是有順序的,也就是當同時有多個imeshmodifier元件時,會按照掛載順序依次執行modifymesh。

在某些情景下,我們需要乙個ui層去接受事件,又不需要顯示這一層ui。針對這種情況,一種簡單的做法是掛載乙個空image,將alpha設為0。但是這種做法有個缺陷,會造成無用的重複繪製,在一些手機平台上,會產生無用的額外的開銷。最好的辦法是自定義乙個graphic元件,但又不進行渲染。這可以通過自定義網格來實現,也就是清除網格。

在quizdom專案裡面,uiblank就實現了這麼乙個機制:

[addcomponentmenu("ugui/uiblank", 1)]

public class uiblank : maskablegraphic

protected override void onpopulatemesh(vertexhelper tofill)

}

值得注意的是,在建構函式裡面申明了uselegacymeshgeneration為false,也就是說不用obsolete生成方法,只需要覆寫onpopulatemesh就可以了。方法裡面很簡單,該行**就是把網格頂點資訊清除。

在處理人物頭像的時候,往往需要頭像顯示成圓形的,而頭像本身的是方的。在ugui中,可以採用mask元件實現這個功能,具體是給元件乙個圓形白底不透明的遮罩。不幸的是,這種方式有比較大的缺陷。mask元件是採用模板快取去實現的,意味著mask下面的ui跟mask之外的ui不能進行batch操作。這樣割裂了原本一體的ui介面,導致了drawcall的增加。由於頭像可能會比較多,mask的開銷會很明顯。如下圖所示,乙個mask頭像就占用了3個drawcall(也就是batch數)。

如果採用圓形網格的形式,就可以避免這種問題,只是會增加網格的記憶體占用。相比較而言,少量的記憶體換取drawcall數的下降,還是值得的。

circleimage指令碼通過繼承image,覆寫onpopulatemesh的方式來實現圓的繪製。下面是簡化的**,基本思想是將圓等分成segements個扇形,以三角形近似扇形來實現的。等分得越多,越接近於圓。

protected override void onpopulatemesh(vertexhelper vh)

var ********count = segements * 3;

for (int i = 0, vidx = 1; i < ********count - 3; i += 3, vidx++)

vh.add********(verticecount - 1, 0, 1);

}

採用circleimage的drawcall如下所示,只占用本身的繪製開銷,drawcall為1.

ugui官方text並不支援**混排。一種**混排的方式是將文字和合在一張圖集上,但text一般是動態字型,這種方式不太適合;另一方面,也不利於ugui的batch操作,會導致drawcall增加。一種可行的思路是,通過修改text網格,給預留空間,然後將補上空缺的位置。

具體實現,看下面**。值得注意的地方是,setverticesdirty方法。當該方法被呼叫時,說明網格需要重新生成,下一步需要執行onpopulatemesh方法。

public override void setverticesdirty()

updatequadimage的邏輯是,通過正規表示式去匹配原有文字中的標籤,然後用image子物體去替換它們,具體**可以參考附件工程。linkimagetext的實現,有一定侷限性,它只支援單行文字。

protected override void onpopulatemesh(vertexhelper tofill)}}

var offset = offsetx;

if (alignment == textanchor.lowerleft || alignment == textanchor.middleleft ||

alignment == textanchor.upperleft)

else if (alignment == textanchor.lowercenter || alignment == textanchor.middlecenter ||

alignment == textanchor.uppercenter)

else if (alignment == textanchor.lowerright || alignment == textanchor.middleright ||

alignment == textanchor.upperright)

for (int i = 0; i < tofill.currentvertcount; i++)

for (var i = 0; i < m_imagesvertexindex.count; i++)

}

在這個實現中,利用了父類text的網格生成結果,在這個基礎上進行文字和位置的調整。這個主要由於unity text生成規則並不開放,只提供textgenerator類可以呼叫。text內部會使用構造好的textgenerator進行生成。這裡就不再展開。參考工程效果圖如下:

unity ui框架的可擴充套件性相對ngui來說要好一點,合理利用擴充套件介面,可以不侷限於現有的ui元件,同時也可以提高ui的渲染效率。本文針對網格自定義這一點,列舉了一些應用場景和優化的點,主要供大家擴充套件思路。

Unity 畫自定義網格

有時候需要程式化動態生成網格 例如骨骼 先3d建乙個模型,然後匯入到unity 除錯檢視mesh.vertices 的排列,用excel幾下索引。然後賦值 的時候記得按照 123456 的順序排列,因為unity就是這樣匯入的貌似,否則畫的網格不正確,最後記得重新計算下法線 這裡不需要設定矩陣 因為...

32EasyUI 資料網格 自定義分頁

資料網格 datagrid 內建乙個很好特性的分頁功能,自定義也相當簡單。在本教程中,我們將建立乙個資料網格 datagrid 並在分頁工具欄上新增一些自定義按鈕。請記得,設定 pagination 屬性為 true,這樣才會生成分頁工具欄。var pager tt datagrid getpage...

MySQL自定義函式應用

mysql mysql delimiter mysql mysql create function myfunction in string varchar 255 in find str varchar 20 in repl str varchar 20 returns varchar 255 b...