前言
今天我们来实现一个简单的2D精灵图描边效果,效果图如下:
准备工作:
首先我们先打开unity新建一个场景,导入一个图片,并把该图片设置为Sprite类型,如图:
  
实现思路:
思路其实很简单,可以通过判断该像素周围是否有透明度为 0的值,如果有,则说明该像素位于边缘。
所以我们需要打开alpha blend,即: Blend SrcAlpha OneMinusSrcAlpha,并且加入渲染队列,
Tags
{
"Queue"
=
"Transparent"
}
Blend SrcAlpha OneMinusSrcAlpha
下面我们开始编写片元着色器,顶点着色器就是常规的顶点坐标变换,这里就不贴代码了,主要来看看片元着色器:
// ---------------------------【片元着色器】---------------------------
fixed4
frag
(
VertexOutput
i
)
:
SV_Target
{
fixed4
col
=
tex2D
(
_MainTex
,
i
.
uv
)
;
// 采样周围4个点
float2
up_uv
=
i
.
uv
+
float2
(
0
,
1
)
*
_lineWidth
*
_MainTex_TexelSize
.
xy
;
float2
down_uv
=
i
.
uv
+
float2
(
0
,
-
1
)
*
_lineWidth
*
_MainTex_TexelSize
.
xy
;
float2
left_uv
=
i
.
uv
+
float2
(
-
1
,
0
)
*
_lineWidth
*
_MainTex_TexelSize
.
xy
;
float2
right_uv
=
i
.
uv
+
float2
(
1
,
0
)
*
_lineWidth
*
_MainTex_TexelSize
.
xy
;
// 如果有一个点透明度为0 说明是边缘
float
w
=
tex2D
(
_MainTex
,
up_uv
)
.
a
*
tex2D
(
_MainTex
,
down_uv
)
.
a
*
tex2D
(
_MainTex
,
left_uv
)
.
a
*
tex2D
(
_MainTex
,
right_uv
)
.
a
;
if
(
w
==
0
)
{
col
.
rgb
=
_lineColor
;
}
return
col
;
}
_MainTex_TexelSize:贴图像素尺寸大小
我们可以通过该属性计算出周围(上下左右)的像素坐标,然后判断有没有透明度为0的值。 如果为0就返回边框颜色。
效果如下:
虽然我们实现了该功能,但是我们仔细观察会发现边缘锯齿很严重,不平滑。我们可以做下优化,利用插值来平滑过渡,
最终完整Shader代码如下:
// ---------------------------【2D 描边效果】---------------------------
// create by 长生但酒狂
Shader
"lcl/shader2D/outline"
{
Properties
{
_MainTex
(
"Texture"
,
2D
)
=
"white"
{
}
_lineWidth
(
"lineWidth"
,
Range
(
0
,
10
)
)
=
1
_lineColor
(
"lineColor"
,
Color
)
=
(
1
,
1
,
1
,
1
)
}
// ---------------------------【子着色器】---------------------------
SubShader
{
// 渲染队列采用 透明
Tags
{
"Queue"
=
"Transparent"
}
Blend SrcAlpha
OneMinusSrcAlpha
Pass
{
CGPROGRAM
#
pragma
vertex vert
#
pragma
fragment frag
#include
"UnityCG.cginc"
//顶点着色器输入结构体
struct
VertexInput
{
float4
vertex
:
POSITION
;
float2
uv
:
TEXCOORD0
;
}
;
//顶点着色器输出结构体
struct
VertexOutput
{
float2
uv
:
TEXCOORD0
;
float4
vertex
:
SV_POSITION
;
}
;
// ---------------------------【顶点着色器】---------------------------
VertexOutput
vert
(
VertexInput
v
)
{
VertexOutput
o
;
o
.
vertex
=
UnityObjectToClipPos
(
v
.
vertex
)
;
o
.
uv
=
v
.
uv
;
return
o
;
}
sampler2D
_MainTex
;
float4
_MainTex_TexelSize
;
float
_lineWidth
;
float4
_lineColor
;
// ---------------------------【片元着色器】---------------------------
fixed4
frag
(
VertexOutput
i
)
:
SV_Target
{
fixed4
col
=
tex2D
(
_MainTex
,
i
.
uv
)
;
// 采样周围4个点
float2
up_uv
=
i
.
uv
+
float2
(
0
,
1
)
*
_lineWidth
*
_MainTex_TexelSize
.
xy
;
float2
down_uv
=
i
.
uv
+
float2
(
0
,
-
1
)
*
_lineWidth
*
_MainTex_TexelSize
.
xy
;
float2
left_uv
=
i
.
uv
+
float2
(
-
1
,
0
)
*
_lineWidth
*
_MainTex_TexelSize
.
xy
;
float2
right_uv
=
i
.
uv
+
float2
(
1
,
0
)
*
_lineWidth
*
_MainTex_TexelSize
.
xy
;
// 如果有一个点透明度为0 说明是边缘
float
w
=
tex2D
(
_MainTex
,
up_uv
)
.
a
*
tex2D
(
_MainTex
,
down_uv
)
.
a
*
tex2D
(
_MainTex
,
left_uv
)
.
a
*
tex2D
(
_MainTex
,
right_uv
)
.
a
;
// if(w == 0){
// col.rgb = _lineColor;
// }
// 和原图做插值
col
.
rgb
=
lerp
(
_lineColor
,
col
.
rgb
,
w
)
;
return
col
;
}
ENDCG
}
}
}
最终效果图对比:
最后
最后欢迎来我的
GitHub
Star,谢谢! 里面有我平时学习unity shader过程中实现的一些特效demo。
本文介绍如何在Unity中实现2D精灵图的描边效果,通过判断像素周围透明度变化来识别边缘,并使用插值优化边缘平滑度。
434

被折叠的 条评论
为什么被折叠?



