定义脚本CurvedText继承自Text,重写OnPopulateMesh函数
protected override void OnPopulateMesh(VertexHelper toFill) //在Unity生成顶点数据后会调用这个函数,
{ //toFill保存了Mesh的所有信息
base.OnPopulateMesh(toFill); //在这个函数中改变顶点坐标,达到改变mesh形状的目的
CurvedText(toFill);
}
private void CurvedText(VertexHelper toFill)
{
if (!IsActive()) //处于未激活状态
return;
for (int i = 0; i < cachedTextGenerator.lines.Count; i++) //遍历所有行
{
UILineInfo line = cachedTextGenerator.lines[i]; //当前行
if (i + 1 < cachedTextGenerator.lines.Count) //不是最后一行
{
UILineInfo line2 = cachedTextGenerator.lines[i + 1]; //下一行
int current = 0; //一行的第几个字
for (int j = line.startCharIdx; j < line2.startCharIdx - 1; j++) //遍历一行所有文字 ,下一行起点为界限
{
CurvedText(toFill,j, current++, i ,line2.startCharIdx - 1 - line.startCharIdx);
}
}
else if (i + 1 == cachedTextGenerator.lines.Count) //最后一行
{
int current = 0;
for (int j = line.startCharIdx; j < cachedTextGenerator.characterCountVisible; j++) //总字数为界限
{
int index = current;
CurvedText(toFill, j, current++, i , cachedTextGenerator.characterCountVisible - line.startCharIdx);
}
}
}
}
坐标变换函数
void CurvedText(VertexHelper helper, int index, int charXIndex, int charYStep , int lineCount)
{
UIVertex lb = new UIVertex();
helper.PopulateUIVertex(ref lb, index * 4); //获取点的信息 index一行的第几个文字 ,一个文字4个点组成
UIVertex lt = new UIVertex();
helper.PopulateUIVertex(ref lt, index * 4 + 1); //lb 左下 lt左上 rt 右上 ,rb右下
UIVertex rt = new UIVertex();
helper.PopulateUIVertex(ref rt, index * 4 + 2);
UIVertex rb = new UIVertex();
helper.PopulateUIVertex(ref rb, index * 4 + 3);
Vector3 center = Vector3.Lerp(lb.position, rt.position, 0.5f); //文字的中心点
float degree = GetAngle(helper, lineCount, text.Split('\n')[charYStep], index - cachedTextGenerator.lines[charYStep].startCharIdx); //获取文字旋转角度
Matrix4x4 move = Matrix4x4.TRS(-center, Quaternion.identity, Vector3.one); //变化前 坐标 旋转 缩放矩阵
float y = curvedRadius - curvedRadius * Mathf.Cos(degree * Mathf.Deg2Rad); //根据角度计算 y 坐标 curvedRadius文字绕成圆的弧度
float x = curvedRadius * Mathf.Sin(degree * Mathf.Deg2Rad); //根据角度计算 x 坐标
Vector3 pos = new Vector3(x, y, 0);
Vector3 charadir = (new Vector3(0, curvedRadius, 0) - pos).normalized; //顶点指向圆中心方向
pos += lb.position.y * charadir * 0.4f; //向内移动 文字收缩
Matrix4x4 place = Matrix4x4.TRS(pos, Quaternion.Euler(new Vector3(0,0,degree)), Vector3.one); //变化后 坐标 旋转 缩放矩阵
Matrix4x4 transform = place * move; //变化矩阵 之前矩阵基础上 旋转平移 缩放
lb.position = transform.MultiplyPoint3x4(lb.position); //根据矩阵旋转4个顶点
lt.position = transform.MultiplyPoint3x4(lt.position);
rt.position = transform.MultiplyPoint3x4(rt.position);
rb.position = transform.MultiplyPoint3x4(rb.position);
helper.SetUIVertex(lb, index * 4); //刷新4个顶点
helper.SetUIVertex(lt, index * 4 + 1);
helper.SetUIVertex(rt, index * 4 + 2);
helper.SetUIVertex(rb, index * 4 + 3);
}
角度计算函数
private float GetAngle(VertexHelper helper , int charaCount , string tex ,int index)
{
float totalangle = 0;
int startindex = cachedTextGenerator.lines[step].startCharIdx;
for (int i = 0; i < charaCount; i++)
{
UIVertex lb = new UIVertex();
helper.PopulateUIVertex(ref lb, (i + startindex) * 4);
UIVertex lt = new UIVertex();
helper.PopulateUIVertex(ref lt, (i + startindex) * 4 + 1);
float width = Vector3.Distance(lb.position, lt.position);
float angle = Mathf.Asin(width / 2 / curvedRadius) * 2 * Mathf.Rad2Deg * curvedFontSpaceScale;
totalangle += angle;
}
totalangle /= 2;
float getAngle = 0;
for (int i = 0; i <= index; i++)
{
float nowindexangle = 0;
UIVertex lb = new UIVertex();
helper.PopulateUIVertex(ref lb,(i + startindex) * 4);
UIVertex lt = new UIVertex();
helper.PopulateUIVertex(ref lt,(i + startindex)* 4 + 1);
nowindexangle = Vector3.Distance(lb.position, lt.position);
if (i == index)
{
getAngle += Mathf.Asin(nowindexangle / 2 / curvedRadius) * Mathf.Rad2Deg * curvedFontSpaceScale;
}
else
{
getAngle += Mathf.Asin(nowindexangle / 2 / curvedRadius) * 2 * Mathf.Rad2Deg * curvedFontSpaceScale;
}
}
getAngle -= totalangle;
if (step != 0)
return getAngle / (step * 0.3f + 1);
return getAngle;
}
效果图: