溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Unity+shader如何繪制halftone動畫實現(xiàn)星之卡比新星同盟切屏效果

發(fā)布時間:2021-11-15 16:13:40 來源:億速云 閱讀:328 作者:柒染 欄目:大數(shù)據(jù)

這篇文章將為大家詳細講解有關Unity+shader如何繪制halftone動畫實現(xiàn)星之卡比新星同盟切屏效果,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

卡比是個好游戲,這次的切屏和loading畫面也是可愛得不行。先放出這篇文章想要重現(xiàn)的效果:


Unity+shader如何繪制halftone動畫實現(xiàn)星之卡比新星同盟切屏效果

卡比的進門切屏效果

接下來放出我們最終實現(xiàn)的效果:

Unity+shader如何繪制halftone動畫實現(xiàn)星之卡比新星同盟切屏效果

使用起來也是十分簡單的,以上效果連動畫系統(tǒng)都可以完成。

分析一番后,我們可以將卡比的切屏特效拆分成幾個部分:

1.沿一個方向移動的halftone圖形
2.兩張貼圖/顏色的切換
3.任意形狀的mask貼圖以指定軸旋轉(zhuǎn)縮放

那么從第一步開始,繪制一個halftone圖形。
要繪制halftone dots 并讓它們在畫面中移動,首先需要一個property來確定圖形的位置。

  Properties {
	 _MainTex ("Texture A", 2D) = "black" {} 
	 _MainTexB ("Texture B", 2D) = "black" {} 
	 [Space(10)]
	 _Position("Halftone Position", Float)=1
	 _Diameter("Diameter", Range(0,1) )=0.25
	 _Num("Length", Range(1,16)) = 3.0
 }
這里面還定義了dots的直徑 _Diameter ,和halftone過渡區(qū)域的長度 _Num
struct v2f {
	float4 pos : SV_POSITION;
	half2 uvTA: TEXCOORD0;
	half2 uvTB: TEXCOORD1;
	half2 uvORI: TEXCOORD2;//original
};
 
v2f vert(appdata_img v) {
	v2f o;
	o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
	o.uvTA=(v.texcoord-_MainTex_ST.zw)*_MainTex_ST.xy ;
	o.uvTB=(v.texcoord-_MainTexB_ST.zw)*_MainTexB_ST.xy ;
	o.uvORI.xy=v.texcoord;
	return o;
}

這里兩張貼圖可以使用tillng和offset,而繪制halftone的uv則使用原始的值。

之后以position為基礎,將uv劃分為若干網(wǎng)格。最后以每個格子的中心點為圓心畫出圓點。

    fixed4 frag(v2f i) : SV_Target {
	float _rd;
	fixed2 posCenter;
	fixed indexOfGrid=floor((i.uvORI.x-_Position)/_Diameter);//num of grids between uv and PosW
	posCenter.x=_Position+(indexOfGrid + 0.5)*_Diameter;
	posCenter.y=(floor(i.uvORI.y/_Diameter) + 0.5)*_Diameter;
	_rd=0.5*_Diameter* abs(indexOfGrid)/_Num;//radius of the current grid 
	fixed inCircle=step(distance(i.uvORI,posCenter),_rd);
	inCircle=clamp(inCircle,0,1);
 
	fixed4 texA=tex2D(_MainTex, i.uvTA).rgba;
	fixed4 texB=tex2D(_MainTexB, i.uvTB).rgba;
	fixed4 sum= lerp(texB,texA,inCircle);
	return sum;
}

看一下效果,似乎出現(xiàn)了一些問題呢

可以發(fā)現(xiàn),position的左右兩側(cè)同時出現(xiàn)了對稱的圓點,解決這個問題,只需要讓uv大于position的部分直接顯示textureB即可。

if(indexOfGrid>=1){
	return tex2D(_MainTexB, i.uvTB).rgba ;//return texture A when uv is in front (larger) of PosW
}

另一個問題是,圓點的半徑根據(jù)和position的距離是一個遞增的關系,在后方的格子里,圓點的半徑超過了格子的尺寸時,并不會在相鄰的格子里顯示出來。
這個問題在格子里畫方塊時不會看出異常

畫圓點的時候就可以發(fā)現(xiàn)出現(xiàn)了一些明顯的直線(上上圖的第一列圓點處),畫方塊的時候就滿看不出來了

這時就需要在計算時將后方法格子一起考慮進去了

	float _rdNext=_rd+0.5*_Diameter/_Num; 
	fixed2 posCenterNext= posCenter-fixed2(diameterW,0); //center of up-next grid 
	//fixed inCircle=step(abs(i.uvORI.x-posCenter.x),_rd)*step(abs(i.uvORI.y-posCenter.y),_rd); //Square 
	fixed inCircle=step(distance(i.uvORI,posCenter),_rd)+step(distance(i.uvORI,posCenterNext),_rdNext); //Dot

現(xiàn)在,一個可以移動的halftone圖形就畫出來了Unity+shader如何繪制halftone動畫實現(xiàn)星之卡比新星同盟切屏效果但是這和我們常見的半調(diào)圖形還有一些不同……

是的,格子之間沒有偏移,完全是橫平豎直的分布,顯得一點也不好看,這就需要加上一個參數(shù)來讓它在y方向有一個偏移,之后為了讓圖形更加自然,在y方向偏移時,x方向也進行一定壓縮。于是我們對frag進行以下修改
fixed4 frag(v2f i) : SV_Target {
	float _rd;
	fixed2 posCenter;
	fixed diameterW,diameterH;
	diameterW=_Diameter*(1-_rotOffset/2);//width of grid , reduce when _rotOffset is larger than zero
	diameterH=_Diameter;
	fixed indexOfGrid=floor((i.uvORI.x-_Position)/diameterW);//num of grids between uv and PosW
	if(indexOfGrid>=1){
		return tex2D(_MainTexB, i.uvTB).rgba ;//return texture A when uv is in front (larger) of PosW
	}
 
	posCenter.x=_Position+(indexOfGrid+0.5)*diameterW;
	fixed modOffset=frac(indexOfGrid*_rotOffset)*_Diameter;
	posCenter.y=(floor((i.uvORI.y-modOffset)/diameterH)+ 0.5)*diameterH+modOffset;
 
	_rd=0.5*diameterH* abs(indexOfGrid)/_Num;//radius of the current grid 
	float _rdNext=_rd+0.5*diameterH/_Num;
	fixed2 posCenterNextUp=posCenter-fixed2(diameterW,_Diameter*(_rotOffset-1));
	fixed2 posCenterNextDown=posCenter-fixed2(diameterW,_Diameter*_rotOffset); //center of down-next grid
	float _rdPrev=_rd-0.5*diameterH/_Num;
	fixed2 posCenterPrevUp=posCenter+fixed2(diameterW,_Diameter*(_rotOffset-1));
	fixed2 posCenterPrevDown=posCenter+fixed2(diameterW,_Diameter*_rotOffset); //center of down-next grid
	//fixed inCircle=step(abs(i.uvORI.x-posCenter.x),_rd)*step(abs(i.uvORI.y-posCenter.y),_rd);//Square
	fixed inCircle=step(distance(i.uvORI,posCenter),_rd);
	inCircle+=step(distance(i.uvORI,posCenterNextUp),_rdNext)+step(distance(i.uvORI,posCenterNextDown),_rdNext);
	inCircle+=step(distance(i.uvORI,posCenterPrevUp),_rdPrev)+step(distance(i.uvORI,posCenterPrevDown),_rdPrev);
	inCircle=clamp(inCircle,0,1);
 
	fixed4 texA=tex2D(_MainTex, i.uvTA).rgba;
	fixed4 texB=tex2D(_MainTexB, i.uvTB).rgba;
	fixed4 sum= lerp(texB,texA,inCircle);
	return sum;
}

因為在uv方向上都有了偏移,所以繪制一個格子里的內(nèi)容時需要左上左下、右上右下四個格子。

在properties中,添加

_rotOffset("Offset Between Points",  Range(0,0.5)) = 0.0

由于圓點是對稱圖形,偏移量的取值范圍只需要是格子尺寸的一半。
至此,一個可以移動位置的halftone切圖效果就完成了。Unity+shader如何繪制halftone動畫實現(xiàn)星之卡比新星同盟切屏效果說到這里,大家可能會想,這個跟直接使用一張貼圖作為遮罩有什么不同呢?答案是,確實沒什么不同,目前為止的效果是完全可以使用一張遮罩實現(xiàn)的。使用遮罩甚至還能達成更多花哨的效果,但遮罩也有它所不能完成的事情。接下來修改格子劃分的方法,讓格子的位置不再跟隨position變化,再改變一下計算圓點半徑的方法,作出圓點一個個彈出的效果。

修改一下格子劃分的方法,讓格子的位置不再跟隨position變化:

fixed indexOfGrid=floor((i.uvORI.x)/diameterW);//num of grids between uv and PosW 
posCenter.x=(indexOfGrid+0.5)*diameterW;     
fixed modOffset=frac(indexOfGrid*_rotOffset)*_Diameter;
posCenter.y=(floor((i.uvORI.y-modOffset)/diameterH)+ 0.5)*diameterH+modOffset;

然后再改變一下計算圓點半徑的方法,讓其根據(jù)uv和position 的關系變化:

 _rd=0.5*(_Position-posCenter.x)/_Num;//radius of the current grid 
 float _rdNext=_rd+0.5*diameterW/_Num; 
 float _rdPrev=_rd-0.5*diameterW/_Num;

這里計算前后格子中的半徑時,需要改用壓縮過的diameter,不然就會出現(xiàn)不太對勁的效果。由于劃分格子的方法已經(jīng)發(fā)生了變化,原本的if(indexOfGrid>=1)的時候,直接輸出textureB已經(jīng)無效了,實際上,判斷的條件應該是圓點半徑小于0。

Unity+shader如何繪制halftone動畫實現(xiàn)星之卡比新星同盟切屏效果接下來,需要一個表明角度的property,來讓圖形按照一個方向移動,而不是只能從左到右。

   _Rotation("Rotation", Range(0,360)) = 0.0

旋轉(zhuǎn)角度的算法,在很多地方都可以找到。這里直接轉(zhuǎn)換計算halftone時使用的uv坐標,而textureA和B的uv不受影響。由于各個頂點之間的uv變化是線性的,這一轉(zhuǎn)化可以放在vert函數(shù)中完成。

o.uvORI.xy=v.texcoord; fixed2 offsetXY=fixed2(0.5,0.5); 
 float Rot = _Rotation * (3.1415926f/180.0f); 
 float s = sin(Rot); 
 float c = cos(Rot); 
 float2x2 rMatrix = float2x2(c, -s, s, c); 
 rMatrix *= 0.5; 
 rMatrix += 0.5; 
 rMatrix = rMatrix * 2 - 1; 
 o.uvORI.xy = mul(o.uvORI.xy-offsetXY, rMatrix)+offsetXY;

這個_Rotation換成弧度角也是完全可以的。 _Rotation("Rotation", Range(0,6.283)) = 0.0 ,到時候就不需要進行乘PI再除180的計算。

現(xiàn)在看一下 示例場景

SlideshowEffect: Halftone and Popup

https://sakuraplus.github.io/make-terrain-with-google-elevation/webplayershow/webplayershow.html

里面的halftone切圖的效果基本完成了。

關于Unity+shader如何繪制halftone動畫實現(xiàn)星之卡比新星同盟切屏效果就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI