1. 程式人生 > >ChunkDisappearImage-一個以矩形為單位的圖片消失分解效果

ChunkDisappearImage-一個以矩形為單位的圖片消失分解效果

效果

使用

1.將ChunkDisappearImage掛在一個空GameObject上。 2.將ChunkDisappearImage的Material設為ChunkDisappearImageMaterial。 3.設定RectTransform的寬、高、縮放、旋轉等引數。設定ChunkDisappearImage的引數。

引數

Speed: 小方塊移動的速度。 TargetX,TargetY: 每個小方塊移動的終點座標。 SubRectX,SubRectY: 每個小方塊的長寬。 Interval: 每個小方塊開始移動時間的間隔。 SpeedArg: 距離越遠的方塊是否執行越快,_SpeedArg為1時,所有方塊執行速度基本相同,值越小,距離越遠的方塊執行的越快。 ps:目標點的座標,小方塊的寬高都是Image物件為父節點的本地座標。

實現

簡介

實現主要分為三個步驟: 1.修改image的mesh。 2.將與運動相關的引數傳入shader中。 3.在移動結束後將mesh恢復為普通的image的shader。

實現細節

mesh的拆分

1.Image通過OnPopulateMesh函式構建對應的mesh,所以我們通過重寫Image的OnPopulateMesh來對mesh進行構建。

Image的預設mesh: 拆分後的mesh: 以拆分為四塊為例 將mesh拆分為很多個小矩形後,還得想辦法告訴shader每個頂點是屬於那個矩形的,才能以此為依據進行矩形的移動。

2.如何告訴shader每個頂點是屬於哪個矩形的。

public partial struct UIVertex
{
    public Vector3 position;
    public Vector3 normal;
    public Vector4 tangent;
    public Color32 color;
    public Vector2 uv0;
    public Vector2 uv1;
    public Vector2 uv2;
    public Vector2 uv3;

可以看下描述一個UI頂點的結構體中都包含了哪些欄位,UGUI中只用到了position,color,uv0這三個欄位。 這代表我們可以使用剩餘的欄位傳我們需要的額外資訊,這裡選擇使用uv1欄位將每個矩形的左下角的點作為矩形的位置資訊傳入shader,在shader中,以此為基礎進行小矩形塊的移動。 注意: ①不能用normal和tangent,因為UGUI在渲染時,傳入shader中的position不是傳入VertexHelper時的原始值,而是該點在根canvas上的座標,同理,normal,tangent也做了相應的變換。不是原始值了。 所以在傳額外資訊的時候要用uv1、uv2、uv3欄位,這三個欄位不會隨點的移動、旋轉、縮放而改變。 ②由於unity高版本在ugui渲染時做了優化,在預設情況下只會將position、color、uv0三個欄位傳入shader,所以需要手動將uv1設為生效才行。

image本地座標到根canvas座標的模型矩陣的計算

mLocalToCanvas = canvas.rootCanvas.transform.localToWorldMatrix.inverse * transform.localToWorldMatrix;

image的模型矩陣: canvas的模型矩陣: 由於矩陣滿足結合律,所以用用canvas的模型矩陣的逆乘以image的模型矩陣會將canvas的模型矩陣消掉,也就是image座標->canvas座標的模型矩陣: 用這個矩陣乘上image上的本地座標就可以算出對應的canvas上的座標。

開始時間和結束時間的計算

開始時間 分兩種情況: ①當目標點在圖片內時,不去算準確的起始時間,直接設定為0。 ②當目標點在圖片外時,最近點一定是四個頂點之一。遍歷四個頂點,計算一下離目標點最近的方塊開始運動時的_Delta值,即f第一次不為0的時候 結束時間 計算一下最遠點的f為1的情況即可,由於距離目標點最遠的點一定是四個頂點之一,所以列舉四個頂點即可。

shader的重寫

我們要改動Image預設的shader的頂點著色器來實現每個頂點的位移和alpha值的降低。 我們選擇5.37f1的UGUI預設shader,UI-Default.shader進行修改,這個在unity官網就可以下到。

注意:

在Unity高版本開啟低版本的shader時,會對一些函式做替換,如在2018.2開啟5.37f1的shader時,會對如下語句進行修改。

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

此demo中使用的是2018.2版本的unity,所以在低版本使用時要把這句話改回去,不然會報錯。

頂點的移動公式:

//計算該方塊到目標點的距離,以此為標準作為每個方塊移動時間的延遲
float distance = length(target.xyz - leftBottom.xyz);
//距離越遠的方塊是否執行越快,_SpeedArg為1時,所有方塊執行速度大致相同,值越小,距離越遠的方塊執行的越快
float tempDis = 1 + distance * _SpeedArg;
float f = clamp((_Delta - distance * _Interval) / tempDis, 0, 1);

根據f在0-1之間的變化,來控制方塊在起點到終點之間的移動和alpha值的變化。 ①distance * _Interval保證每個距終點距離不同方塊之間的開始移動時間會有一個間隔。 ②tempDis可以控制不同距離方塊之間的速度比。

小結

原理其實並不難,主要只有兩部分:改mesh,改shader。就是一些座標的轉換、開始結束時間的控制、版本的相容性比較麻煩。 在把整個流程跑通一次之後,就會對流程有一個較為全面的認識,下次做2D或是3D的一些效果思路也也會更廣一些。