【实现100个unity特效之2】使用shader和shader Graph实现2d图片描边效果(附源码)
最近在学习shader Graph相关内容,其实关于实现2d图片描边效果,网上可以看到很多教程,但是我发现大多数都是基于比较老旧的2018unity版本,可是我们实际开发使用可能是比较新的2021及以上版本,差别还是有的,实际在升级或者使用过程中,会遇到诸多问题,而且也很少有人会分享shader Graph的连线图源码没有的话我就想着把我的学习笔记和整理源码分享出来吧,我想于是就有了这篇文章。
前言
最近在学习shader Graph相关内容,其实关于实现2d图片描边效果,网上可以看到很多教程,但是我发现大多数都是基于比较老旧的2018unity版本,可是我们实际开发使用可能是比较新的2021及以上版本,差别还是有的,实际在升级或者使用过程中,会遇到诸多问题,而且也很少有人会分享shader Graph的连线图源码
没有的话我就想着把我的学习笔记和源码整理分享出来吧,于是就有了这篇文章
Shader
1. 内描边
思路:在片元着色器中,判断当前片元的上下左右像素(使用数值width来确定上下左右“多远”,从而得到描边的宽度),上下左右四个像素的 alpha 分量相乘越接近0,则该像素颜色越接近描边颜色。大致可以理解为如果某像素p的上下左右其中某个像素为透明像素,则p处于边缘,将p像素绘制为描边颜色。
代码如下:
Shader "Custom_Shader/ImageInnerOutline"
{
Properties
{
_MainTex ("Sprite Texture", 2D) = "white" {}
_OutlineWidth ("Outline Width", float) = 1
_OutlineColor ("Outline Color", Color) = (1,1,1,1)
}
SubShader
{
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
half4 _MainTex_TexelSize;
float _OutlineWidth;
float4 _OutlineColor;
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
half2 uv : TEXCOORD0;
half2 left : TEXCOORD1;
half2 right : TEXCOORD2;
half2 up : TEXCOORD3;
half2 down : TEXCOORD5;
};
v2f vert(appdata i)
{
v2f o;
o.vertex = UnityObjectToClipPos(i.vertex);
o.uv = TRANSFORM_TEX(i.uv, _MainTex);
o.left = o.uv + half2(-1, 0) * _MainTex_TexelSize.xy * _OutlineWidth;
o.right = o.uv + half2(1, 0) * _MainTex_TexelSize.xy * _OutlineWidth;
o.up = o.uv + half2(0, 1) * _MainTex_TexelSize.xy * _OutlineWidth;
o.down = o.uv + half2(0, -1) * _MainTex_TexelSize.xy * _OutlineWidth;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed4 c = tex2D(_MainTex, i.uv);
float transparent = tex2D(_MainTex, i.left).a * tex2D(_MainTex, i.right).a * tex2D(_MainTex, i.up).a * tex2D(_MainTex, i.down).a;
c.rgb = lerp(_OutlineColor.rgb, c.rgb, transparent);
return c;
}
ENDCG
}
}
}
描边效果:
内描边会占用图片本身边缘的非透明像素,当描边宽度增大时当效果为
2. 外描边
思路:在片元着色器中,处理像素p,针对p的上下左右四个像素采样(使用一个变量width来控制描边宽度,也就是处理上下左右多远的像素),若p本身是透明像素,则
若上下左右存在非透明像素,则当前像素p返回描边颜色
若上下左右都是透明像素,则返回透明即可
若 p 本身非透明像素,则返回本身颜色即可
代码如下:
Shader "Custom_Shader/ImageOuterOutline"
{
Properties
{
_MainTex ("Sprite Texture", 2D) = "white" {}
_OutlineWidth ("Outline Width", float) = 1
_OutlineColor ("Outline Color", Color) = (1.0, 1.0, 1.0, 1.0)
_AlphaValue ("Alpha Value", Range(0, 1)) = 0.1
}
SubShader
{
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
half4 _MainTex_TexelSize;
float _OutlineWidth;
float4 _OutlineColor;
float _AlphaValue;
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float4 normal : NORMAL;
};
struct v2f
{
float4 vertex : SV_POSITION;
half2 uv : TEXCOORD0;
half2 left : TEXCOORD1;
half2 right : TEXCOORD2;
half2 up : TEXCOORD3;
half2 down : TEXCOORD5;
};
v2f vert(appdata i)
{
v2f o;
o.vertex = o.vertex + i.normal * _OutlineWidth;
o.vertex = UnityObjectToClipPos(i.vertex);
o.uv = TRANSFORM_TEX(i.uv, _MainTex);
o.left = o.uv + half2(-1, 0) * _MainTex_TexelSize.xy * _OutlineWidth;
o.right = o.uv + half2(1, 0) * _MainTex_TexelSize.xy * _OutlineWidth;
o.up = o.uv + half2(0, 1) * _MainTex_TexelSize.xy * _OutlineWidth;
o.down = o.uv + half2(0, -1) * _MainTex_TexelSize.xy * _OutlineWidth;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
float transparent = tex2D(_MainTex, i.left).a + tex2D(_MainTex, i.right).a + tex2D(_MainTex, i.up).a + tex2D(_MainTex, i.down).a;
fixed4 col = tex2D(_MainTex, i.uv);
if (col.a < 0.1) {
return step(_AlphaValue, transparent) * _OutlineColor;
} else {
return col;
}
}
ENDCG
}
}
}
外描边效果:
外描边不会占用图片非透明像素,但要求图片外围要有足够但透明像素,当调整外描边宽度时,效果:
描边宽度较大时,Image 图片顶部和左边有平滑的切割是图片本身的范围
Shader Graph
1. 2d图片描边
(ps:图片看不清也没关系,文件末尾我会放手demo源码
,不清楚的可以直接查看源码进行学习)
不同图片上的效果
2. 带炫光的2d图片描边
不同图片上的效果
最终演示效果
源码
https://gitcode.net/unity1/unity2d-shader-picturestroke
参考
- 【视频】https://www.youtube.com/watch?v=Eyx3EfqqfMw&list=PLzDRvYVwl53tqzN5R-j33Sd7kf_f6b6z4
- 【文章】https://www.jianshu.com/p/c68a730e9a8b
完结
如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦
好了,我是向宇,https://xiangyu.blog.csdn.net/
一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你有任何问题,欢迎你来评论私信告诉我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
这里是一个专注于游戏开发的社区,我们致力于为广大游戏爱好者提供一个良好的学习和交流平台。我们的专区包含了各大流行引擎的技术博文,涵盖了从入门到进阶的各个阶段,无论你是初学者还是资深开发者,都能在这里找到适合自己的内容。除此之外,我们还会不定期举办游戏开发相关的活动,让大家更好地交流互动。加入我们,一起探索游戏开发的奥秘吧!
更多推荐
所有评论(0)