定義腳本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;
}
效果圖: