因为项目原因,采用的是比较老的NGUI(2.7),文本控件UILabel没有类似于UGUI的Gradient渐变效果的选项,所以需要自己动手添加.
先瞧瞧成品后的效果:
再来看看UGUI的Gradient效果,很方便,直接挂脚本就生效.
代码如下:
public class Gradient : BaseMeshEffect
{
public Color32 topColor = Color.white;
public Color32 bottomColor = Color.black;
public override void ModifyMesh(VertexHelper helper)
{
if (!IsActive() || helper.currentVertCount == 0)
return;
List<UIVertex> vertices = new List<UIVertex>();
helper.GetUIVertexStream(vertices);
float bottomY = vertices[0].position.y;
float topY = vertices[0].position.y;
for (int i = 1; i < vertices.Count; i++)
{
float y = vertices[i].position.y;
if (y > topY)
{
topY = y;
}
else if (y < bottomY)
{
bottomY = y;
}
}
float uiElementHeight = topY - bottomY;
UIVertex v = new UIVertex();
for (int i = 0; i < helper.currentVertCount; i++)
{
helper.PopulateUIVertex(ref v, i);
v.color = Color32.Lerp(bottomColor, topColor, (v.position.y - bottomY) / uiElementHeight);
helper.SetUIVertex(v, i);
}
}
}
看UGUI的源码可以发现,文本的显示其实根本也是顶点,三角面,纹理采样的过程,一个字符需要四个顶点,两个三角面,因为高度的不一样,所以需要计算每个顶点所处高度对应的颜色值.
在Inspector面板调节字体颜色的时其实就是修改生成的字符网格顶点的颜色.可以看上面的代码设置颜色的地方:
那么渐变效果又是从何而来呢?
这就要从渲染管线来看了,在光栅化的插值阶段,顶点的颜色也会通过插值处理,应用到每个像素点,再配合Fragment Shader的纹理采样过程,达到了渐变效果.整个过程可以不用关心,Unity内部自动处理好了,所以UGUI的gradient效果只需要吧每个字符网格顶部的两个顶点的颜色和底部的两个顶点颜色设置为想要的颜色即可达到过度效果.知道这一点,就可以容易的给NGUI添加同样的效果了,毕竟NGUI的代码是完全开源的,项目中就可以查看,找到设置顶点颜色的地方稍作处理即可.
回到主题NGUI
ngui中的文本控件是UILabel,并没有发现给顶点设置颜色的地方,继续跟踪代码会发现在UiFont脚本中有个Print的方法,里面可以找到给字体网格设置颜色的相关操作.
方法比较长,就截取关键部分来看吧,毕竟版本也比较老,代码也有些差别,不过核心是一样的.
这是在一个for循环中,遍历每一个字符,上面If的部分是我添加的,可以看出是分别设置顶部和底部顶点的颜色,而原始代码就是else部分,一个字符的四个顶点颜色设置为同一个颜色值.接下来要做的就是自定义面板,让顶部和底部的颜色值在Inspect面板显示,方便使用.
UIlabel中添加的属性:
ColorTop和ColorBottom同useGradient一致,就不再贴出来了.
UILabelInspector.cs中的DrawProperties方法中添加相关代码:
bool useGradient = EditorGUILayout.Toggle("Gradient", mLabel.useGradient, GUILayout.Width(100f));
if (useGradient != mLabel.useGradient)
{
RegisterUndo();
mLabel.useGradient = useGradient;
}
if (useGradient)
{
EditorGUI.indentLevel += 1;
Color top = EditorGUILayout.ColorField("Top", mLabel.colorTop);
if (top != mLabel.colorTop) { RegisterUndo(); mLabel.colorTop = top; }
Color bottom = EditorGUILayout.ColorField("Bottom", mLabel.colorBottom);
if (bottom != mLabel.colorBottom) { RegisterUndo(); mLabel.colorBottom = bottom; }
EditorGUI.indentLevel -= 1;
}
搞定!