NGUI框架

NGUI有三大基礎機制支撐整個NGUI的顯示和交互,這三大機制分別是:渲染機制事件、消息機制、間隔動畫

渲染機制事件

  1. 基礎介紹
    NGUI的UIWidget、UIDrawCall、UIGeometry和UIPanel等基礎腳本
    • UIWidget是UI的基礎組件(UILabel,UISprite)的基類,含有組件的基本信息(width,Height,color,AnchorPoint等)
    • UIGeometry 是UIWidget的幾何數據,記錄了頂點座標,貼圖的UVS和顏色等信息
      • 存儲頂點、UV、Color、相對父節點的位移數據
      • 向Buffer寫數據
    • UIDrawCall是將多個UIWeiget的UIGeometry組合起來一起回執
      • drawcall是啥?其實就是對底層的圖形程序(比如:OpenGL ES)接口的調用,以在屏幕上畫出東西,所以,是誰去調用這些接口呢?GPU,Unity每次在準備數據並通知GPU渲染的過程稱爲一次Draw Call,一般情況下,渲染一次擁有一個網格並攜帶一種材質的物體便會使用一次Draw Call,對於渲染場景中的這些物體,在每一次DrawCall中除了在通知GPU的渲染上非常耗時之外,切換材質與shader也是非常耗時的操作。這個值可以在Game視圖窗口的status面板查看。
      • 有一次我們發現NGUI的UIPanel.LateUpdate函數的CPU開銷非常大。仔細研究之後,發現是合併了太多的DrawCall所致,尤其是將運行時會運動變化的UI控件和靜止不變的UI控件的DrawCall合在了一起。當一個UI控件(UIWidget)的位置、大小或顏色等屬性發生變化時,UIPanel就需要重建這個控件所用的DrawCall,某些情況下還要重建Panel上的所有DrawCall。有時重建一個DrawCall會消耗不少CPU開銷,它需要重新計算這個DrawCall上所有控件的頂點信息,包括頂點位置、UV和顏色等。如果很多控件都集中在同一個DrawCall上,那麼只要一個控件有一點點變化,這個DrawCall上的所有控件的頂點就都要重新遍歷一邊;而我們的UI又大量採用了九宮格拉伸,使控件的頂點數量變得更多,因此重建一個DrawCall的開銷就更大。
          因此我們將UI控件分組,將一段時間內會發生變化的控件——比如怪物頭頂的血條和傷害跳字放在同一個Panel上,並且這個Panel上只有這些控件,其餘基本不變化的控件就放在別的Panel上。這樣兩類控件就被隔開到不同的DrawCall不同的Panel中,當一個控件發生變化而導致DrawCall重建時,就不需要遍歷那些沒有變化的控件。因爲在美術設計上,一段時間內在變化的控件總是少數,所以優化效果十分明顯,節省的CPU佔用率能達到25%。
      • 減小DrawCall的思路:對DrawCall的優化,主要是爲了儘量解放CPU在調用圖形接口的開銷上,所以針對drawcall我們的思路就是每個物體儘量減少渲染次數,多個物體最好一起渲染,所以這個思路有一下幾個解決方案:
        • 使用drawcal batching,也就是描述調用批處理,unity在運行時可以將一個物體進行合併,從而用一個描繪來渲染他們
        • 通過把紋理打包成圖集來儘量減少材質的使用
        • 儘量少的使用反光,陰影之類的
    • UIPanel 用於管理UIWeiget、UIDrawCall等,實現界面的渲染剪裁、更新
      • 對所有widget進行排序、更新、生成widget的幾何數據
      • 負責管理DrawCall、Widget
      • 根據深度值進行渲染順序的排序
      • 有Clipping功能(ScrollView)
      • SetDerty()影響所有的子節點,在下一次update時所有的DrawCalls和Widget(Rect)重新計算alpha值
      • 在LateUpdate中更新所有的子Panels和Widgets還有DrawCalls
      • 在FillDrawCall中遍歷Widgets將材質、紋理、着色器相同的並且連續Widget中的Geometroy數據填充到一個DrawCall上並將DrawCall與Widget關聯,將不可見的,沒有頂點數據的Widget的DrawCall設置爲null。
    • UIRoot UI界面的根目錄,用於分辨率適配和事件廣播
      • 屏幕自適應
      • 所有UIRect的root

消息機制

  • 基礎介紹
      UICamera:真正做的事情是發送NGUI事件給所有被當前camera渲染的object,camera是UICamera腳本所在的那個。 其實這個腳本做的事情和UI無關。事實上如果你想讓遊戲裏面的object接收OnPress、OnClick、OnDrag等這類事件,你需要把UICamera掛在你的主相機上。遊戲場景裏面可以有多個UICamera。大多數遊戲一個掛在渲染widget的相機上,一個掛在渲染遊戲的相機上。UICamera發送以下事件給collider,用他們到自己的腳本里面,只要實現相應的函數即可:
    Ø OnHover (isOver) 發送時機爲鼠標懸停(只觸發一次)或者離開collider。
    Ø OnPress (isDown) 發送時機爲鼠標在collider上按下。
    Ø OnSelect (selected)發送時機爲鼠標點擊和鬆開的時候都在同一個object上。
    Ø OnClick ()發送時機和OnSelect一樣,但是要求鼠標沒有移動特別多。UICamera.currentTouchID表示按下的鼠標哪個鍵。
    Ø OnDoubleClick ()發送時機爲當在四分之一秒內click兩次的時候。UICamera.currentTouchID表示按下的鼠標哪個鍵。
    Ø OnDragStart ()發送時機爲OnDrag()事件之前。
    Ø OnDrag (delta) 發送時機爲一個object被拖拽。
    Ø OnDragOver(draggedObject)發送時機爲其他的object拖拽到他的上面。
    Ø OnDragOut (draggedObject)發送時機爲其他的object拖拽出他的上面。
    Ø OnDragEnd ()發送時機爲drag事件結束。發送給被拖拽的object。
    Ø OnInput (text)發送時機爲輸入的時候(在點擊選擇了一個collider之後)。
    Ø OnTooltip (show) 發送時機爲鼠標懸停在一個collider上一段時間沒有移動。
    Ø OnScroll (float delta)發送時機爲鼠標滾輪滾動。
    Ø OnKey (KeyCode key)發送時機爲鍵盤或者輸入控制器被使用的時候。

事件接受函數如下:

void OnPress (bool isPressed)
{
if (isPressed)
Debug.Log("I was pressed on!");
else
Debug.Log("I was unpressed");
}

- 監聽和分發
  在Update()中,依次處理 觸摸/點擊,文本輸入,鍵盤/搖桿輸入,Tip。
  其中最主要的就是 觸摸/點擊 事件的處理了,下面以觸摸事件處理ProcessTouches()來分析。
  第一步:從Input節點中,獲取觸摸/點擊的信息爲Touch類。
  第二步:根據Touch類的信息,分析出可能事件。
  第三步:通過物理的射線檢測即(Physics.RaycastAll)找出來對應UI使用的Collider,並把Collider所在的Gameobject作爲觸發事件的對象。
  第四步:把消息事件轉化成按照實現相應的函數調用。
  第五步:在控件所對應的腳本中實現對應的函數,便可以收到來自於UICamara的調用,並做相應的處理(如:UIButton)
  第六部:把靜態的Current變量設置爲當前的控件腳本,把使用SentMessage或EventDelegate.Excute再次分發出去。如:UIToggle.OnChange

間隔動畫Tween

間隔動畫:對對象的某一個變量,使這個變量在一定時間段內,每一幀按照預先指定曲線變化,從而形成一段動畫。如:屏幕顏色的漸變、屏幕抖動、對象的運動等等。

  • UITweener

是實現NGUI中間隔動畫的基礎。間隔動畫的基類,所有間隔組建都繼承該類,用於執行update()。所有的繼承了都需要從Begin開始。繼承類中主要函數是OnUpdate,用於處理每幀的更新處理。在Begin開啓後,當前腳本狀態會被設爲true,在運行結束之後,又會設置爲false。

  • UIPlayTween

:這個腳本管理一組Tween腳本的Play,提供了不同的Tirgger,然後在不同的事件函數中觸發Play(true)


參考知識:

1.什麼是UV?

對於三維模型,有兩個最重要的座標系統,一是頂點的位置(X,Y,Z)座標,另一個就是UV座標。什麼是UV?簡單的說,就是貼圖影射到模型表面的依據。 完整的說,其實應該是UVW(因爲XYZ已經用過了,所以另選三個字母表示)。U和V分別是圖片在顯示器水平、垂直方向上的座標,取值一般都是0~1,也 就是(水平方向的第U個像素/圖片寬度,垂直方向的第V個像素/圖片高度)。那W呢?貼圖是二維的,何來三個座標?嗯嗯,W的方向垂直於顯示器表面,一般 用於程序貼圖或者某些3D貼圖技術(記住,確實有三維貼圖這種概念!),對於遊戲而言不常用到,所以一般我們就簡稱UV了。

所有的圖象文件都是二維的一個平面。水平方向是U,垂直方向是V,通過這個平面的,二維的UV座標系。我們可以定位圖象上的任意一個象素。但是一個問題是如何把這個二維的平面貼到三維的NURBS表面和多邊形表面呢? 對於NURBS表面。由於他本身具有UV參數,儘管這個UV值是用來定位表面上的點的參數,但由於它也是二維的,所以很容易通過換算把表面上的點和平面圖象上的象素對應起來。所以把圖象貼帶NURBS是很直接的一件事。但是對於多變形模型來講,貼圖就變成一件麻煩的事了。所以多邊形爲了貼圖就額外引進了一個UV座標,以便把多邊形的頂點和圖象文件上的象素對應起來,這樣才能在多邊形表面上定位紋理貼圖。所以說多邊形的頂點除了具有三維的空間座標外。還具有二維的UV座標。

UV” 這裏是指u,v紋理貼圖座標的簡稱(它和空間模型的X, Y, Z軸是類似的). 它定義了圖片上每個點的位置的信息. 這些點與3D模型是相互聯繫的, 以決定表面紋理貼圖的位置. UV就是將圖像上每一個點精確對應到模型物體的表面. 在點與點之間的間隙位置由軟件進行圖像光滑插值處理. 這就是所謂的UV貼圖.

那爲什麼用UV座標而不是標準的投影座標呢? 通常給物體紋理貼圖最標準的方法就是以planar(平面),cylindrical(圓柱), spherical(球形),cubic(方盒)座標方式投影貼圖.

Planar projection(平面投影方式)是將圖像沿x,y或z軸直接投影到物體. 這種方法使用於紙張, 佈告, 書的封面等 - 也就是表面平整的物體.平面投影的缺點是如果表面不平整, 或者物體邊緣彎曲, 就會產生如圖A的不理想接縫和變形. 避免這種情況需要創建帶有alpha通道的圖像, 來掩蓋臨近的平面投影接縫, 而這會是非常煩瑣的工作. 所以不要對有較大厚度的物體和不平整的表面運用平面投影方式. 對於立方體可以在x, y方向分別進行平面投影, 但是要注意邊緣接縫的融合. 或者採用無縫連續的紋理, 並使用cubic投影方式. 多數軟件有圖片自動縮放功能, 使圖像與表面吻合. 顯然, 如果你的圖像與表面形狀不同, 自動縮放就會改變圖像的比例以吻合表面. 這通常會產生不理想的效果, 所以製作貼圖前先測量你的物體尺寸.
鏈接:http://www.cnblogs.com/jenry/p/4083415.html

2、紋理,貼圖,材質的區別?

材質 Material包含貼圖 Map,貼圖包含紋理 Texture。

紋理是最基本的數據輸入單位,遊戲領域基本上都用的是位圖。此外還有程序化生成的紋理 Procedural Texture。

貼圖的英語 Map 其實包含了另一層含義就是“映射”。其功能就是把紋理通過 UV 座標映射到3D 物體表面。貼圖包含了除了紋理以外其他很多信息,比方說 UV 座標、貼圖輸入輸出控制等等。

材質是一個數據集,主要功能就是給渲染器提供數據和光照算法。貼圖就是其中數據的一部分,根據用途不同,貼圖也會被分成不同的類型,比方說 Diffuse Map,Specular Map,Normal Map 和 Gloss Map 等等。另外一個重要部分就是光照模型 Shader ,用以實現不同的渲染效果。
鏈接:https://www.zhihu.com/question/25745472

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章