-
-
Save dotsquid/7b855916723ff0771355c929de6b1cd8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEngine.UI; | |
using SC.Utilities; | |
using TMPro; | |
[ExecuteAlways] | |
[RequireComponent(typeof(TMP_Text))] | |
public class TextMeshProSubdivisionEffect : MonoBehaviour | |
{ | |
private static readonly Vector2 kVector2Up = Vector2.up; | |
private static readonly Vector2 kVector2One = Vector2.one; | |
private static readonly Vector2 kVector2Right = Vector2.right; | |
[SerializeField] | |
private int _subdivisionLevel = 2; | |
private TMP_Text _text; | |
private bool _isModifying; | |
#if UNITY_EDITOR | |
protected void OnValidate() | |
{ | |
_subdivisionLevel = Mathf.Max(_subdivisionLevel, 1); | |
SubdivideText(); | |
} | |
#endif | |
private void Awake() | |
{ | |
TryCaptureComponent(); | |
SubdivideText(); | |
} | |
private void OnDestroy() | |
{ | |
if (_text != null) | |
{ | |
_text.OnPreRenderText -= OnPreRenderText; | |
} | |
} | |
private void OnEnable() | |
{ | |
TMPro_EventManager.TEXT_CHANGED_EVENT.Add(OnTextChanged); | |
} | |
private void OnDisable() | |
{ | |
TMPro_EventManager.TEXT_CHANGED_EVENT.Remove(OnTextChanged); | |
} | |
private void TryCaptureComponent() | |
{ | |
if (TryGetComponent(out _text)) | |
{ | |
_text.OnPreRenderText += OnPreRenderText; | |
} | |
} | |
private void OnTextChanged(Object obj) | |
{ | |
if (obj == _text) | |
SubdivideText(); | |
} | |
private void OnPreRenderText(TMP_TextInfo textInfo) | |
{ | |
#if NOPE | |
var meshInfos = textInfo.meshInfo; | |
for (int i = 0, count = meshInfos.Length; i < count; ++i) | |
{ | |
var meshInfo = meshInfos[i]; | |
SubdivideMesh(ref meshInfo, _subdivisionLevel); | |
} | |
#endif | |
} | |
private void SubdivideText() | |
{ | |
if (!_isModifying && _text != null) | |
{ | |
_isModifying = true; | |
//_text.ForceMeshUpdate(); | |
_text.UpdateVertexData(); | |
var textInfo = _text.textInfo; | |
var meshInfo = textInfo.meshInfo; | |
for (int i = 0, count = meshInfo.Length; i < count; ++i) | |
{ | |
var mesh = meshInfo[i].mesh; | |
using (var vh = new VertexHelper(mesh)) | |
{ | |
SubdivideMesh(vh, _subdivisionLevel); | |
vh.FillMesh(mesh); | |
_text.UpdateGeometry(mesh, i); | |
} | |
} | |
_isModifying = false; | |
} | |
} | |
#if NOPE | |
private void SubdivideMesh(ref TMP_MeshInfo meshInfo, int level) | |
{ | |
int vertsCount = meshInfo.vertexCount; | |
int quadsCount = vertsCount / 6; | |
int subQuadsPerAxis = level; | |
int subQuadsPerQuad = subQuadsPerAxis * subQuadsPerAxis; | |
int totalQuads = quadsCount * subQuadsPerQuad; | |
float quadIndexStep = 1.0f / (totalQuads - 1); | |
float t = 1.0f / subQuadsPerAxis; | |
var shuffledQuadIndicies = GetContinuousArray(totalQuads); | |
var quadVerts = new UIVertex[4]; | |
var subQuadVerts = new UIVertex[4]; | |
for (int i = 0; i < quadsCount; ++i) | |
{ | |
quadVerts[0] = Extract(ref meshInfo, i * 6 + 0); | |
quadVerts[1] = Extract(ref meshInfo, i * 6 + 1); | |
quadVerts[2] = Extract(ref meshInfo, i * 6 + 2); | |
quadVerts[3] = Extract(ref meshInfo, i * 6 + 4); | |
for (int y = 0; y < subQuadsPerAxis; ++y) | |
{ | |
for (int x = 0; x < subQuadsPerAxis; ++x) | |
{ | |
float tx0 = t * x; | |
float ty0 = t * y; | |
float tx1 = t + tx0; | |
float ty1 = t + ty0; | |
Lerp(ref subQuadVerts[0], quadVerts, tx0, ty0); | |
Lerp(ref subQuadVerts[1], quadVerts, tx1, ty0); | |
Lerp(ref subQuadVerts[2], quadVerts, tx1, ty1); | |
Lerp(ref subQuadVerts[3], quadVerts, tx0, ty1); | |
int quadIndex = x + y * subQuadsPerAxis + i * subQuadsPerQuad; | |
float invQuadIndex = shuffledQuadIndicies[quadIndex] * quadIndexStep; | |
var uv2 = invQuadIndex * kVector2One; | |
subQuadVerts[0].uv2 = uv2; | |
subQuadVerts[1].uv2 = uv2; | |
subQuadVerts[2].uv2 = uv2; | |
subQuadVerts[3].uv2 = uv2; | |
//SetUV2(subQuadVerts, uv2); | |
//vh.AddUIVertexQuadFull(subQuadVerts); | |
} | |
} | |
} | |
} | |
#endif | |
private void SubdivideMesh(VertexHelper vh, int level) | |
{ | |
var verts = new List<UIVertex>(); | |
vh.GetUIVertexStream(verts); | |
vh.Clear(); | |
int vertsCount = verts.Count; | |
int quadsCount = vertsCount / 6; | |
int subQuadsPerAxis = level; | |
int subQuadsPerQuad = subQuadsPerAxis * subQuadsPerAxis; | |
int totalQuads = quadsCount * subQuadsPerQuad; | |
float quadIndexStep = 1.0f / (totalQuads - 1); | |
var shuffledQuadIndicies = GetContinuousArray(totalQuads); | |
var quadVerts = new UIVertex[4]; | |
var subQuadVerts = new UIVertex[4]; | |
for (int i = 0; i < quadsCount; ++i) | |
{ | |
quadVerts[0] = verts[i * 6 + 0]; | |
quadVerts[1] = verts[i * 6 + 1]; | |
quadVerts[2] = verts[i * 6 + 2]; | |
quadVerts[3] = verts[i * 6 + 4]; | |
float t = 1.0f / subQuadsPerAxis; | |
// Since this effect is intended to be used with text | |
// which has the same color for all vertices | |
// we can use the color of the first vertex. | |
// But proper color interpolation for vertices | |
// being inserted is highly welcome. | |
var vertexPreset = new UIVertex() | |
{ | |
color = quadVerts[0].color | |
}; | |
for (int y = 0; y < subQuadsPerAxis; ++y) | |
{ | |
for (int x = 0; x < subQuadsPerAxis; ++x) | |
{ | |
float tx0 = t * x; | |
float ty0 = t * y; | |
float tx1 = t + tx0; | |
float ty1 = t + ty0; | |
Lerp(ref subQuadVerts[0], quadVerts, tx0, ty0); | |
Lerp(ref subQuadVerts[1], quadVerts, tx1, ty0); | |
Lerp(ref subQuadVerts[2], quadVerts, tx1, ty1); | |
Lerp(ref subQuadVerts[3], quadVerts, tx0, ty1); | |
int quadIndex = x + y * subQuadsPerAxis + i * subQuadsPerQuad; | |
float invQuadIndex = shuffledQuadIndicies[quadIndex] * quadIndexStep; | |
var uv2 = invQuadIndex * kVector2One; | |
subQuadVerts[0].uv2 = uv2; | |
subQuadVerts[1].uv2 = uv2; | |
subQuadVerts[2].uv2 = uv2; | |
subQuadVerts[3].uv2 = uv2; | |
//SetUV2(subQuadVerts, uv2); | |
vh.AddUIVertexQuadFull(subQuadVerts); | |
} | |
} | |
} | |
} | |
private static void SetUV2(UIVertex[] verts, Vector2 uv2) | |
{ | |
{ | |
var vert = verts[0]; | |
vert.uv2 = uv2; | |
verts[0] = vert; | |
} | |
{ | |
var vert = verts[1]; | |
vert.uv2 = uv2; | |
verts[1] = vert; | |
} | |
{ | |
var vert = verts[2]; | |
vert.uv2 = uv2; | |
verts[2] = vert; | |
} | |
{ | |
var vert = verts[3]; | |
vert.uv2 = uv2; | |
verts[3] = vert; | |
} | |
} | |
private static void Lerp(ref UIVertex result, UIVertex[] verts, float tx, float ty) | |
{ | |
UIVertex v01 = Lerp(ref verts[0], ref verts[1], tx); | |
UIVertex v32 = Lerp(ref verts[3], ref verts[2], tx); | |
Lerp(ref result, ref v01, ref v32, ty); | |
} | |
private static void Lerp(ref UIVertex result, ref UIVertex a, ref UIVertex b, float t) | |
{ | |
var aPos = a.position; | |
var aUV0 = a.uv0; | |
var aUV1 = a.uv1; | |
var aUV2 = a.uv2; | |
var aUV3 = a.uv3; | |
var aC = a.color; | |
var bPos = b.position; | |
var bUV0 = b.uv0; | |
var bUV1 = b.uv1; | |
var bUV2 = b.uv2; | |
var bUV3 = b.uv3; | |
var bC = b.color; | |
result.position = Vector2.Lerp(aPos, bPos, t); | |
result.uv0 = Vector2.Lerp(aUV0, bUV0, t); | |
result.uv1 = Vector2.Lerp(aUV1, bUV1, t); | |
result.uv2 = Vector2.Lerp(aUV2, bUV2, t); | |
result.uv3 = Vector2.Lerp(aUV3, bUV3, t); | |
result.color = Color.Lerp(aC, bC, t); | |
} | |
private static UIVertex Lerp(ref UIVertex a, ref UIVertex b, float t) | |
{ | |
UIVertex result = default; | |
Lerp(ref result, ref a, ref b, t); | |
return result; | |
} | |
private static UIVertex Lerp(UIVertex[] verts, float tx, float ty) | |
{ | |
UIVertex result = default; | |
Lerp(ref result, verts, tx, ty); | |
return result; | |
} | |
private static UIVertex Extract(ref TMP_MeshInfo meshInfo, int index) | |
{ | |
return new UIVertex() | |
{ | |
position = meshInfo.vertices[index], | |
normal = meshInfo.normals[index], | |
tangent = meshInfo.tangents[index], | |
color = meshInfo.colors32[index], | |
uv0 = meshInfo.uvs0[index], | |
uv1 = meshInfo.uvs2[index] | |
}; | |
} | |
private int[] GetContinuousArray(int count, int startValue = 0) | |
{ | |
int[] array = new int[count]; | |
for (int i = 0; i < count; ++i) | |
{ | |
array[i] = startValue + i; | |
} | |
return array; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment