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;
        }
    }

}

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>