반응형
TextmeshPro기반의 BitmapFont 사용할때 SDF쉐이더가 아닌 Sprite쉐이더를 사용합니다.
해당 쉐이더에는 Shadow기능이 없어 별도 Shadow 컴포넌트를 제작했습니다.
(MeshRenderer에서만 사용가능)
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// TextMeshPro - MeshRenderer전용 Shadow 효과
/// </summary>
[ExecuteInEditMode]
public class TMPSpriteShadow : MonoBehaviour
{
[SerializeField] private Color m_EffectColor = new Color(0f, 0f, 0f, 0.5f);
[SerializeField] private Vector2 m_EffectDistance = new Vector2(1f, -1f);
[SerializeField] private bool m_UseGraphicAlpha = true;
private TMP_Text m_TextComponent;
private void Awake()
{
m_TextComponent = GetComponent<TMP_Text>();
}
private void OnEnable()
{
if (m_TextComponent == null) m_TextComponent = GetComponent<TMP_Text>();
TMPro_EventManager.TEXT_CHANGED_EVENT.Add(ON_TEXT_CHANGED); // TMP 수정 이벤트 콜백 등록
SetVerticesDirty();
}
private void OnDisable()
{
TMPro_EventManager.TEXT_CHANGED_EVENT.Remove(ON_TEXT_CHANGED); // TMP 수정 이벤트 콜백 삭제
SetVerticesDirty();
}
// Inspector 값 수정시 콜백 호출
private void OnValidate()
{
SetVerticesDirty();
}
protected virtual void LateUpdate()
{
if (isActiveAndEnabled && m_TextComponent)
{
if (m_TextComponent.havePropertiesChanged)
{
SetVerticesDirty(); // TMP컴포넌트 수정시 호출
}
}
}
// TMP 텍스트 변화 콜백 함수
private void ON_TEXT_CHANGED(Object obj)
{
TMP_TextInfo textInfo = m_TextComponent.textInfo;
if (m_TextComponent != obj || textInfo.characterCount - textInfo.spaceCount <= 0)
return;
VertexHelper s_VertexHelper = new VertexHelper();
for (int i=0;i<textInfo.meshInfo.Length;i++)
{
Mesh mesh = textInfo.meshInfo[i].mesh;
if (mesh == null) continue;
FillVertexHelper(s_VertexHelper, mesh); // VertexHelper 수동 구성
ModifyMesh(s_VertexHelper); // TMP Mesh 수정
s_VertexHelper.FillMesh(mesh);
}
}
// TMP 오브젝트 Mesh 수정 (그림자 메쉬 추가)
private void ModifyMesh(VertexHelper vh)
{
if (!isActiveAndEnabled || vh.currentVertCount <= 0)
return;
List<UIVertex> s_Verts = new List<UIVertex>();
vh.GetUIVertexStream(s_Verts);
int start = 0;
int end = s_Verts.Count;
ApplyShadow(s_Verts, m_EffectColor, start, end, m_EffectDistance, m_UseGraphicAlpha);
vh.Clear();
vh.AddUIVertexTriangleStream(s_Verts);
s_Verts.Clear();
}
// Mesh 버텍스 정보 갱신
private void SetVerticesDirty()
{
if (m_TextComponent == null) return;
for(int i=0;i< m_TextComponent.textInfo.meshInfo.Length;i++)
{
TMP_MeshInfo info = m_TextComponent.textInfo.meshInfo[i];
Mesh mesh = info.mesh;
if (mesh == null) continue;
mesh.Clear();
mesh.vertices = info.vertices;
mesh.uv = info.uvs0;
mesh.colors32 = info.colors32;
mesh.triangles = info.triangles;
}
m_TextComponent.havePropertiesChanged = true;
}
// VertexHelper 수동 구성
private void FillVertexHelper(VertexHelper vh, Mesh mesh)
{
List<Vector2> s_Uv0 = new List<Vector2>();
List<Vector3> s_Vertices = new List<Vector3>();
List<int> s_Indices = new List<int>();
List<Color32> s_Colors = new List<Color32>();
mesh.GetVertices(s_Vertices);
mesh.GetColors(s_Colors);
mesh.GetUVs(0, s_Uv0);
mesh.GetIndices(s_Indices, 0);
vh.Clear();
for (int i = 0; i < s_Vertices.Count; i++)
{
vh.AddVert(s_Vertices[i], s_Colors[i], s_Uv0[i]);
}
for (int i = 0; i < s_Indices.Count; i += 3)
{
vh.AddTriangle(s_Indices[i], s_Indices[i + 1], s_Indices[i + 2]);
}
}
private void ApplyShadow(List<UIVertex> verts, Color color, int start, int end, Vector2 effectDistance, bool useGraphicAlpha)
{
if (color.a <= 0)
return;
ApplyShadowZeroAlloc(verts, color, start, end, effectDistance.x, effectDistance.y, useGraphicAlpha);
}
// Shadow 버텍스 추가
private void ApplyShadowZeroAlloc(List<UIVertex> verts, Color color, int start, int end, float x, float y, bool useGraphicAlpha)
{
int count = end - start;
int neededCapacity = verts.Count + count;
if (verts.Capacity < neededCapacity)
verts.Capacity = neededCapacity;
UIVertex vt = default(UIVertex);
for (int i = 0; i < count; ++i)
{
vt = verts[i];
verts.Add(vt);
Vector3 v = vt.position;
vt.position.Set(v.x + x, v.y + y, v.z);
Color vertColor = color;
vertColor.a = useGraphicAlpha ? color.a * vt.color.a / 255 : color.a;
vt.color = vertColor;
verts[i] = vt;
}
}
}
참고자료
- https://github.com/mob-sakai/MeshEffectForTextMeshPro
반응형
'Unity' 카테고리의 다른 글
AI Skybox Generator (0) | 2023.04.03 |
---|---|
Unity Hub 에디터 커맨드 라인 인자 - 특정 그래픽 API로 에디터 실행 (0) | 2023.03.07 |
[Unity] 블루스택으로 유니티 프로파일링하기 (1) | 2022.05.18 |
URP 커스텀 Unlit Shader (1) | 2021.12.02 |
Shader Graph 에디터 에러 발생시 해결법 (0) | 2021.12.01 |
WRITTEN BY
- CatDarkGame
Technical Artist dhwlgn12@gmail.com
,