美术希望在3D UI中显示自定义的网格,比如显示一个带弧形的UI。纯3D确实是可以做的,但是涉及到UI事件或者裁切就无法统一。
由于默认的UI是矩形,UI的显示与相应区域就是RectTransform的size,如果我们使用自定义Mesh的UI那么显示区域就要单独调整,比如单独设置显示的旋转、缩放、平移。
如下图所示,显示区域和响应区域是不一样的。
如下图所示,MeshImage就是我封装的UI组件,这时候调整overridePostion、 overrideRotation 、overrideScale 来修改3D模型的显示区域。
而修改RectTransform则修改它的整体响应区域。
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(CanvasRenderer))]
public class MeshImage : MaskableGraphic
{
public Vector3 overridePostion;
public Vector3 overrideRotation;
public Vector3 overrideScale = new Vector3(100f, 100f, 100f);
public Texture texture;
public Mesh mesh;
public override Texture mainTexture
{
get { return texture; }
}
protected override void OnPopulateMesh(VertexHelper vh)
{
if (mesh != null)
{
vh.Clear();
//提取Mesh信息
int[] triangles = mesh.triangles;
Vector3[] vertices = mesh.vertices;
Vector3[] normals = mesh.normals;
Vector2[] UVs = mesh.uv;
//处理缩放矩阵
Matrix4x4 matrix4X4 = Matrix4x4.identity;
matrix4X4.m00 = overrideScale.x;
matrix4X4.m11 = overrideScale.y;
matrix4X4.m22 = overrideScale.z;
for (int i = 0; i < vertices.Length; i++)
{
//组合UI顶点信息
UIVertex temp = new UIVertex();
temp.position = matrix4X4.MultiplyPoint3x4((Quaternion.Euler(overrideRotation) * vertices[i]) + overridePostion);
temp.uv0 = UVs[i];
temp.normal = normals[i];
temp.color = (Color32)color;
vh.AddVert(temp);
}
//设置三角形索引
for (int i = 0; i < triangles.Length; i += 3)
{
vh.AddTriangle(triangles[i], triangles[i + 1], triangles[i + 2]);
}
}
}
//只有编辑器才会执行
//修改面板属性重新刷新
protected override void OnValidate()
{
base.OnValidate();
SetMaterialDirty();
SetVerticesDirty();
}
}
原理就是将Mesh的顶点信息取出来,并且组合到UI顶点中,配合3D摄像机整体的关系就都出来了。
还有一点默认UI的shader是不写深度的,如果模型有厚度就要写深度了,自己改下shader就行。