【Unity Shader】基于UGUI的水波倒影按钮

先上效果:

【Unity Shader】基于UGUI的水波倒影按钮_第1张图片

首先说一下原理,这个shader实现的原理很简单,通过使用两个Pass,第一个Pass先正常渲染一遍UI,第二个Pass将UV坐标y值上下翻转,并将顶点坐标偏移一定距离,再做扭曲操作。实现起来并不是很难,主要需要注意的就是UGUIshader要注意的几个格式,比如UGUI shader都要有模板测试和ColorMask的部分(如果你希望你的shader能支持UGUI mask的话)。


首先是shader的模板测试部分,(模板测试参考官网:http://docs.unity3d.com/Manual/SL-Stencil.html)

【Unity Shader】基于UGUI的水波倒影按钮_第2张图片

在属性块中定义这些属性,如果希望能支持UIMask,则这是必须的,注意前5段定义了模板缓存的比较函数,模板值,测试成功后的操作函数,以及模板读写的掩码,shader中的使用方式如下:

【Unity Shader】基于UGUI的水波倒影按钮_第3张图片

我们知道正常使用模板缓存,需要指定模板值,比较函数等,并且通常都是指定一个具体的枚举值,比如Greater,Less,Equal,LEqual等,而UGUIshader则直接将具体的数值传入,当然这一过程是有UGUIMask脚本完成的,那么这些具体的数值是如何和比较函数一一对应的,我们可以看下UnityEngine.Rendering名称空间,

【Unity Shader】基于UGUI的水波倒影按钮_第4张图片

其中包括一些shader中常用枚举,包括blend的混合因子,当然还有深度测试和模板测试的比较方式,cullMode等,也就是说如果希望尝试编写一个shader,其光栅化阶段的模板测试,深度测试,以及混合等是可以通过脚本控制的,则可以使用这种方式。

另外UGUIshader中还是用了ColorMask,注意UGUI源码中Mask类是如何使用ColorMask的,可以看到当UGUIMask关闭ShowMaskGraphic时colormask会被设为0,也就是UGUImask通过使用colormask来完成”是否显示mask本身“的功能。

以上部分是UGUIshader中为了让你写的UIshader支持Mask功能所做的事。

(支持Mask的UGUI水波:)

【Unity Shader】基于UGUI的水波倒影按钮_第5张图片

另外,UGUI有一点需要注意,UGUI Image类的颜色信息和Button类的鼠标滑过或点击的反馈颜色都是通过直接修改UGUI的网格的顶点色实现的,换句话说如果希望自己写的UGUIshader能获取到Button中鼠标滑过或点击的颜色,则必须在shader的顶点输入结构中包含顶点颜色信息。


接下来说一下水波的原理,主要就是使用一张噪波贴图,其R通道与G通道如下:

【Unity Shader】基于UGUI的水波倒影按钮_第6张图片【Unity Shader】基于UGUI的水波倒影按钮_第7张图片

shader中通过读入该噪波贴图的RG通道,并将其颜色值转换为-1到1的范围,再乘上一个偏移强度,就得到了uv的偏移量,当使用_Time将噪波贴图运动,就能达到水波的效果了。另外我还在shader中加入了扭曲强度和alpha的淡入淡出效果,直接贴源码:

Shader "MyUI/UI Wave"
{
	Properties
	{
		[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
		_NoiseTex ("Wave Noise", 2D) = "white" {}//噪波贴图
		_Offset ("Vertex Offset", vector) = (0, 0, 0, 0)//表示顶点的偏移量
		_Indentity ("Indentity", float) = 0.1//表示水波的扭曲强度
		_SpeedX ("WaveSpeedX", float) = 0.08//噪波贴图延X方向的移动速度
		_SpeedY ("WaveSpeedY", float) = 0.04//噪波贴图延Y方向的移动速度
		_AlphaFadeIn ("AlphaFadeIn", float) = 0.0//水波的淡入位置
		_AlphaFadeOut ("AlphaFadeOut", float) = 1.0//水波的淡出位置
		_TwistFadeIn ("TwistFadeIn", float) = 1.0//扭曲的淡入位置
		_TwistFadeOut ("TwistFadeOut", float) = 1.01//扭曲的淡出位置
		_TwistFadeInIndentity ("TwistFadeInIndentity", float) = 1.0//扭曲的淡入强度
		_TwistFadeOutIndentity ("TwistFadeOutIndentity", float) = 1.0//扭曲的淡出强度
		_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
	}

	CGINCLUDE
	//定义顶点的输入结构
		struct appdata_ui
		{
			float4 vertex   : POSITION;
			float4 color    : COLOR;
			float2 texcoord : TEXCOORD0;
		};

		//定义顶点到片段的结构
		struct v2f_ui
		{
			float4 pos   : SV_POSITION;
			fixed4 color    : COLOR;
			half2 uv  : TEXCOORD0;
		};

		fixed4 _Color;

		//两个Pass通用的顶点函数
		void vert_ui(inout appdata_ui Input, out v2f_ui Output){

			Output.pos = mul(UNITY_MATRIX_MVP, Input.vertex);
				Output.uv = Input.texcoord;
			#ifdef UNITY_HALF_TEXEL_OFFSET
				Output.uv.xy += (_ScreenParams.zw-1.0)*float2(-1,1);
			#endif
				Output.color = Input.color * _Color;
		}
	ENDCG

	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 SrcAlpha OneMinusSrcAlpha
		ColorMask [_ColorMask]

		Pass
		{
			//第一个Pass,正常渲染
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"


			v2f_ui vert(appdata_ui v)
			{
				v2f_ui o;
				vert_ui(v, o);
				return o;
			}

			sampler2D _MainTex;

			fixed4 frag(v2f_ui i) : SV_Target
			{
				half4 color = tex2D(_MainTex, i.uv) * i.color;
				clip (color.a - 0.01);
				return color;
			}
		ENDCG
		}

		Pass
		{
			//第二个Pass,渲染水波
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			sampler2D _NoiseTex;

			float4 _Offset;
			half _SpeedX;
			half _SpeedY;
			half _Indentity;
			float _AlphaFadeIn;
			float _AlphaFadeOut;
			half _TwistFadeIn;
			half _TwistFadeOut;
			fixed _TwistFadeInIndentity;
			fixed _TwistFadeOutIndentity;

			v2f_ui vert(appdata_ui v)
			{
				v2f_ui o;
				v.vertex = v.vertex - float4 (_Offset.xyz, 0);//偏移顶点坐标
				vert_ui(v, o);
				return o;
			}

			sampler2D _MainTex;

			fixed4 frag(v2f_ui i) : SV_Target
			{
				//对淡入强度和淡出强度的插值
				fixed fadeT = saturate((_TwistFadeOut - i.uv.y) / (_TwistFadeOut - _TwistFadeIn));
				float2 tuv = (i.uv - float2(0.5, 0)) * fixed2(lerp(_TwistFadeOutIndentity, _TwistFadeInIndentity, fadeT), 1) + float2(0.5, 0);

				//计算噪波贴图的RG值,得到扭曲UV,
				float2 waveOffset = (tex2D(_NoiseTex, tuv + float2(0, _Time.y * _SpeedY)).rg + tex2D(_NoiseTex, tuv + float2(_Time.y * _SpeedX, 0)).rg) - 1;
				float2 ruv = float2(i.uv.x, 1 - i.uv.y) + waveOffset * _Indentity;

				//使用扭曲UV对纹理采样
				float4 c = tex2D (_MainTex, ruv);

				//对淡入Alpha和淡出Alpha的插值
				fixed fadeA = saturate((_AlphaFadeOut - ruv.y) / (_AlphaFadeOut - _AlphaFadeIn));
				c = c * _Color * i.color * fadeA;
				clip (c.a - 0.01);
				return c;
			}
		ENDCG
		}
	}
}


https://github.com/AsehesL/UGUIEffect


你可能感兴趣的:(游戏开发,Unity,Shader)