Graphics类
当一个UGUI的UI元素生成顶点数据时会调用Graphics类中的 OnPopulateMesh(VertexHelper vh) 函数,我们可以在这个函数中修改顶点的数据或者获取顶点的数据。
UGUI中与显示相关的控件,例如Image、Text、RawImage等都继承自MaskableGraphic类,MaskableGraphic类继承自Graphic类
控件在画面中的形状、颜色、法线等信息都是由Graphics类中的OnPopulateMesh函数所控制
每当改变了顶点或者纹理后,会调用OnPopulateMesh函数
其中需要的输入参数VertexHelper是一个顶点辅助类,保存着生成Mesh的基本信息
绘制UGUI还可以通过Mesh,但一般不怎么使用
就跟一个3D物体能显示出来因为它的MeshRender和MeshFilter,2D Sprite能显示出来因为它的SpriteRender,UGUI元素也是一样,每个UI元素都有一个CanvasRender组件
CanvasRenderer render;
Vector3[] vertices;
int[] triangles;
void Update()
{
Mesh mesh = new Mesh();
mesh.vertices = vertices;
mesh.triangles = triangles;
render = GetComponent<CanvasRenderer>();
render.SetMesh(mesh);
}
鼠标画线功能
使用UGUI中的重写了 OnPopulateMesh( VertexHelper vh ) 这个方法,然后用来绘制,改一下,可以用来实现鼠标画线的功能。详细参考:
Unity 画线OnPopulateMesh函数VertexHelper_Peter_Gao_的博客-CSDN博客
VertexHelper的类结构
OnPopulateMesh( VertexHelper vh ) 函数中, UI元素的顶点数据会填充这个参数 VertexHelper数据结构,我们可以修改这个数据结构里面的数据从而影响到顶点的一些属性。VertexHelper类的属性和方法:
VertexHelper类的绘制基本图形方法
AddVert:添加顶点(第一个添加的顶点索引为0,第二个添加的顶点为1,依次.....)
AddTriangle:绘制三角形(GPU绘制时会按照输入的顶点下标的顺序绘制一个三角形)
currentIndexCount:VertexHelper结构中有几个顶点索引(重合的顶点被计为2个顶点,例如一个三角形最少有3个顶点,一个正方形最少有6个顶点)
currentVertCount:VertexHelper结构中有几个顶点(AddVert添加了几个顶点就有几个)
PopulateUIVertex:获取某个索引的顶点数据
SetUIVertex:设置某个索引的顶点数据
AddUIVertexQuad:把AddVert和AddTriangle封装到一个函数中
AddUIVertexStream:把AddVert和AddTriangle封装到一个函数中
绘制三角形
我们用AddVert和AddTriangle绘制一个三角形
我们创建一个脚本TestVertexHelper.cs并继承Graphic,因为OnPopulateMesh函数定义在Graphic中
using UnityEngine.UI;
using UnityEngine;
public class Test : Graphic
{
protected override void OnPopulateMesh(VertexHelper vh)
{
base.OnPopulateMesh(vh);
vh.Clear();
vh.AddVert(new Vector3(0, 0), Color.black, Vector2.zero);
vh.AddVert(new Vector3(0, 100), Color.black, Vector2.zero);
vh.AddVert(new Vector3(100, 0), Color.black, Vector2.zero);
vh.AddTriangle(0, 1, 2);
}
}
首先我们用AddVert添加了三个顶点,三个顶点的关系如上图,然后用AddTriangle添加三角形,参数是三角形顶点的索引。GPU在绘制的时候会按照顶点0->顶点1->顶点2来绘制一个三角形
绘制正方形
我们用AddVert和AddTriangle绘制一个正方形
public class TestVertexHelper : Graphic
{
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
//添加四个顶点
vh.AddVert(new Vector3(0, 0), Color.red, Vector2.zero);
vh.AddVert(new Vector3(0, 100), Color.green, Vector2.zero);
vh.AddVert(new Vector3(100, 100), Color.black, Vector2.zero);
vh.AddVert(new Vector3(100, 0), Color.blue, Vector2.zero);
//添加两个三角形
vh.AddTriangle(0, 1, 2);
vh.AddTriangle(2, 3, 0);
}
}
我们首先用AddVert添加了四个顶点,顶点的顺序如图;然后用AddTriangle添加了两个三角形,其中vh.AddTriangle(0, 1, 2)表示用顶点0,1,2来绘制一个三角形,vh.AddTriangle(2, 3, 0)表示用顶点2,3,0来绘制一个三角形。
属性currentIndexCount 和currentVertCount
currentVertCount表示VertexHelper结构中有几个顶点
currentIndexCount表示VertexHelper结构中有几个顶点索引
我们来打印一下刚才绘制的正方形的信息
public class TestVertexHelper : Graphic
{
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
//添加四个顶点
vh.AddVert(new Vector3(0, 0), Color.red, Vector2.zero);
vh.AddVert(new Vector3(0, 100), Color.green, Vector2.zero);
vh.AddVert(new Vector3(100, 100), Color.black, Vector2.zero);
vh.AddVert(new Vector3(100, 0), Color.blue, Vector2.zero);
//添加两个三角形
vh.AddTriangle(0, 1, 2);
vh.AddTriangle(2, 3, 0);
Debug.Log("currentIndexCount " + vh.currentIndexCount);
Debug.Log("currentVertCount " + vh.currentVertCount);
}
}
我们看到顶点索引有四个,顶点有六个
顶点索引有四个(0,1,2,3)这个好理解,但是我们用AddVert添加了四个顶点,这里怎么显示有六个呢?因为unity会把三角形交界处的顶点分成两个。即三角形(0,1,2)和三角形(2,3,0)重合的顶点0,2会被分成两个顶点来处理。
其它函数
PopulateUIVertex函数
返回指定索引的顶点数据,返回的顶点数据会填充UIVertex数据结构
例子:
我们使用PopulateUIVertex函数获取索引为2的顶点数据,然后打印出来
public class TestVertexHelper : Graphic
{
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
//添加四个顶点
vh.AddVert(new Vector3(0, 0), Color.red, Vector2.zero);
vh.AddVert(new Vector3(0, 100), Color.green, Vector2.zero);
vh.AddVert(new Vector3(100, 100), Color.black, Vector2.zero);
vh.AddVert(new Vector3(100, 0), Color.blue, Vector2.zero);
//添加两个三角形
vh.AddTriangle(0, 1, 2);
vh.AddTriangle(2, 3, 0);
UIVertex vertex = new UIVertex();
vh.PopulateUIVertex(ref vertex, 2);
Debug.Log("color " + vertex.color + " position " + vertex.position + " uv0 " + vertex.uv0);
}
}
我们看到这个数据,和我们设置的第三个顶点的数据是一样的
SetUIVertex函数
设置一个顶点的数据
我们上面把第三个顶点的颜色设置为了黑色(vh.AddVert(new Vector3(100, 100), Color.black, Vector2.zero)?,我们通过SetUIVertex函数把第三个顶点(索引为2的顶点,索引从0开始)的三色设置为黄色
public class TestVertexHelper : Graphic
{
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
//添加四个顶点
vh.AddVert(new Vector3(0, 0), Color.red, Vector2.zero);
vh.AddVert(new Vector3(0, 100), Color.green, Vector2.zero);
vh.AddVert(new Vector3(100, 100), Color.black, Vector2.zero);
vh.AddVert(new Vector3(100, 0), Color.blue, Vector2.zero);
//添加两个三角形
vh.AddTriangle(0, 1, 2);
vh.AddTriangle(2, 3, 0);
//得到第三个顶点(顶点索引为2,从0开始)的颜色
UIVertex vertex = new UIVertex();
vh.PopulateUIVertex(ref vertex, 2);
//设置颜色为黄色
vertex.color = Color.yellow;
vh.SetUIVertex(vertex, 2);
}
}
我们看到索引为2的顶点变成了黄色
AddUIVertexQuad(UIVertex[] verts)函数
增加一个长方形
public class TestVertexHelper : Graphic
{
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
UIVertex[] verts = new UIVertex[4];
verts[0].position = new Vector3(0, 0);
verts[0].color = Color.red;
verts[0].uv0 = Vector2.zero;
verts[1].position = new Vector3(0, 100);
verts[1].color = Color.green;
verts[1].uv0 = Vector2.zero;
verts[2].position = new Vector3(100, 100);
verts[2].color = Color.black;
verts[2].uv0 = Vector2.zero;
verts[3].position = new Vector3(100, 0);
verts[3].color = Color.blue;
verts[3].uv0 = Vector2.zero;
vh.AddUIVertexQuad(verts);
}
}
我们看到这个方法和绘制两个三角形产生的效果是一样的
public void AddUIVertexStream(List verts, List indices);
这个方法向VertexHelper中批量增加顶点数据,第一个参数为顶点数据,第二个参数为构成图元的顶点索引目录
假如我们要绘制两个三角形,加入我们有两个三角形,顶点索引分别为(0,1,2),(2,3,0),那么我们的indices应该定义为
List indices = new List() { 0, 1, 2, 2, 3, 0 };
public class TestVertexHelper : Graphic
{
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
List verts = new List();
UIVertex vert0 = new UIVertex();
vert0.position = new Vector3(0, 0);
vert0.color = Color.red;
vert0.uv0 = Vector2.zero;
verts.Add(vert0);
UIVertex vert1 = new UIVertex();
vert1.position = new Vector3(0, 100);
vert1.color = Color.green;
vert1.uv0 = Vector2.zero;
verts.Add(vert1);
UIVertex vert2 = new UIVertex();
vert2.position = new Vector3(100, 100);
vert2.color = Color.black;
vert2.uv0 = Vector2.zero;
verts.Add(vert2);
UIVertex vert3 = new UIVertex();
vert3.position = new Vector3(100, 0);
vert3.color = Color.blue;
vert3.uv0 = Vector2.zero;
verts.Add(vert3);
List<int> indices = new List<int>() { 0, 1, 2, 2, 3, 0 };
vh.AddUIVertexStream(verts, indices);
}
效果:
void AddUIVertexTriangleStream(List verts)函数
这个方法向VertexHelper中批量增加三角形顶点数据,参数的长度必须是三的倍数
public class TestVertexHelper : Graphic
{
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
List<UIVertex> verts = new List<UIVertex>();
UIVertex vert0 = new UIVertex();
vert0.position = new Vector3(0, 0);
vert0.color = Color.red;
vert0.uv0 = Vector2.zero;
verts.Add(vert0);
UIVertex vert1 = new UIVertex();
vert1.position = new Vector3(0, 100);
vert1.color = Color.green;
vert1.uv0 = Vector2.zero;
verts.Add(vert1);
UIVertex vert2 = new UIVertex();
vert2.position = new Vector3(100, 100);
vert2.color = Color.black;
vert2.uv0 = Vector2.zero;
verts.Add(vert2);
vh.AddUIVertexTriangleStream(verts);
}
}
GetUIVertexStream(List stream)函数
获取当前VertexHelper中的所有顶点的信息
public class TestVertexHelper : Graphic
{
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
//添加三个顶点
vh.AddVert(new Vector3(0, 0), Color.red, Vector2.zero);
vh.AddVert(new Vector3(0, 100), Color.green, Vector2.zero);
vh.AddVert(new Vector3(100, 100), Color.black, Vector2.zero);
//添加三角形
vh.AddTriangle(0, 1, 2);
//得到所有顶点的信息
List<UIVertex> stream = new List<UIVertex>();
vh.GetUIVertexStream(stream);
foreach (UIVertex v in stream) {
Debug.Log("color " + v.color + " position " + v.position + " uv0 " + v.uv0);
}
}
}