兩行shader代碼搞定百葉窗效果!!!
先看下效果:
直接上shader代碼:
Shader "Learning/baiyechuang"
{
Properties
{
_TopTex ("TopTexture", 2D) = "white" {}
_BottomTex ("BottomTexture", 2D) = "white" {}
_ColumnCount("ColumnCount", int) = 3
_RowCount("RowCount", int) = 3
_ShowPercent_Col("ShowPercent_Col", range(0, 1)) = 0.5
_ShowPercent_Row("ShowPercent_Row", range(0, 1)) = 0.5
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _TopTex;
sampler2D _BottomTex;
int _ColumnCount;
int _RowCount;
float _ShowPercent_Col;
float _ShowPercent_Row;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float2 nuv = frac(i.uv * float2(_ColumnCount, _RowCount));
return lerp(tex2D(_TopTex, i.uv), tex2D(_BottomTex, i.uv), step(step(_ShowPercent_Col, nuv.x) + step(_ShowPercent_Row, nuv.y), 0.5));
}
ENDCG
}
}
}
主要思路:
把圖片分成幾行或者幾列,通過計算,決定當前像素點顯示哪個圖的像素,通過調節閾值可以達到動態的效果。
shader實現的代碼很簡單,只有frag shader中的兩行代碼,下面拆分一下這兩行代碼,進行解釋
float2 nuv = frac(i.uv * float2(_ColumnCount, _RowCount));
int col_show = step(_ShowPercent_Col, nuv.x);
int row_show = step(_ShowPercent_Row, nuv.y);
int show_tex = step(col_show + row_show, 0.5);
fixed4 col = 0;
col = lerp(tex2D(_TopTex, i.uv), tex2D(_BottomTex, i.uv), show_tex);
return col;
line1:
通過uv取每個部分的小數部分,也就是把uv座標轉化爲再這一部分中的對應比例,如下圖
P點是任意一個像素點,代碼中nuv.x
就是P點左邊黃線算起,在第二格中的百分比。
line2,line3:
計算任意像點的百分比和輸入的閾值作比較,大於閾值返回0,小於閾值返回1。
line4:
橫縱的結果相加可得到三種值:0,1,2,跟0.5相比,大於0.5返回1,小於0.5返回0,這個值會在下面代碼用到
line6:
用於判斷當前uv點顯示哪張圖片的像素,使用lerp
函數,差值爲0或1,可以理解爲取兩個極端,就是判斷用哪張圖片的像素,這個差值就是line4的到的值。
以上就是各個代碼的含義,可能因爲用了step
函數導致不容易理解,其實使用setp
函數就是爲了避免使用if else
的邏輯判斷語句,這樣可以增加shader的效率。這段shader最終的形成也是根據邏輯判斷語句簡化成現在這個樣子。
在文章的結束貼上一個用if else
實現的邏輯,可以方便理解:
fixed4 frag (v2f i) : SV_Target
{
float2 nuv = frac(i.uv * float2(_ColumnCount, _RowCount));
bool col_show = nuv.x > _ShowPercent_Col;
bool row_show = nuv.y > _ShowPercent_Row;
if (col_show || row_show) {
return tex2D(_TopTex, i.uv);
}
else {
return tex2D(_BottomTex, i.uv);
}
}