Unity Shader入门☀️ | 使用Shader实现一个 图片边框 ✨制作!

Posted 呆呆敲代码的小Y

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity Shader入门☀️ | 使用Shader实现一个 图片边框 ✨制作!相关的知识,希望对你有一定的参考价值。

  • 📢博客主页:https://blog.csdn.net/zhangay1998
  • 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
  • 📢本文由 呆呆敲代码的小Y 原创,首发于 CSDN🙉
  • 📢未来很长,值得我们全力奔赴更美好的生活✨


🎬使用Shader实现一个 图片边框 ✨制作!

📢前言

  • 🎄闲来无事,正好碰到一个需求需要给图片加上一个边框

  • 🎄加边框的方式有很多种,可以用遮罩来做,也可以自定义修改图片等

  • 🎄那我今天就选择来用Shader搞一个图片边框


🍉图片边框制作

🏳️‍🌈Shader代码

新建一个 Shader ,然后改个名字,如下所示

然后打开这个Shader脚本,将以下代码复制进去!

Shader "Custom/SpritesOutline"
{
	Properties
	{
		[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
		_Color("Main texture Tint", Color) = (1,1,1,1)

		[Header(General Settings)]
		[MaterialToggle] _OutlineEnabled("Outline Enabled", Float) = 1
		[MaterialToggle] _ConnectedAlpha("Connected Alpha", Float) = 0
		[HideInInspector] _AlphaThreshold("Alpha clean", Range(0, 1)) = 0
		_Thickness("Width (Max recommended 100)", float) = 10
		[KeywordEnum(Solid, Gradient, Image)] _OutlineMode("Outline mode", Float) = 0
		[KeywordEnum(Contour, Frame)] _OutlineShape("Outline shape", Float) = 0
		[KeywordEnum(Inside under sprite, Inside over sprite, Outside)] _OutlinePosition("Outline Position (Frame Only)", Float) = 0

		[Header(Solid Settings)]
		_SolidOutline("Outline Color Base", Color) = (1,1,1,1)

		[Header(Gradient Settings)]
		_GradientOutline1("Outline Color 1", Color) = (1,1,1,1)
		_GradientOutline2("Outline Color 2", Color) = (1,1,1,1)
		_Weight("Weight", Range(0, 1)) = 0.5
		_Angle("Gradient Angle (General gradient Only)", float) = 45
			//[KeywordEnum(General, Frame directed)] _FrameMode("Frame Mode (Frame Only)", Float) = 0

			[Header(Image Settings)]
			_FrameTex("Frame Texture", 2D) = "white" {}
			_ImageOutline("Outline Color Base", Color) = (1,1,1,1)
			[KeywordEnum(Stretch, Tile)] _TileMode("Frame mode", Float) = 0
	}

		SubShader
			{
				Tags
				{
					"Queue" = "Transparent"
					"IgnoreProjector" = "True"
					"RenderType" = "Transparent"
					"PreviewType" = "Plane"
					"CanUseSpriteAtlas" = "True"
				}

				Cull Off
				Lighting Off
				ZWrite Off
				Blend One OneMinusSrcAlpha

				Pass
				{
				CGPROGRAM
					#pragma vertex vert
					#pragma fragment frag
					#pragma multi_compile _ PIXELSNAP_ON
					#pragma exclude_renderers d3d11_9x

					#include "UnityCG.cginc"

					struct appdata_t
					{
						float4 vertex   : POSITION;
						float4 color    : COLOR;
						float2 texcoord : TEXCOORD0;
					};

					struct v2f
					{
						float4 vertex   : SV_POSITION;
						fixed4 color : COLOR;
						float2 texcoord  : TEXCOORD0;
					};

					fixed4 _Color;
					fixed _Thickness;
					fixed _OutlineEnabled;
					fixed _ConnectedAlpha;
					fixed _OutlineShape;
					fixed _OutlinePosition;
					fixed _OutlineMode;

					fixed4 _SolidOutline;

					fixed4 _GradientOutline1;
					fixed4 _GradientOutline2;
					fixed _Weight;
					fixed _AlphaThreshold;
					fixed _Angle;
					//fixed _FrameMode;

					fixed4 _ImageOutline;
					fixed _TileMode;

					v2f vert(appdata_t IN)
					{
						v2f OUT;
						OUT.vertex = UnityObjectToClipPos(IN.vertex);
						OUT.texcoord = IN.texcoord;
						OUT.color = IN.color * _Color;
						#ifdef PIXELSNAP_ON
						OUT.vertex = UnityPixelSnap(OUT.vertex);
						#endif

						return OUT;
					}

					sampler2D _MainTex;
					sampler2D _AlphaTex;
					float _AlphaSplitEnabled;
					uniform float4 _MainTex_TexelSize;

					sampler2D _FrameTex;
					uniform float4 _FrameTex_TexelSize;
					uniform float4 _FrameTex_ST;

					fixed4 SampleSpriteTexture(float2 uv)
					{
						float2 offsets;
						if ((_OutlinePosition != 2 && _OutlineShape == 1) || _OutlineEnabled == 0) // not outside and frame
						{
							offsets = float2(0, 0);
						}
						else
						{
							offsets = float2(_Thickness * 2, _Thickness * 2);
						}
						float2 bigsize = float2(_MainTex_TexelSize.z, _MainTex_TexelSize.w);
						float2 smallsize = float2(_MainTex_TexelSize.z - offsets.x, _MainTex_TexelSize.w - offsets.y);

						float2 uv_changed = float2
						(
							uv.x * bigsize.x / smallsize.x - 0.5 * offsets.x / smallsize.x,
							uv.y * bigsize.y / smallsize.y - 0.5 * offsets.y / smallsize.y
						);

						if (uv_changed.x < 0 || uv_changed.x > 1 || uv_changed.y < 0 || uv_changed.y > 1)
						{
							return float4(0, 0, 0, 0);
						}

						fixed4 color = tex2D(_MainTex, uv_changed);

		#if UNITY_TEXTURE_ALPHASPLIT_ALLOWED
						if (_AlphaSplitEnabled)
							color.a = tex2D(_AlphaTex, uv).r;
		#endif //UNITY_TEXTURE_ALPHASPLIT_ALLOWED

						return color;
					}

					bool CheckOriginalSpriteTexture(float2 uv, bool ifZero)
					{
						float thicknessX = _Thickness / _MainTex_TexelSize.z;
						float thicknessY = _Thickness / _MainTex_TexelSize.w;
						int steps = 100;
						float angle_step = 360.0 / steps;

						float alphaThreshold = _AlphaThreshold / 10;
						float alphaCount = _AlphaThreshold * 10;

						// check if the basic points has an alpha to speed up the process and not use the for loop
						bool outline = false;
						float alphaCounter = 0;

						if (ifZero)
						{

						}
						else
						{
							outline = SampleSpriteTexture(uv + fixed2(0, +thicknessY)).a > alphaThreshold ||
										SampleSpriteTexture(uv + fixed2(0, -thicknessY)).a > alphaThreshold ||
										SampleSpriteTexture(uv + fixed2(+thicknessX, 0)).a > alphaThreshold ||
										SampleSpriteTexture(uv + fixed2(-thicknessX, 0)).a > alphaThreshold ||
										SampleSpriteTexture(uv + fixed2(+thicknessX * cos(3.14 / 4), -thicknessY * sin(3.14 / 4))).a > alphaThreshold ||
										SampleSpriteTexture(uv + fixed2(-thicknessX * cos(3.14 / 4), +thicknessY * sin(3.14 / 4))).a > alphaThreshold ||
										SampleSpriteTexture(uv + fixed2(-thicknessX * cos(3.14 / 4), -thicknessY * sin(3.14 / 4))).a > alphaThreshold ||
										SampleSpriteTexture(uv + fixed2(+thicknessX * cos(3.14 / 4), +thicknessY * sin(3.14 / 4))).a > alphaThreshold;
						}
						if (outline) return outline;

						for (int i = 0; i < steps; i++) // high number and not a variable to avoid stupid compiler bugs
						{
							float angle = i * angle_step * 2 * 3.14 / 360;
							if (ifZero && SampleSpriteTexture(uv + fixed2(thicknessX * cos(angle), thicknessY * sin(angle))).a == 0)
							{
								alphaCounter++;
								if (alphaCounter >= alphaCount)
								{
									outline = true;
									break;
								}
							}
							else if (!ifZero && SampleSpriteTexture(uv + fixed2(thicknessX * cos(angle), thicknessY * sin(angle))).a > alphaThreshold)
							{
								outline = true;
								break;
							}
						}

						return outline;
					}

					fixed4 frag(v2f IN) : SV_Target
					{
						float thicknessX = _Thickness / _MainTex_TexelSize.z;
						float thicknessY = _Thickness / _MainTex_TexelSize.w;

						fixed4 c = SampleSpriteTexture(IN.texcoord) * IN.color;

						c.rgb *= c.a;

						fixed alpha;

						fixed4 outlineC = fixed4(0, 0, 0, 1);

						if (_OutlineEnabled != 0)
						{
							if (_OutlineMode == 0) // Solid
							{
								outlineC = _SolidOutline;

								if (_ConnectedAlpha != 0)
								{
									outlineC.a *= _Color.a;
								}
								outlineC.rgb *= outlineC.a;
							}
							else if (_OutlineMode == 1) // Gradient
							{
								float x = IN.texcoord.x;
								float y = IN.texcoord.y;

								float ratio1 = 0;
								float ratio2 = 0;

								if (_OutlineShape == 0) // contour
								{
									if (
										((_OutlinePosition != 2 && _OutlineShape == 1) && c.a != 0 &&  // inside and frame
											(
												IN.texcoord.y + thicknessY > 1 ||
												IN.texcoord.y - thicknessY < 0 ||
												IN.texcoord.x + thicknessX > 1 ||
												IN.texcoord.x - thicknessX < 0 ||
												CheckOriginalSpriteTexture(IN.texcoord, true)
											)
										)
										||
										((_OutlinePosition == 2 || _OutlineShape != 1) && c.a == 0 &&   // outside or contour
											CheckOriginalSpriteTexture(IN.texcoord, false)
										)
									)
									{
										if (_Angle >= 360)
										{
											int div = _Angle / 360;
											_Angle = (_Angle / 360 - div) * 360;
										}
										_Angle *= 2 * 3.14 / 360;

										ratio1 = (0.5 - x) * cos(_Angle) + (0.5 - y) * sin(_Angle) + 0.5;
										ratio2 = (x - 0.5) * cos(_Angle) + (y - 0.5) * sin(_Angle) + 0.5;

										ratio1 *= 2 * _Weight;
										ratio2 *= 2 * (1 - _Weight);

										if (_ConnectedAlpha != 0)
										{
											_GradientOutline1.a *= _Color.a;
											_GradientOutline2.a *= _Color.a;
											//outlineC.rgb *= outlineC.a;
										}
										_GradientOutline1.rgb *= _GradientOutline1.a;
										_GradientOutline2.rgb *= _GradientOutline2.a;
										outlineC = _GradientOutline1 * ratio1 + _GradientOutline2 * ratio2;
									}
								}
								else if (_OutlineShape == 1) // frame
								{
									if (IN.texcoord.y + thicknessY > 1 ||
										IN.texcoord.y - thicknessY < 0 ||
										IN.texcoord.x + thicknessX > 1 ||
										IN.texcoord.x - thicknessX < 0)
									{
										// between down left to up left
										if (y * thicknessX - x * thicknessY > 0 &&
											y * thicknessX + x * thicknessY - thicknessX < 0 &&
											x < 0.5f)
										{
											ratio1 = 1 - x / thicknessX;
											ratio2 = x / thicknessX;
										}
										// between down left to down right
										else if (y * thicknessX - x * thicknessY < 0 &&
												y * thicknessX + x * thicknessY - thicknessY < 0 &&
												y < 0.5f)
										{
											ratio1 = 1 - y / thicknessY;
											ratio2 = y / thicknessY;
										}
										// between down right to up right
										else if (y * thicknessX - x * thicknessY - thicknessX + thicknessY < 0 &&
												y * thicknessX + x * thicknessY - thicknessY > 0 &&
												x > 0.5f)
										{
											ratio1 = (x - 1) / thicknessX + 1;
											ratio2 = -(x - 1) / thicknessX;
										}
										// between up left to up right
										else if (y * thicknessX - x * thicknessY - thicknessX + thicknessY > 0 &&
												y * thicknessX + x * thicknessY - thicknessX > 0 &&
												y > 0.5f)
										{
											ratio1 = (y - 1) / thicknessY + 1;
											ratio2 = -(y - 1) / thicknessY;
										}

										ratio1 *= 2 * _Weight;
										ratio2 *= 2 * (1 - _Weight);

										if (_ConnectedAlpha != 0)
										{
											_GradientOutline1.a *= _Color.a;
											_GradientOutline2.a *= _Color以上是关于Unity Shader入门☀️ | 使用Shader实现一个 图片边框 ✨制作!的主要内容,如果未能解决你的问题,请参考以下文章

unity shader有啥用

小功能⭐️Unity2018 Shader Graph——全息影像物体消融

小功能⭐️Unity2018 Shader Graph——全息影像物体消融

小功能⭐️Unity2018 Shader Graph——全息影像物体消融

unity之模糊背景(带你欣赏女人的朦胧美)

unity之模糊背景(带你欣赏女人的朦胧美)