本文参考了文章Unity shader 实现图片带圆角和边线border
并在上文基础上增加了功能。圆角区域不会再被点击到。
效果如下:
使用方法:
点击添加方法即可。如图
Corner4==圆角大小,Alpha==中心区域透明度,BorderWidth==描边宽度,BorderColor==描边颜色
shader:
Shader "Custom/UI/RoundConor"
{
Properties
{
[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
_Alpha("Alpha", Range(0, 1)) = 1
_StencilComp("Stencil Comparison", Float) = 8
_Stencil("Stencil ID", Float) = 0
_StencilOp("Stencil Operation", Float) = 0
_StencilWriteMask("Stencil Write Mask", Float) = 255
_StencilReadMask("Stencil Read Mask", Float) = 255
_ColorMask("Color Mask", Float) = 15
_RoundedCorner("Round",Vector)=(8,8,8,8)
_Width("View Width", Float) = 200
_Height("View Height", Float) = 200
_BorderWidth("Border Width", Float) = 1
_BorderColor("Boader Color", Color) = (1, 0, 0, 1)
}
SubShader
{
Tags
{
"Queue" = "Transparent"
"IgnoreProjector" = "True"
"RenderType" = "Transparent"
"PreviewType" = "Plane"
"CanUseSpriteAtlas" = "True"
}
Stencil
{
Ref[_Stencil]
Comp[_StencilComp]
Pass[_StencilOp]
ReadMask[_StencilReadMask]
WriteMask[_StencilWriteMask]
}
Cull Off
Lighting Off
ZWrite Off
ZTest[unity_GUIZTestMode]
Blend SrcAlpha OneMinusSrcAlpha
ColorMask[_ColorMask]
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "UnityUI.cginc"
#pragma multi_compile __ UNITY_UI_ALPHACLIP
struct appdata_t
{
float4 vertex :
POSITION;
float4 color :
COLOR;
float2 texcoord :
TEXCOORD0;
};
struct v2f
{
float4 vertex :
SV_POSITION;
fixed4 color :
COLOR;
half2 texcoord :
TEXCOORD0;
float4 worldPosition :
TEXCOORD1;
};
float _Alpha;
fixed4 _TextureSampleAdd;
float4 _ClipRect;
float4 _RoundedCorner;
float _Width;
float _Height;
float _BorderWidth;
float4 _BorderColor;
float4 _MainTex_TexelSize; //纹理的大小,可能没有纹理,只有顶点颜色
v2f vert(appdata_t IN)
{
v2f OUT;
OUT.worldPosition = IN.vertex;
OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
OUT.texcoord = IN.texcoord;
OUT.color = IN.color;
return OUT;
}
sampler2D _MainTex;
fixed4 frag(v2f IN) : SV_Target
{
half4 color = IN.color;
if (_MainTex_TexelSize.z > 0)
{
//有纹理,则颜色从纹理读取, 并叠加顶点颜色
color = (tex2D(_MainTex, IN.texcoord)) * IN.color;
}
color.a=color.a= _Alpha;
//float width = _MainTex_TexelSize.z;
//float height = _MainTex_TexelSize.w;
float width = _Width;
float height = _Height;
if (width <= 0 && _MainTex_TexelSize.z > 0)
{
//如果没定义宽度,而纹理又定义了宽度,则从纹理宽度读取
width = _MainTex_TexelSize.z;
}
if (height <= 0 && _MainTex_TexelSize.w > 0)
{
//同上
height = _MainTex_TexelSize.w;
}
float border_width = _BorderWidth;
half4 border_color = _BorderColor;
float x = IN.texcoord.x * width;
float y = IN.texcoord.y * height;
float arc_size = 0;
float r = _RoundedCorner.w;
//左下角
if (x < r && y < r)
{
arc_size = (x - r) * (x - r) + (y - r) * (y - r);
if (arc_size > r * r)
{
color.a = 0;
}
else if (border_width > 0 && arc_size > (r - border_width) * (r - border_width))
{
color = border_color;
}
}
r = _RoundedCorner.x;
//左上角
if (x < r && y > (height - r))
{
arc_size = (x - r) * (x - r) + (y - (height - r)) * (y - (height - r));
if (arc_size > r * r)
{
color.a = 0;
}
else if (border_width > 0 && arc_size > (r - border_width) * (r - border_width))
{
color = border_color;
}
}
r = _RoundedCorner.z;
//右下角
if (x > (width - r) && y < r)
{
arc_size = (x - (width - r)) * (x - (width - r)) + (y - r) * (y - r);
if (arc_size > r * r)
{
color.a = 0;
}
else if (border_width > 0 && arc_size > (r - border_width) * (r - border_width))
{
color = border_color;
}
}
r = _RoundedCorner.y;
//右上角
if (x > (width - r) && y > (height - r))
{
arc_size = (x - (width - r)) * (x - (width - r)) + (y - (height - r)) * (y - (height - r));
if (arc_size > r * r)
{
color.a = 0;
}
else if (border_width > 0 && arc_size > (r - border_width) * (r - border_width))
{
color = border_color;
}
}
if (border_width > 0)
{
//下边直线区域
if (x > _RoundedCorner.w && x < (width - _RoundedCorner.z) && y < border_width)
{
color = border_color;
}
//上边直线区域
if (x > _RoundedCorner.x && x < (width - _RoundedCorner.y) && (height - y) < border_width)
{
color = border_color;
}
//左边直线区域
if (y > _RoundedCorner.w && y < (height - _RoundedCorner.x) && x < border_width)
{
color = border_color;
}
//右边直线区域
if (y > _RoundedCorner.z && y < (height - _RoundedCorner.y) && x > (width - border_width))
{
color = border_color;
}
}
return color;
}
ENDCG
}
}
}
代码:
namespace UnityEngine.UI
{
public class UIRoundConor_RawImage : RawImage
{
const float defaultCorner = 4;
[SerializeField]
protected Vector4 m_Corner4 = new Vector4(defaultCorner, defaultCorner, defaultCorner, defaultCorner);
[SerializeField][Range(0,1)] protected float m_Alpha = 1;
[SerializeField][Range(0,255)] protected float m_BorderWidth = 1;
[SerializeField] protected Color m_BorderColor = Color.black;
private static readonly int RoundedCornerID = Shader.PropertyToID("_RoundedCorner");
private static readonly int BorderWidthID = Shader.PropertyToID("_BorderWidth");
private static readonly int BorderColorID = Shader.PropertyToID("_BorderColor");
private static readonly int WidthID = Shader.PropertyToID("_Width");
private static readonly int HeightID = Shader.PropertyToID("_Height");
private static readonly int AlphaID = Shader.PropertyToID("_Alpha");
/// <summary>
/// 角点
/// x=topLeft
/// y=topRight
/// z=bottomRight
/// w=bottomLeft
/// </summary>
public Vector4 Corner4
{
get => m_Corner4;
set
{
m_Corner4 = value;
UpdateMaterial();
}
}
/// <summary>
/// 中心区域透明度
/// </summary>
public float Alpha
{
get => m_Alpha;
set
{
m_Alpha = value;
UpdateMaterial();
}
}
/// <summary>
/// 描边宽度
/// </summary>
public float BorderWidth
{
get => m_BorderWidth;
set
{
m_BorderWidth = value;
UpdateMaterial();
}
}
/// <summary>
/// 描边颜色
/// </summary>
public Color BorderColor
{
get => m_BorderColor;
set
{
m_BorderColor = value;
UpdateMaterial();
}
}
protected override void Awake()
{
var shader = Shader.Find("Custom/UI/RoundConor");
this.material = new Material(shader);
UpdateMaterial();
}
/// <summary>
/// 更新材料
/// </summary>
protected override void UpdateMaterial()
{
base.UpdateMaterial();
material.SetVector(RoundedCornerID, m_Corner4);
material.SetFloat(AlphaID, m_Alpha);
material.SetFloat(BorderWidthID, m_BorderWidth);
material.SetColor(BorderColorID, m_BorderColor);
material.SetFloat(WidthID, rectTransform.rect.size.x);
material.SetFloat(HeightID, rectTransform.rect.size.y);
}
/// <summary>
/// 设置点击区域,圆角区域不可被点击
/// </summary>
/// <param name="sp"></param>
/// <param name="eventCamera"></param>
/// <returns></returns>
public override bool Raycast(Vector2 sp, Camera eventCamera)
{
Vector2 localPoint;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, sp, eventCamera, out localPoint))
{
if (!float.IsNaN(localPoint.x)&&!float.IsNaN(localPoint.y))
{
var realCorner = m_Corner4;
var localRect = rectTransform.rect;
var topLeft = new Vector2(localRect.xMin + realCorner.x, localRect.yMin + realCorner.x);
if (localPoint.x < topLeft.x && localPoint.y < topLeft.y)
{
if (Vector2.Distance(topLeft, localPoint) > realCorner.x)
{
return false;
}
}
var topRight = new Vector2(localRect.xMax - realCorner.y, localRect.yMin + realCorner.y);
if (localPoint.x > topRight.x && localPoint.y < topRight.y)
{
if (Vector2.Distance(topRight, localPoint) > realCorner.y)
{
return false;
}
}
var bottomRight = new Vector2(localRect.xMax - realCorner.z, localRect.yMax - realCorner.z);
if (localPoint.x > bottomRight.x && localPoint.y > bottomRight.y)
{
if (Vector2.Distance(bottomRight, localPoint) > realCorner.z)
{
return false;
}
}
var bottomLeft = new Vector2(localRect.xMin + realCorner.w, localRect.yMax - realCorner.w);
if (localPoint.x < bottomLeft.x && localPoint.y > bottomLeft.y)
{
if (Vector2.Distance(bottomLeft, localPoint) > realCorner.w)
{
return false;
}
}
}
}
return base.Raycast(sp, eventCamera);
}
}
}
using UnityEditor;
using UnityEditor.UI;
using UnityEngine.UI;
[CustomEditor(typeof(UIRoundConor_RawImage), true)]
public class UIRoundConor_RawImageEditor : RawImageEditor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
EditorGUILayout.Space();
var corner = serializedObject.FindProperty("m_Corner4");
EditorGUILayout.PropertyField(corner);
var alpha = serializedObject.FindProperty("m_Alpha");
EditorGUILayout.PropertyField(alpha);
var borderWidth = serializedObject.FindProperty("m_BorderWidth");
EditorGUILayout.PropertyField(borderWidth);
var borderColor = serializedObject.FindProperty("m_BorderColor");
EditorGUILayout.PropertyField(borderColor);
serializedObject.ApplyModifiedProperties();
}
}
UIRoundConor_RawImageEditor请放在Editor文件目录下!