接到需求,首先想到的写(bai du)个shader来实现。
网上搜到了很多个版本的模糊效果的shader,最开始用的一个版本用到了GrabPass,效果出来后发现在Android手机上角色会倒置。然后搜索GrabPass的替换方法,有用到Camera的,效果也不理想。
最终决定在Spine原有的Shader上修改。于是搜到没有使用GrabPass的模糊效果的Shader。
Unity Shader-后处理:高斯模糊_puppet_master的专栏-CSDN博客_unity高斯模糊一.简介上一篇文章学习了模糊的原理以及基本的模糊实现,对于清晰和模糊这个定义感觉还是比较说明问题,这里再贴出一下:“清晰的图片,各个像素之间会有明显的过渡,而如果各个像素之间的差距不是很大,那么图像就会模糊了”。鉴于这个定义,我们就可以通过代码来实现模糊的效果。上一篇Unity Shader-后处理:均值模糊中实现了一个基本的均值模糊,也就是将一个像素和其周围的像素取平均值从而进行https://blog.csdn.net/puppet_master/article/details/52783179Unity工程中找到Spine-SkeletonGraphic-TintBlack的shader,然后将两个shader放到一起。
直接贴最终的shader
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
// This is a premultiply-alpha adaptation of the built-in Unity shader "UI/Default" in Unity 5.6.2 to allow Unity UI stencil masking.
Shader "Spine/SkeletonGraphicGlass"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,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
[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
_blurSizeX("BlurSizeX", Range(0,50)) = 2
_blurSizeY("BlurSizeY", Range(0,50)) = 2
}
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]
Fog { Mode Off }
Blend One OneMinusSrcAlpha
ColorMask [_ColorMask]
//后处理效果一般都是这几个状态
ZTest Always
Pass
{
CGPROGRAM
//使用上面定义的vertex和fragment shader
#pragma vertex vert_blur
#pragma fragment frag_blur
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
#include "UnityCG.cginc"
#include "UnityUI.cginc"
#pragma multi_compile __ UNITY_UI_ALPHACLIP
struct VertexInput {
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct VertexOutput {
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
half2 texcoord : TEXCOORD0;
float4 worldPosition : TEXCOORD1;
UNITY_VERTEX_OUTPUT_STEREO
};
fixed4 _Color;
fixed4 _TextureSampleAdd;
float4 _ClipRect;
VertexOutput vert (VertexInput IN) {
VertexOutput OUT;
UNITY_SETUP_INSTANCE_ID(IN);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
OUT.worldPosition = IN.vertex;
OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
OUT.texcoord = IN.texcoord;
#ifdef UNITY_HALF_TEXEL_OFFSET
OUT.vertex.xy += (_ScreenParams.zw-1.0) * float2(-1,1);
#endif
OUT.color = IN.color * float4(_Color.rgb * _Color.a, _Color.a); // Combine a PMA version of _Color with vertexColor.
return OUT;
}
sampler2D _MainTex : register(s0);
fixed4 frag (VertexOutput IN) : SV_Target
{
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
#ifdef UNITY_UI_ALPHACLIP
clip (color.a - 0.001);
#endif
return color;
}
#include "UnityCG.cginc"
//blur结构体,从blur的vert函数传递到frag函数的参数
struct v2f_blur
{
float4 pos : SV_POSITION; //顶点位置
float2 uv : TEXCOORD0; //纹理坐标
float4 uv01 : TEXCOORD1; //一个vector4存储两个纹理坐标
float4 uv23 : TEXCOORD2; //一个vector4存储两个纹理坐标
float4 uv45 : TEXCOORD3; //一个vector4存储两个纹理坐标
};
//shader中用到的参数
//sampler2D _MainTex;
//XX_TexelSize,XX纹理的像素相关大小width,height对应纹理的分辨率,x = 1/width, y = 1/height, z = width, w = height
float4 _MainTex_TexelSize;
//给一个offset,这个offset可以在外面设置,是我们设置横向和竖向blur的关键参数
float4 _offsets;
float _blurSizeX;
float _blurSizeY;
//vertex shader
v2f_blur vert_blur(appdata_img v)
{
v2f_blur o;
o.pos = UnityObjectToClipPos(v.vertex);
//uv坐标
o.uv = v.texcoord.xy;
_offsets = fixed4(_blurSizeX, _blurSizeY, 0, 0);
//计算一个偏移值,offset可能是(0,1,0,0)也可能是(1,0,0,0)这样就表示了横向或者竖向取像素周围的点
_offsets *= _MainTex_TexelSize.xyxy;
//由于uv可以存储4个值,所以一个uv保存两个vector坐标,_offsets.xyxy * float4(1,1,-1,-1)可能表示(0,1,0-1),表示像素上下两个
//坐标,也可能是(1,0,-1,0),表示像素左右两个像素点的坐标,下面*2.0,*3.0同理
o.uv01 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1);
o.uv23 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1) * 2.0;
o.uv45 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1) * 3.0;
return o;
}
//fragment shader
fixed4 frag_blur(v2f_blur i) : SV_Target
{
fixed4 color = fixed4(0,0,0,0);
//将像素本身以及像素左右(或者上下,取决于vertex shader传进来的uv坐标)像素值的加权平均
color += 0.4 * tex2D(_MainTex, i.uv);
color += 0.15 * tex2D(_MainTex, i.uv01.xy);
color += 0.15 * tex2D(_MainTex, i.uv01.zw);
color += 0.10 * tex2D(_MainTex, i.uv23.xy);
color += 0.10 * tex2D(_MainTex, i.uv23.zw);
color += 0.05 * tex2D(_MainTex, i.uv45.xy);
color += 0.05 * tex2D(_MainTex, i.uv45.zw);
return color;
}
ENDCG
}
}
}
原图
模糊后