Unity画贝塞尔曲线自定义图片组件
头一回写这个文章,也是就分享一点自己的学习心得,并且记录下自己做过的这个功能。
事实上我这也是借鉴了大佬的代码,统筹琢磨出来的,比较初级,但是有用。
话不多说,上效果图:
如图所见,展现出来的功能组件很简单,就是一个继承了Image并且多加了几个变量的自定义组件 ,实现的就是右边将图片作为元素绘制成一条贝塞尔曲线。
控制点列表中的点数据我做的还不够智能,暂时用第一个和最后一个表示这条线的起点和终点,而其他的点都是这条贝塞尔曲线的极点了。
“密集度 mesh数量”可以看成是要生成多少个图片元素
“mesh宽度”可以看成你要生成图片元素的大小
反正就那个意思,很简单,我就不多啰嗦了。看见这篇文章的朋友完全可以直接下来用。大家也可以根据我的代码进行拓展的,看懂原来的垃圾代码就好了嘿嘿~(手都滑稽)
public static class Bezier
{
/// <summary>
/// 获取绘制点
/// </summary>
/// <param name="controlPoints">控制点列表</param>
/// <param name="density">密度</param>
/// <returns></returns>
public static Vector3[] GetPointList(List<Vector2> controlPoints, int density)
{
List<Vector3> points = new List<Vector3>();
for(int i = 0; i <= density; i++)
{
points.Add(BezierMath(i / (float)density, controlPoints.Count - 1, controlPoints));
}
return points.ToArray();
}
/// <summary>
/// 贝塞尔曲线的函数
/// </summary>
/// <param name="t">分段参数</param>
/// <param name="lineNum">线段数量</param>
/// <param name="controlPoints">锚点列表</param>
/// <returns></returns>
public static Vector2 BezierMath(float t, int lineNum, List<Vector2> controlPoints)
{
Vector2 result = new Vector2();
for (int i = 0; i <= lineNum; i++)
{
float temp = BaseBezier(t, i, lineNum);
result.x += controlPoints[i].x * temp;
result.y += controlPoints[i].y * temp;
}
return result;
}
/// <summary>
/// 贝塞尔基函数
/// </summary>
/// <param name="t">参数</param>
/// <param name="index">线段序号</param>
/// <param name="lineNum">线段数量</param>
/// <returns></returns>
public static float BaseBezier(float t, int index, int lineNum)
{
float result = Factorial(lineNum) * Mathf.Pow(t, index) * Mathf.Pow(1 - t, lineNum - index) / (Factorial(index) * Factorial(lineNum - index));
return result;
}
/// <summary>
/// Factorial 阶乘
/// </summary>
/// <param name="step"></param>
/// <returns></returns>
public static int Factorial(int step)
{
int result = 1;
for (int j = step; j > 1; j--)
{
result *= j;
}
return result;
}
}
public class BezierMeshImage : Image
{
/// <summary> 密集度 mesh数量 </summary>
public int density = 50;
/// <summary> mesh 宽度 </summary>
public float width;
/// <summary> 控制点列表 </summary>
public List<Vector2> controlList = new List<Vector2>();
/// <summary> 贝塞尔点数组 </summary>
Vector3[] bezierPoints;
protected override void OnPopulateMesh(VertexHelper vh)
{
bezierPoints = Bezier.GetPointList(controlList, density);
vh.Clear();
for (int index = 0; index < bezierPoints.Length; index++)
{
Vector3 baseVector = bezierPoints[index];
var i = index * 4;
vh.AddVert(baseVector + new Vector3(-width/2, -width/2, 1), color, new Vector2(0f, 0f));
vh.AddVert(baseVector + new Vector3(-width/2, width/2, 1), color, new Vector2(0f, 1f));
vh.AddVert(baseVector + new Vector3(width/2, width/2, 1), color, new Vector2(1f, 1f));
vh.AddVert(baseVector + new Vector3(width/2, -width/2, 1), color, new Vector2(1f, 0f));
vh.AddTriangle(i, i + 1, i + 2);
vh.AddTriangle(i + 2, i + 3, i);
}
}
}
[CustomEditor(typeof(BezierMeshImage))] // 定义子类的编辑器扩展
public class BezierMeshImageEditor : ImageEditor
{
private BezierMeshImage be;
public List<Vector2> pointList;
public static bool isOpenList;
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
be = (BezierMeshImage)base.target;
//be.controlV2 = EditorGUILayout.Vector2Field("控制点坐标", be.controlV2);
be.density = EditorGUILayout.IntField("密集度 mesh数量", be.density);
be.width = EditorGUILayout.FloatField("mesh 宽度 ", be.width);
pointList = be.controlList;
isOpenList = EditorGUILayout.Foldout(isOpenList, "控制点列表");
if(isOpenList)
{
for(int i = 0; i < pointList.Count; i++)
{
pointList[i] = EditorGUILayout.Vector2Field(name, pointList[i]);
}
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("+"))
{
Vector2 point = new Vector2();
point = EditorGUILayout.Vector2Field(name, point);
pointList.Add(point);
}
if (GUILayout.Button("-"))
{
if (pointList.Count > 0)
pointList.RemoveAt(pointList.Count - 1);
}
EditorGUILayout.EndHorizontal();
}
be.controlList = pointList;
if (HasPreviewGUI())
{
be.enabled = false;
be.enabled = true;
}
}
}