프로그래밍/유니티

[유니티] Curved Text

갓똥 2022. 8. 29. 12:23
728x90
반응형

 

using UnityEngine;
using TMPro;

[ExecuteInEditMode]
public class CurvedText : MonoBehaviour
{
	private TextMeshProUGUI _textComponent;

	[SerializeField]
	private AnimationCurve vertexCurve = new(new Keyframe (0.0f, 0.1f), new Keyframe (0.5f, 0.0f), new Keyframe (1.0f, 0.1f));
	[SerializeField]
	private float curveScale = 100.0f;

	private void Awake ()
	{
		_textComponent = gameObject.GetComponent<TextMeshProUGUI> ();
	}

	private void Update ()
	{
		if (!_textComponent.havePropertiesChanged) 
		{
			return;
		}

		UpdateCurveMesh ();
	}

	private void UpdateCurveMesh ()
	{
		_textComponent.ForceMeshUpdate();

		var textInfo = _textComponent.textInfo;
		var characterCount = textInfo.characterCount;

		if (characterCount == 0)
			return;

		var boundsMinX = _textComponent.bounds.min.x;
		var boundsMaxX = _textComponent.bounds.max.x;

		for (int i = 0; i < characterCount; i++) 
		{
			if (!textInfo.characterInfo [i].isVisible)
				continue;

			int vertexIndex = textInfo.characterInfo [i].vertexIndex;

			int materialIndex = textInfo.characterInfo [i].materialReferenceIndex;
			var vertices = textInfo.meshInfo [materialIndex].vertices;

			Vector3 offsetToMidBaseline = new Vector2 ((vertices [vertexIndex + 0].x + vertices [vertexIndex + 2].x) / 2, textInfo.characterInfo [i].baseLine);

			vertices [vertexIndex + 0] += -offsetToMidBaseline;
			vertices [vertexIndex + 1] += -offsetToMidBaseline;
			vertices [vertexIndex + 2] += -offsetToMidBaseline;
			vertices [vertexIndex + 3] += -offsetToMidBaseline;

			float x0 = (offsetToMidBaseline.x - boundsMinX) / (boundsMaxX - boundsMinX); // Character's position relative to the bounds of the mesh.
			float x1 = x0 + 0.0001f;
			float y0 = vertexCurve.Evaluate (x0) * curveScale;
			float y1 = vertexCurve.Evaluate (x1) * curveScale;
			float charSize = boundsMaxX - boundsMinX;
			Vector3 horizontal = new Vector3 (1, 0, 0);
			Vector3 tangent = new Vector3 (charSize * 0.0001f, y1 - y0);
			float angle = Mathf.Acos (Vector3.Dot (horizontal, tangent.normalized)) * Mathf.Rad2Deg;
			Vector3 cross = Vector3.Cross (horizontal, tangent);
			angle = cross.z > 0 ? angle : 360 - angle;

			var matrix = Matrix4x4.TRS (new Vector3 (0, y0, 0), Quaternion.Euler (0, 0, angle), Vector3.one);
			vertices [vertexIndex + 0] = matrix.MultiplyPoint3x4 (vertices [vertexIndex + 0]);
			vertices [vertexIndex + 1] = matrix.MultiplyPoint3x4 (vertices [vertexIndex + 1]);
			vertices [vertexIndex + 2] = matrix.MultiplyPoint3x4 (vertices [vertexIndex + 2]);
			vertices [vertexIndex + 3] = matrix.MultiplyPoint3x4 (vertices [vertexIndex + 3]);

			vertices [vertexIndex + 0] += offsetToMidBaseline;
			vertices [vertexIndex + 1] += offsetToMidBaseline;
			vertices [vertexIndex + 2] += offsetToMidBaseline;
			vertices [vertexIndex + 3] += offsetToMidBaseline;
		}

		_textComponent.UpdateVertexData ();
	}

#if UNITY_EDITOR
	protected virtual void OnValidate()
	{
		UpdateCurveMesh ();
	}

	private void OnEnable()
	{
		UpdateCurveMesh ();
	}

	private void OnDisable()
	{
		_textComponent.ForceMeshUpdate();
	}
#endif
}

스크립트 작성 후 텍스트 컴포넌트에 붙여서 쓰면 된다.

728x90
반응형