使用SuperTextMesh 针对项目的几个修改记录
相关参考资料
项目场景渲染文字,由于Text组件功能太少 选择了SuperTextMesh(STM)
STM 实现原理
通过字体的UV组成几个网格,利用字体图不是透明像素就填充指定颜色,从而保证拉伸后的清晰度
每个字体都是由你当前使用的文字的集合组成一个texture然后每个使用这个字体组件从这个字体的Texutre获取像信息来进行渲染
但是这个Texture动态大小的字体图集,如果使用文字多了,图集就会变大,使用字改变了就会改变贴图的上的文字的UV位置,所有使用这个图集的组件就要更新UV来从新刷新数据
这就需要在Font这个图集刷新的时候刷新下 需要在Font.textureRebuilt添加回调函数
修改1
Font.textureRebuilt 按现在STM的代码。每个STM都会在这个注册个回调,造成这个代理函数队列非常大,总是会卡帧,我改了下STM注册的规则自己注册队列来
把STM源码注册 用这AddFontRebuilt来注册Font.textureRebuilt即可
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Assets.Clavian.SuperTextMesh.Scripts
{
//字体重绘管理
//由于Font.textureReBuilt 源码性能问题 如果多个text对象添加到这个队列中,每次回调会有卡顿,所以我这边从新包装下下回调函数
public class FontUpdate
{
public Dictionary<uint, Action<Font>> dic;
uint indexkey=0;//减少判断key 用个范围增量值来做KEY
static FontUpdate _instance;
public static FontUpdate instance
{
get
{
if (_instance==null)
{
_instance = new FontUpdate();
}
return _instance;
}
}
public FontUpdate ()
{
dic = new Dictionary<uint, Action<Font>>();
Font.textureRebuilt += rebuildFont;
}
//重绘调用
void rebuildFont(Font font)
{
foreach (Action<Font> item in dic.Values)
{
item.Invoke(font);
}
}
//注册一个重绘回调 为了减少寻址导致的消耗,预留uint长度 key 返回一个KEY 作为清理key
//这个策略有待验证
public uint AddFontRebuilt(Action<Font> fun )
{
indexkey++;
dic.Add(indexkey,fun);
return indexkey;
}
//清理一个重绘回调
public void RemoveFontRebuilt(uint index)
{
dic.Remove(index);
if (dic.Count==0)//清理 如果所有都清理 预留key 归零
{
indexkey = 0;
if (sw.util.LoggerHelper.CheckLogLv(sw.util.LogLevel.DEBUG))Debugger.Log("clear RemoveFontRebuilt");
}
}
}
}
修改2
最早需求文字是没有背景的,所以场景有N个文字只需要一个drawCall就能完成所有STM的文字渲染
现在有需求需要在文字后面加上背景,这样的话必然会有2个材质叠加渲染,要知道U3D的动态合批是合并上下层级同一个材质的渲染对象。这样就不会动态合批了,性能会有问题。
解决办法
STM是用网格去渲染字体,我就在STM源码生成网格上进行修改 生成4个顶点在文字后面 再取一个背景贴图吧贴图渲染上去
1 要保证4个顶点在mesh需要的顶点前4个位置 4个顶点
2 生成2个三角面
3 传入4个UV点保证正向渲染
4 字体的面和会和背景的面重叠 所有 4个顶点位置要Z轴有个0.001的距离,否则会闪烁
5 先生成文字的mesh位置后再计算top left right bootom 4个顶点的位置
6 shader修改 把渲染文字透明值是0的时候 来填充背景图片
UWA上的老兄提示的多材质渲染方式来处理
叠加后 自动合批了 哈哈