Food ji blindly forcing: mixed arrangement of pictures and texts based on UGUI (Continued)

Posted by keigowei on Wed, 26 Jan 2022 09:06:07 +0100

Last Mixed arrangement of pictures and texts

Today, when you have this demand again, you pick it up and find a better understanding by the way. For record
Direct up shader

//	Author:zouchunyi
//	E-mail:zouchunyi@kingsoft.com

Shader "UI/EmojiText" {
	Properties {
		[PerRendererData] _MainTex ("Font 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

		_EmojiTex ("Emoji Texture", 2D) = "white" {}
		_EmojiDataTex ("Emoji Data", 2D) = "white" {}
		_EmojiSize ("Emoji count of every line",float) = 200
		_FrameSpeed ("FrameSpeed",Range(0,10)) = 3
	}
	
	SubShader
	{
		Tags
		{ 
			"LightMode"="UniversalForward"
			"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]
		Blend SrcAlpha OneMinusSrcAlpha
		ColorMask [_ColorMask]

		Pass
		{
			Name "Default"
		CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma target 2.0

			#include "UnityCG.cginc"
			#include "UnityUI.cginc"

			#pragma multi_compile __ UNITY_UI_ALPHACLIP
			
			struct appdata_t
			{
				float4 vertex   : POSITION;
				float4 color    : COLOR;
				float2 texcoord : TEXCOORD0;
				float2 texcoord1 : TEXCOORD1;
			};

			struct v2f
			{
				float4 vertex   : SV_POSITION;
				fixed4 color    : COLOR;
				half2 texcoord  : TEXCOORD0;
				half2 texcoord1 : TEXCOORD1;
			};
			
			fixed4 _Color;
			fixed4 _TextureSampleAdd;
			float4 _ClipRect;

			v2f vert(appdata_t IN)

			{
				v2f OUT;
				OUT.vertex = UnityObjectToClipPos(float4(IN.vertex.x, IN.vertex.y, IN.vertex.z, 1.0));

				OUT.texcoord = IN.texcoord;
				OUT.texcoord1 = IN.texcoord1;
				
				#ifdef UNITY_HALF_TEXEL_OFFSET
				OUT.vertex.xy += (_ScreenParams.zw-1.0) * float2(-1,1) * OUT.vertex.w;
				#endif
				
				OUT.color = IN.color * _Color;
				return OUT;
			}

			sampler2D _MainTex;
			sampler2D _EmojiTex;
			sampler2D _EmojiDataTex;
		    float _EmojiSize;
			float _FrameSpeed;

			fixed4 frag(v2f IN) : SV_Target
			{
				fixed4 color;
				if (IN.texcoord1.x >0 && IN.texcoord1.y > 0)
				{
					// it's an emoji

					// compute the size of emoji
					half size = (1 / _EmojiSize);
					// compute the center uv of per pixel in the emoji
					half2 uv = half2(floor(IN.texcoord1.x * _EmojiSize) * size + 0.5 * size,floor(IN.texcoord1.y * _EmojiSize) * size + 0.5 * size);
					// read data
					fixed4 data = tex2D(_EmojiDataTex, uv);
					// compute the frame count of emoji
					half frameCount = 1 + sign(data.r) + sign(data.g) * 2 + sign(data.b) * 4;
					// compute current frame index of emoji
					half index = abs(fmod(floor(_Time.x * _FrameSpeed * 50), frameCount));
					// judge current frame is in the next line or not.
					half flag = (1 + sign(IN.texcoord1.x + index * size - 1)) * 0.5;
					// compute the final uv
					IN.texcoord1.x += index * size - flag;
					IN.texcoord1.y += size * flag;

					color = tex2D(_EmojiTex, IN.texcoord1);
				}else
				{
					// it's a text, and render it as normal ugui text
					color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
				}

				#ifdef UNITY_UI_ALPHACLIP
				clip (color.a - 0.001);
				#endif

				return color;
			}
		ENDCG
		}
	}
}

There are two important parts

In the film source shader, use if to judge whether the film element has a second set of uv coordinates (because the second set of uv coordinates is assigned to the position of the picture to be rendered in the custom text component written before, but the ordinary text does not, so it is 0 by default) to distinguish whether it is a picture or text. If it's a picture, go_ emojiTex (previously generated Photo Collection) and texcoord1 (the second set of uv coordinates) are used. The default is to use the first set of uv coordinates when the text goes down. That's it.
As for the middle ones, which are used to calculate the number of frames of animation, I haven't used them for the time being. I can comment them out directly and won't repeat them.

Difficulties encountered
Put this shader into the project and find that it has no effect. It can't even render normal text.
Problem:
Our project uses the urp pipeline, but the cg Code used by my shader is not added
"LightMode" = "UniversalForward
Just add this to the tags

Difficulty 2
When there are spaces, tabs, carriage returns and other things in the input text, the expression will fail to render and become the initial "%%"
The problem is that when calculating the vertex number of the picture in the custom imagetext component, the spaces are also included, but when generating the rendered mesh, the spaces are not rendered and are not in verts, so they are not aligned
Solution: when matching the emoticon to the input string, go to the space first, as shown in the figure

Well, that's about it~

Topics: C# Unity UGUI