Skip to content

Instantly share code, notes, and snippets.

@nndwn
Last active May 6, 2024 00:22
Show Gist options
  • Save nndwn/5a6193474da03f20a71c0c184689457c to your computer and use it in GitHub Desktop.
Save nndwn/5a6193474da03f20a71c0c184689457c to your computer and use it in GitHub Desktop.
Jitter TextMeshPro
using System.Collections;
using TMPro;
using UnityEngine;
using Object = UnityEngine.Object;
using Random = UnityEngine.Random;
public class VertexJitter : MonoBehaviour
{
private const float AngleMultiplier = 0.5f;
private const float CurveScale = 0f;
public bool play;
private TMP_Text _textComponent;
private bool _hasTextChanged;
private bool _isAnimating;
public Coroutine playing;
private struct VertexAnim
{
public float angleRange;
public float angle;
public float speed;
}
public void Play(bool animate)
{
play = false;
_isAnimating = animate;
if (_isAnimating)
{
playing = StartCoroutine(AnimateVertexColors());
}
}
private void OnEnable()
{
TMPro_EventManager.TEXT_CHANGED_EVENT.Add(ON_TEXT_CHANGED);
_textComponent = GetComponent<TMP_Text>();
if (play)
{
playing = StartCoroutine(AnimateVertexColors());
}
}
private void OnDisable()
{
TMPro_EventManager.TEXT_CHANGED_EVENT.Remove(ON_TEXT_CHANGED);
}
private void ON_TEXT_CHANGED(Object obj)
{
if (obj == _textComponent)
_hasTextChanged = true;
}
private IEnumerator AnimateVertexColors()
{
_textComponent.ForceMeshUpdate();
var textInfo = _textComponent.textInfo;
var loopCount = 0;
_hasTextChanged = true;
var vertexAnims = new VertexAnim[1024];
for (var i = 0; i < vertexAnims.Length; i++)
{
vertexAnims[i].angleRange = Random.Range(10f, 25f);
vertexAnims[i].speed = Random.Range(1f, 3f);
}
var cacheMeshInfo = textInfo.CopyMeshInfoVertexData();
while (true)
{
if (_hasTextChanged)
{
cacheMeshInfo = textInfo.CopyMeshInfoVertexData();
_hasTextChanged = false;
}
var characterCount = textInfo.characterCount;
for (var i = 0; i < characterCount; i++)
{
var charInfo = textInfo.characterInfo[i];
if (!charInfo.isVisible) continue;
var vertAnim = vertexAnims[i];
var vertexIndex = textInfo.characterInfo[i].vertexIndex;
var materialIndex = textInfo.characterInfo[i].materialReferenceIndex;
var sourceVertices = cacheMeshInfo[materialIndex].vertices;
Vector2 charMidBaseline = (sourceVertices[vertexIndex + 0] + sourceVertices[vertexIndex + 2] / 2);
Vector3 offset = charMidBaseline;
var destinationVertices = textInfo.meshInfo[materialIndex].vertices;
destinationVertices[vertexIndex + 0] = sourceVertices[vertexIndex + 0] - offset;
destinationVertices[vertexIndex + 1] = sourceVertices[vertexIndex + 1] - offset;
destinationVertices[vertexIndex + 2] = sourceVertices[vertexIndex + 2] - offset;
destinationVertices[vertexIndex + 3] = sourceVertices[vertexIndex + 3] - offset;
vertAnim.angle = Mathf.SmoothStep(-vertAnim.angleRange, vertAnim.angleRange,Mathf.PingPong(loopCount / 25f * vertAnim.speed, 1f));
var jitterOffset = new Vector3(Random.Range(-.25f, .25f), Random.Range(-25f, .25f), 0);
var matrix4X4 = Matrix4x4.TRS(jitterOffset * CurveScale,
Quaternion.Euler(0, 0, Random.Range(-5f, 5f) * AngleMultiplier), Vector3.one);
destinationVertices[vertexIndex + 0] =
matrix4X4.MultiplyPoint3x4(destinationVertices[vertexIndex + 0]);
destinationVertices[vertexIndex + 1] =
matrix4X4.MultiplyPoint3x4(destinationVertices[vertexIndex + 1]);
destinationVertices[vertexIndex + 2] =
matrix4X4.MultiplyPoint3x4(destinationVertices[vertexIndex + 2]);
destinationVertices[vertexIndex + 3] =
matrix4X4.MultiplyPoint3x4(destinationVertices[vertexIndex + 3]);
destinationVertices[vertexIndex + 0] += offset;
destinationVertices[vertexIndex + 1] += offset;
destinationVertices[vertexIndex + 2] += offset;
destinationVertices[vertexIndex + 3] += offset;
vertexAnims[i] = vertAnim;
}
for (var i = 0; i < textInfo.meshInfo.Length; i++)
{
textInfo.meshInfo[i].mesh.vertices = textInfo.meshInfo[i].vertices;
_textComponent.UpdateGeometry(textInfo.meshInfo[i].mesh, i);
}
loopCount += 1;
yield return new WaitForSeconds(0.1f);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment