简介 记录研究 Text Animator 插件的实现Text Animator
Text的区别 TextMesh 是将每个字符都作为一个Mesh进行渲染显示,相对于原先 Text 将整体划分为一个 Mesh,可拓展性更高
字体的显示 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Shader "TextMeshPro/Bitmap" { Properties { _MainTex ("Font Atlas" , 2 D) = "white" {} _FaceTex ("Font Texture" , 2 D) = "white" {} _FaceColor ("Text Color" , Color) = (1 ,1 ,1 ,1 ) } fixed4 frag (v2f IN) : SV_Target { fixed4 color = tex2D (_MainTex, IN.texcoord0); color = fixed4 (tex2D (_FaceTex, IN.texcoord1).rgb * IN.color.rgb, IN.color.a * color.a); } }
其中 MainTex 的 Alpha 通道存储文字的遮罩 FaceTex 对应着 文本的字体贴图,切换这张贴图可以实现字体的切换
主要组件 TextAnimatorPlayer 默认TextAnimatorPlayer,可以动态显示字母(就像打字机一样)
TextAnimator 控制文本的效果显示
function UpdateEffectsToMesh
实现思路 从 TextMeshProUGUI 组件内容中,解析其中的标签,注册到行为中,获取 Mesh 的顶点数据、顶点色数据,修改后再赋予给 Mesh 自己实现的效果,简单的修改 Mesh 顶点x坐标 你的浏览器不支持播放该视频
源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 using System.Collections;using System.Collections.Generic;using TMPro;using UnityEngine;public class VertexData { public Vector3[] vertices=new Vector3[4 ]; public Color32[] color = new Color32[4 ]; } public class AnimationTest : MonoBehaviour { public float timeInterval = 2 ; private VertexData[] vertexDatas; TMP_TextInfo textInfo; TMP_Text tmp_text; void Start () { tmp_text = GetComponent<TMP_Text>(); textInfo = tmp_text.GetTextInfo(tmp_text.text); vertexDatas = new VertexData[textInfo.characterCount]; for (int z = 0 ; z < vertexDatas.Length; z++) { vertexDatas[z] = new VertexData(); for (int k = 0 ; k < 4 ; k++) { vertexDatas[z].vertices[k] = textInfo.meshInfo[textInfo.characterInfo[z].materialReferenceIndex].vertices[textInfo.characterInfo[z].vertexIndex + k]; vertexDatas[z].color[k] = textInfo.meshInfo[textInfo.characterInfo[z].materialReferenceIndex].colors32[textInfo.characterInfo[z].vertexIndex + k]; } } } float lastTime = 0 ; Vector3 vector = Vector3.zero; void Update () { if (Time.realtimeSinceStartup - lastTime > timeInterval) { vector.x = Random.Range(-1f , 1f ) * 10 ; lastTime = Time.realtimeSinceStartup; for (int z = 0 ; z < vertexDatas.Length; z++) { vertexDatas[z].vertices = MoveChar(vertexDatas[z].vertices, vector); vertexDatas[z].color = RandomColor(); } UpdateMesh(); } } private Color32[] RandomColor () { Color32[] colors = new Color32[4 ]; Color32 color = new Color32((byte )Random.Range(155 , 255 ), (byte )Random.Range(155 , 255 ), (byte )Random.Range(155 , 255 ), 255 ); for (int k = 0 ; k < 4 ; k++) { colors[k] = color; } return colors; } private void UpdateMesh () { for (int z = 0 ; z < vertexDatas.Length; z++) { for (int k = 0 ; k < 4 ; k++) { textInfo.meshInfo[textInfo.characterInfo[z].materialReferenceIndex].vertices[textInfo.characterInfo[z].vertexIndex + k] = vertexDatas[z].vertices[k]; textInfo.meshInfo[textInfo.characterInfo[z].materialReferenceIndex].colors32[textInfo.characterInfo[z].vertexIndex+k] = vertexDatas[z].color[k]; } } tmp_text.UpdateVertexData(); } private Vector3[] MoveChar (Vector3[] vec, Vector3 dir ) { for (byte j = 0 ; j < vec.Length; j++) { vec[j] += dir; } return vec; } }
UpdateEffectsToMesh 对每个 behaviorEffects 设置时间,开始计算
1 2 3 4 5 for (int i = 0 ; i < behaviorEffects.Count; i++){ behaviorEffects[i].SetAnimatorData(m_time); behaviorEffects[i].Calculate(); }
对规定区域的字符进行处理,应用 behaviorEffects 的效果
1 2 3 4 5 6 7 8 9 10 void TryApplyingBehaviors (){ if (enabled_globalBehaviors && enabled_localBehaviors) { foreach (int behaviorIndex in characters[i].indexBehaviorEffects) { behaviorEffects[behaviorIndex].ApplyEffect(ref characters[i].data, i); } } }
ShakeBehavior
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public override void Calculate (){ timePassed += time.deltaTime; if (timePassed >= shakeDelay) { timePassed = 0 ; randIndex = Random.Range(0 , TextUtilities.fakeRandomsCount); if (lastRandomIndex == randIndex) { randIndex++; if (randIndex >= TextUtilities.fakeRandomsCount) randIndex = 0 ; } lastRandomIndex = randIndex; } } public override void ApplyEffect (ref CharacterData data, int charIndex ){ data.vertices.MoveChar ( TextUtilities.fakeRandoms[ Mathf.RoundToInt((charIndex + randIndex) % (TextUtilities.fakeRandomsCount - 1 )) ] * shakeStrength * uniformIntensity ); }
WiggleBehavior
1 2 3 4 5 public override void ApplyEffect (ref CharacterData data, int charIndex ){ data.vertices.MoveChar(directions[charIndex] * Mathf.Sin(time.timeSinceStart* frequency + charIndex) * amplitude * uniformIntensity); }
FadeBehavior
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 Color32 temp; public override void ApplyEffect (ref CharacterData data, int charIndex ){ if (data.passedTime <= delay) return ; charPCTs[charIndex] += time.deltaTime; if (charPCTs[charIndex] > 1 ) charPCTs [charIndex] = 1 ; if (charPCTs[charIndex] < 1 && charPCTs[charIndex] >= 0 ) { for (var i = 0 ; i < TextUtilities.verticesPerChar; i++) { temp = data.colors[i]; temp.a = 0 ; data.colors[i] = Color32.LerpUnclamped(data.colors[i], temp, Tween.EaseInOut(charPCTs[charIndex])); } } else { for (var i = 0 ; i < TextUtilities.verticesPerChar; i++) { temp = data.colors[i]; temp.a = 0 ; data.colors[i] = temp; } } }
BounceBehavior
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public override void ApplyEffect (ref CharacterData data, int charIndex ){ float BounceTween (float t ) { const float stillTime = .2 f; const float easeIn = .2 f; const float bounce = 1 - stillTime - easeIn; if (t <= easeIn) return Tween.EaseInOut(t / easeIn); t -= easeIn; if (t <= bounce) return 1 - Tween.BounceOut(t / bounce); return 0 ; } data.vertices.MoveChar(Vector3.up * uniformIntensity * BounceTween((Mathf.Repeat(time.timeSinceStart * frequency - waveSize * charIndex, 1 ))) * amplitude); }
对于每个字符创建相应的数据,BehaviorEffect 通过修改数据中的值,实现对于 TextMesh 进行修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public struct CharacterData{ public float passedTime; public Color32[] colors; public Vector3[] vertices; public TMPro.TMP_CharacterInfo tmp_CharInfo; }