1. 程式人生 > >利用分格的方法制作更多有趣的特效:畫素化和popup mask

利用分格的方法制作更多有趣的特效:畫素化和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。