LOADING

加载过慢请开启缓存 浏览器默认开启

TMP的描边遮挡改善

分析 TextMeshPro 相邻文字的描边遮挡现象,记录使用 SDF 距离场与自定义深度写入改善显示效果的思路。

TMP全称TextMeshPro,是一款非常强大的文字系统,关于它的内容非常复杂,这次只将目光聚焦在如何解决描边遮挡问题,关于TMP更详细的解读将在其他文章中进行。

unity版本:Unity6000.062f1

1.原因解析

首先看TMP原先有什么问题。当具有描边的文字逐渐靠近到一起的时候,文字之间的描边会相互遮挡如图:

TMP的描边遮挡改善示意图 1

至于造成他们发生这样的情况的原因可以这样理解:TMP的每一个字母都可以看作是一个面片,而一行字则可以看作是一个独立的模型。而一个模型中的每个面片的渲染顺序遵循其内部的网格ID,对于TMP而言,他们的网格就是按照字母顺序从前到后排列的。所以当第一个面片渲染后,第二个模型的一部分像素可能就会覆盖掉第一个模型,这就造成了他们之间的相互遮挡。由于他们同属于同一个模型,所以我们也不可能用遮罩之类的手段去识别文字本体和描边部分,只能另寻他法。

2.自定义的深度写入

Unity的着色器有个功能:我们可以忽略掉物体本身的深度值,而将每次模型的深度写成我们想要指定的值,他就是SV_Depth。

使用示例:

float4 frag(v2f i, out float depth : SV_Depth) : SV_Target
{
    float4 col = float4(1, 0, 0, 1);
    depth = 0.5;
    return col;
}

而TMP是基于SDF的渲染方式,每个文字都会有个距离场,越接近文字中心的值越大

如图所示:

TMP的描边遮挡改善示意图 2

而对于我们的需求来说,描边正是远离文字中心的部分。基于这一点,可以把距离场映射为自定义深度,让文字本体与描边具有不同的深度优先级。不过,写入更大的数值并不意味着一定能通过测试:映射方向需要与实际深度比较方式、深度写入设置以及平台的 reversed-Z 约定相匹配。下面记录的是这次实验的改善结果,移植到其他渲染配置时仍需验证。

改善后效果如下:

TMP的描边遮挡改善示意图 3

参考:Unity:ShaderLab ZTest、不同图形 API 的深度方向差异。