不管是繪製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);

如果加上一個表示顏色數量的property,

_Color("num of color", Range(1,16) )=0

就可以製作出簡單的色階效果了。

_Color=floor(_Color);
if(_Color>1){
_Color=_Color*_Color;
TexPixel.rgb=floor( TexPixel.rgb*_Color)/_Color;
}


在繪製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這個範圍中有不同內容就會導致線條出現。

十分憂傷的,這個問題目前還沒有找到解決辦法:(

希望觀看更多效果,去

Unity Web Player | SlideshowEffect?

sakuraplus.github.io

作為攝像機特效也可以使用

Unity Web Player |SlideshowEffect CamEffect?

sakuraplus.github.io

在slideshow Effects 中,使用了一種取巧的方法,導致這種特效只能使用上下、左右對稱的貼圖作為mask。

獲取更多特效,Buy me a coffee: u3d.as/1jVq

本章使用到的資源在這裡

sakuraplus/make-terrain-with-google-elevation?

github.com
圖標

推薦閱讀:
相关文章