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);
}
}