如何为Unity TextMeshPro添加带自定义描边的自定义<link>标签?
实现TextMeshPro自定义发光描边标签的方案
要解决修改材质影响所有文本的问题,核心是为标签内的文本单独创建材质实例,而非直接修改原材质。以下是具体实现步骤:
1. 确认基础条件
确保你的TextMeshPro使用的Shader支持描边与发光效果,比如内置的TextMeshPro/Distance Field或TextMeshPro/Mobile/Distance Field,这类Shader默认带有描边、自发光参数。
2. 编写自定义标签处理脚本
创建一个C#脚本,挂载在带有TextMeshPro组件的对象上,实现标签解析与材质实例化逻辑:
using UnityEngine; using TMPro; [RequireComponent(typeof(TMP_Text))] public class CustomOutlineTagHandler : MonoBehaviour { private TMP_Text tmpText; // 存储材质实例,用于后续销毁避免内存泄漏 private Material outlineMaterialInstance; void Awake() { tmpText = GetComponent<TMP_Text>(); // 订阅文本更新事件,每次文本刷新时重新处理标签 tmpText.textChanged.AddListener(OnTextChanged); } void OnTextChanged() { // 销毁旧材质实例(如果存在) if (outlineMaterialInstance != null) { Destroy(outlineMaterialInstance); outlineMaterialInstance = null; } TMP_TextInfo textInfo = tmpText.textInfo; bool inOutlineTag = false; int startIndex = -1; // 遍历所有字符,识别标签范围 for (int i = 0; i < textInfo.characterCount; i++) { TMP_CharacterInfo charInfo = textInfo.characterInfo[i]; if (!charInfo.isVisible) continue; if (charInfo.textElementType == TextElementType.Tag) { string tagName = tmpText.text.Substring(charInfo.characterIndex + 1, charInfo.characterLength - 2); if (tagName == "customoutline") { if (!inOutlineTag) { inOutlineTag = true; startIndex = i + 1; // 标签后的第一个有效字符 } else { inOutlineTag = false; // 处理标签范围内的字符 ApplyOutlineToRange(startIndex, i - 1); startIndex = -1; } } } } // 处理未闭合的标签(可选逻辑) if (inOutlineTag && startIndex != -1) { ApplyOutlineToRange(startIndex, textInfo.characterCount - 1); } } void ApplyOutlineToRange(int startIndex, int endIndex) { TMP_TextInfo textInfo = tmpText.textInfo; // 创建原材质的实例副本 if (outlineMaterialInstance == null) { outlineMaterialInstance = new Material(tmpText.fontMaterial); // 自定义描边与发光参数 outlineMaterialInstance.SetFloat(ShaderUtilities.ID_OutlineWidth, 0.1f); outlineMaterialInstance.SetColor(ShaderUtilities.ID_OutlineColor, Color.cyan); outlineMaterialInstance.SetColor(ShaderUtilities.ID_GlowColor, Color.cyan); outlineMaterialInstance.SetFloat(ShaderUtilities.ID_GlowPower, 2f); } // 将材质实例添加到TextMeshPro的材质列表(如果未添加) int outlineMaterialIndex = tmpText.materials.IndexOf(outlineMaterialInstance); if (outlineMaterialIndex == -1) { outlineMaterialIndex = tmpText.materials.Count; tmpText.materials.Add(outlineMaterialInstance); } // 为范围内的字符分配材质实例 for (int i = startIndex; i <= endIndex; i++) { TMP_CharacterInfo charInfo = textInfo.characterInfo[i]; if (!charInfo.isVisible) continue; int meshIndex = charInfo.materialReferenceIndex; TMP_MeshInfo meshInfo = textInfo.meshInfo[meshIndex]; int localCharIndex = i - meshInfo.firstCharacterIndex; // 更新字符的材质索引 meshInfo.characterInfo[localCharIndex].materialReferenceIndex = outlineMaterialIndex; meshInfo.mesh.markDynamic = true; textInfo.meshInfo[meshIndex] = meshInfo; } // 刷新TextMeshPro显示 tmpText.UpdateVertexData(); } void OnDestroy() { // 销毁材质实例,避免内存泄漏 if (outlineMaterialInstance != null) { Destroy(outlineMaterialInstance); } } }
3. 使用自定义标签
在TextMeshPro的文本内容中直接使用<customoutline>标签即可:
this is a <customoutline>test</customoutline> with glowing outline.
关键说明
- 材质隔离:通过
new Material(tmpText.fontMaterial)创建原材质的副本,修改参数只会影响当前文本的标签段,不会波及其他使用原材质的文本。 - 内存管理:在文本更新和脚本销毁时主动销毁旧材质实例,避免内存泄漏。
- 效果定制:可根据需求调整
OutlineWidth、OutlineColor、GlowColor、GlowPower等参数,或替换为支持更强发光效果的自定义Shader。
内容的提问来源于stack exchange,提问作者Death Pad
相关产品推荐
相关产品推荐

