之前写过一篇,方形头像和圆形头像的过度效果,Unity随记(三) 方形头像与圆形头像的切换过度效果.当时采用的就是从中心点(0.5,0.5)为圆心,通过控制半径的长度和方形头像进行剪切的操作。
但是如果需要对icon进行圆角处理,则需要换个方式了,不然会显得比较生硬,对比图如下:
这里采用的是四个角都用一个小圆来进行对边角的裁剪处理(真正的圆角处理不知道是不是这样,不过现在这样的效果看起来已经满足需求了).如下图所示:
参考右上角的小圆,仅仅找到蓝色部分,将蓝色部分的Alpha设为0使其透明不显示即可,所以关键是通过比较优雅的方式找到蓝色部分.
为了使坐标原点在图片的中心点,需要对坐标进行平移(0.5,0.5)的操作,平移后使得上下左右四个圆角的处理差别仅仅在正负号上面,通过abs方法取绝对值则可方便的消除差异,避开了多个if分支语句的处理:
half2 uv = i.uv.xy - half2(0.5h, 0.5h);//将UV中心移动到图片中心
再来看看最后求alpha的部分,三个step只要有一个为0,则alpha就为1,所以需要裁减的部分(蓝色区域)三个step需要都为1,这三个step后面会有说明:
float alpha = 1 - stepX * stepY * stepL;
假如小圆的半径为R,图中黄色部分的可以表示为 |u| < 0.5 - R && |v| < 0.5 - R
本来uv的范围都是0->1,但是上面平移了坐标轴所以范围都变成了-0.5 -> 0.5.
half threshold = 0.5h - _R;//计算出阈值 uv的xy在 ±threshold范围内为显示,剩下四个角需要根据圆来判断
half stepX = step(threshold, abs(uv.x));// -threshold< x < threshold 范围内, stepX为0 否则为 1
half stepY = step(threshold, abs(uv.y));// -threshold< y < threshold 范围内, stepY为0 否则为 1
接下来就是绿色范围,就需要用到length方法了,圆心位置(threshold, threshold):
half l = length(abs(uv) - half2(threshold, threshold));
half stepL = step(_R, l); // l <= _R, stepL为0 l > _R , stepL为1
最终通过这几个step操作就可以优雅的求出当前uv处的alpha了。
附上完整代码:
//圆角处理
Shader "Vitens/CircularCorner"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_R("R", range(0, 0.5)) = 0.1
}
SubShader
{
Tags { "Queue"="Transparent" }
LOD 100
Pass
{
blend SrcAlpha OneMinusSrcAlpha
ZWrite off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _R;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
half2 uv = i.uv.xy - half2(0.5h, 0.5h);//将UV中心移动到图片中心
half threshold = 0.5h - _R;//计算出阈值 uv的xy在 +-threshold范围内为显示,剩下四个角需要根据圆来判断
//四个角的范围内
half l = length(abs(uv) - half2(threshold, threshold));
half stepL = step(_R, l);
//除了角的其他部分
half stepX = step(threshold, abs(uv.x));
half stepY = step(threshold, abs(uv.y));
//三个step只要有一个为0,则alpha就为1,所以需要裁减的部分三个step需要都为1
float alpha = 1 - stepX * stepY * stepL;
fixed4 col = tex2D(_MainTex, i.uv);
col.a = alpha;
return col;
}
ENDCG
}
}
}