利用分格的方法制作更多有趣的特效:畫素化和popup mask
不管是繪製halftone圖形,還是製作TriangularBillboard,都離不開一個環節,那就是格子的劃分。
在格子的基礎上,還可以發展出許多有趣的效果,最常見的就是畫素化。
首先增加兩個property,用以控制在橫向和縱向分格的數量。
Properties { _MainTex ("Main Texture", 2D) = "white" {} _Progress ("Progress", Range(0,1)) = 1.0 _SegmentX("Segment x", Float )=5 _SegmentY("Segment y", Float )=5 }
之後,在frag中,計算當前uv座標所屬的格子的中心位置,方法很簡單,與前幾章中使用的大同小異。對於將格子數量轉換為每個格子在uv中所佔的長度的計算,放在vert活著直接在指令碼中算好傳進來也都是可以的。
fixed4 frag(v2f i) : SV_Target { float2 _Diameter=fixed2(1/ceil(_SegmentX),1/ceil(_SegmentY)); float2 center = float2(_Diameter.x*floor(i.uvORI.x/_Diameter.x), _Diameter.y*floor(i.uvORI.y/_Diameter.y)); center+=_Diameter/2; return tex2D(_MainTex, center); }
在計算出中心位置之後,直接返回中心的顏色,我們就可以得到一張對比強烈的畫素圖了。
如果需要顏色變化更柔和一點,同時取樣中心點周圍的幾個座標的顏色,並且按照你喜歡的方式為周圍座標的顏色加上權重即可。
float4 TexMain = tex2D(_MainTex, i.uvORI); float4 TexPixel = tex2D(_MainTex,center)*0.4; TexPixel += tex2D(_MainTex, center+fixed2( _Diameter.x/4,0))*0.15; TexPixel += tex2D(_MainTex, center-fixed2( _Diameter.x/4,0))*0.15; TexPixel += tex2D(_MainTex, center+fixed2(0, _Diameter.y/4))*0.15; TexPixel += tex2D(_MainTex, center-fixed2(0, _Diameter.y/4))*0.15;
在最後,使用progress來控制顯示原圖還是畫素化之後的圖形,一個簡單的畫素化效果就完成了。
return lerp(TexMain,TexPixel,_Progress);
在繪製halftone 的章節中,我們已經試過了使用一個引數來控制半徑在格子裡畫圓,那麼,如果想要畫一個不好用公式表示的複雜圖形時,要怎麼辦呢?接下來我們試一下使用一個引數來控制多個mask貼圖的縮放。
Shader "TUT/PixelatedPopupMask00" {
Properties {
_MainTex ("Main Texture", 2D) = "white" {}
_MainTexM ("Texture Mask", 2D) = "black" {}
_Scale ("Scale", Float) = 1.0
_SegmentX("Segment x", Float )=5
_SegmentY("Segment y", Float )=5
}
SubShader {
CGINCLUDE
#include "UnityCG.cginc"
sampler2D _MainTex;
sampler2D _MainTexM;
uniform half4 _MainTexM_ST;
uniform half4 _MainTex_ST;
float _SegmentX;
float _SegmentY;
float _Scale;
struct v2f {
float4 pos : SV_POSITION;
half2 uvORI: TEXCOORD2;//original
};
v2f vert(appdata_img v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uvORI=(v.texcoord-_MainTexM_ST.zw)*_MainTexM_ST.xy ;
return o;
}
fixed4 frag(v2f i) : SV_Target {
float2 _Diameter=fixed2(1/ceil(_SegmentX),1/ceil(_SegmentY));
float2 center = float2(_Diameter.x*floor(i.uvORI.x/_Diameter.x), _Diameter.y*floor(i.uvORI.y/_Diameter.y));
center+=_Diameter/2;
float2 _rd=_Scale*_Diameter/2;
fixed4 TexMain = tex2D(_MainTex, i.uvORI);
fixed2 uvMask=fixed2((i.uvORI.x-center.x),(i.uvORI.y-center.y));
uvMask=(uvMask+_rd)/(2*_rd);
uvMask=saturate(uvMask);
fixed4 TexMask= tex2D(_MainTexM,uvMask) ;
return lerp (TexMain, TexMask,TexMask.a);
}
ENDCG
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
FallBack "Diffuse"
}
這裡改用一個叫做scale的property來控制mask貼圖的縮放,scale是1的時候,就讓貼圖剛好充滿整個格子。然後,使用mask貼圖的透明度來控制顯示mainTex還是mask。如果用作mask的圖不是設定為clamp的話,記得要將計算出的uvMask限制在0到1之間。
接下來我們看一下效果。
以下是重點****
噫!奇怪的事情發生了。在本該是格子的邊界處,出現了一些奇怪的線。
我們從頭開始分析:(
為了讓貼圖在每格里繪製,我們計算出的uvMask是這樣: 0~1,0~1,0~1,而不像平時的repeat那樣,可以是0~1,1~2,2~3這樣的值。
推測問題是unity中fragment shader並不是真正以畫素為單位,以至於邊界區域的畫素對周邊的uv進行了插值,於是繪製出一張非常狹窄的uv被映象了的貼圖所導致。希望路過的大佬能為我解惑呀!!;(
既然repeat可以這樣做,那麼我們首先來嘗試計算每個格子在所有格子中的行列數,之後與每次計算出的uv相加,得出0~1,1~2,2~3。
fixed2 indexXY=fixed2(floor(i.uvORI.x/_Diameter.x),floor(i.uvORI.y/_Diameter.y));
之後計算出的0~1之間的值上增加。不要忘了將mask設定為repeat。
uvMask+=indexXY;
是不是奇怪的線線奇蹟般的消失了~然而事情並沒有得到解決。當scale大於1,也就是每個格子裡只能繪製出mask貼圖的一部分時,這個方法就失效了,因為增加過的uv變成了0.1~0.9,1.1~1.9,2.1~2.9,只要mask貼圖在0.9到1.1這個範圍中有不同內容就會導致線條出現。
十分憂傷的,這個問題目前還沒有找到解決辦法:(
希望觀看更多效果,去
作為攝像機特效也可以使用
在slideshow Effects 中,使用了一種取巧的方法,導致這種特效只能使用上下、左右對稱的貼圖作為mask。