一、 效果与引言
相信很多小伙伴都会遇到做圆角矩形的需求,网上的shader还不明白是怎么实现的,甚至还有一部分是错误的,本文讲从原理到代码讲解圆角矩形shader的实现
二、 原理分析
想要实现一个圆角矩形,常见的是抽象成一个数学模型,如下图紫色区域,就是我们应该保留的区域,为了更准确的描述这个图形,我们在四个角创建四个相等的圆形。
因为控制每个像素的颜色主要是由片元着色器负责的,所以我们也通过Fragment Shader去实现这个效果,可以看到在这个函数里我们只能拿到 uv和vertex,所以我们根据uv坐标判定是否在上图的紫色区域,如果在则返回原本的颜色,如果不在返回完全透明的颜色。
(对每个像素都会执行一次frag函数获取真正渲染的颜色)
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
fixed4 frag (v2f i) : SV_Target
{
//....省略
}
因为我们通过uv来判断是否是紫色区域,所以我们需要先了解uv坐标系
首先我们要了解UV坐标系,这并不是什么高深的数学概念,而是一个简单的道理。
首先,我们把水平方向定义为X轴,竖直方向为Y轴,把图片左下角定义为(0,0),右上角定义为(1,1),其他的坐标以此类推
读者可能会产生疑惑,为什么xy两个轴长度不同,但是坐标却不相同?
笔者暂时只能这样描述:我们就如此定义一个坐标系,x轴和y轴单位长度不同
我们需要用户去调整四个圆形的半径 设为Radius,因为uv坐标系的xy单位长度不同,我们设Ratio = Height/Width,Ratio即为y轴单位长度与x轴单位长度之比。
float Radius 圆形半径
float Ratio Y单位长度/X单位长度
接下来我们在图上画四个圆形并作辅助线
通过观察,我们可以发现以下特征
1.只有在红色区域才有可能被舍弃
2.三个圆形R2,R3,R4对应红色区域的任意一个位置,都能在R1内找到等价位置
3. UV坐标转正常坐标的公式为 f (x ,y)= (uv.x , uv.y * Ratio)
在UV坐标内,我们无法通过x2 + y2 来计算长度,因为uv坐标的xy单位不同,所以我们通过上述的坐标转换公式来转化为相同的坐标系
我们需要按以下步骤进行处理
1.将白色区域坐标在左下角找到等价uv坐标,position = abs(step(0.5,uv) - uv)
2.判断等价uv是否在左下角可能舍弃区域,uv.x<Raduis && uv.y < Radius * Ratio
如果不在,则返回原色,如果在则进入下一步
3. 求圆心距 distance = [f(uv.x,uv.y) - f(Radius,Radius)]的长度
如果大于半径则返回fixed(0,0,0,0),否则返回原色
三、着色器代码
在shader内尽量不要使用if语句
以上来着自Hking_Auditore 大大的Shader入门书,通常我们用step和lerp等来代替if
step函数的逻辑可以等价为
step (a, x)
{
if (a>x) return 0;
else return 1;
}
接下来的代码虽然看着多,实际上我们只写了两行
这就是这两行文章来源:https://www.toymoban.com/news/detail-441621.html
float2 p = abs(step(0.5,i.uv) - i.uv);
fixed4 col = tex2D(_MainTex, i.uv) * (step(_Radius,p.x) ||step( _Radius ,p.y*_Ratio) || step(length(float2(p.x-_Radius,p.y*_Ratio-_Radius)),_Radius));
这是完整的着色器代码文章来源地址https://www.toymoban.com/news/detail-441621.html
Shader "Unlit/MyShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Radius ("Radius",float) = 0
_Ratio("Height/Width",float )= 1
}
SubShader
{
Tags { "RenderType"="Transparent" "Queue" = "Transparent"}
LOD 100
Blend SrcAlpha OneMinusSrcAlpha
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;
float _Radius;
float _Ratio;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
//坐标等价到左下角
float2 p = abs(step(0.5,i.uv) - i.uv);
//三个条件同时成立则乘0,否则乘1
//1.在左下角 ,2.长度超过半径
fixed4 col = tex2D(_MainTex, i.uv) * (step(_Radius,p.x) ||step( _Radius ,p.y*_Ratio) || step(length(float2(p.x-_Radius,p.y*_Ratio-_Radius)),_Radius));
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
}
}
}
到了这里,关于Unity 圆角矩形Shader实现(支持长方形)(只写两行)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!