Unity中实现spine角色的模糊效果

接到需求,首先想到的写(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
		}
	}
}

原图

模糊后

 

猜你喜欢

转载自blog.csdn.net/cheng219101/article/details/121038831