Creation of Unity Bezier curve

Creation of Unity Bezier curve

Effect

Please add a picture description

Bezier curve principle

The commonly used Bezier curve is a mathematical curve for two-dimensional graphics applications. Curve definition: start point, end point, control point. By adjusting the control points, the shape of the Bezier curve changes.

first order straight line

How to add CC in the image belowPoint C is within the set time, fromAAPoint A moves toBBPoint B ? Here set a timet , t ∈ ( 0 , 1 ) t ,t \in(0,1)t,t(0,1),

set ttOA ⃗ \vec{OA}in time tOA Equally shortened to OE ⃗ \vec{OE}OE , OB ⃗ \vec{OB}OB The unit vector of extends to OF ⃗ \vec{OF}OF
OE ⃗ = OA ⃗ ( 1 − t ) \vec{OE}=\vec{OA}(1-t)OE =OA (1t)
O F ⃗ = O B ⃗ × t \vec{OF}=\vec{OB}\times t OF =OB ×t
O C ⃗ = O A ⃗ ( 1 − t ) + O B ⃗ × t \vec{OC}=\vec{OA}(1-t)+\vec{OB}\times t OC =OA (1t)+OB ×t

This way you can get CCPoint C is within the set time, fromAAPoint A moves toBBInterpolation of point B.

 Vector3 AB = (1 - t) * OA + t * OB;

second order curve

The second-order is based on the first-order algorithm, which is to deal with AB ⃗ \vec{AB} separatelyAB B C ⃗ \vec{BC} BC

 Vector3 AB = (1 - t) * OA + t * OB;
 Vector3 BC = (1 - t) * OB + t * OC;

Then AB ⃗ \vec{AB}AB B C ⃗ \vec{BC} BC Also perform first-order algorithm processing

 Vector3 ABC = (1 - t) * AB + t * BC;

third order curve

The third-order is similar to the second-order, and it continues to accumulate.

   Vector3 AB = (1 - t) * OA + t * OB;
   Vector3 BC = (1 - t) * OB + t * OC;
   Vector3 CD = (1 - t) * OC + t * OD;

   Vector3 ABC = (1 - t) * AB + t * BC;
   Vector3 BCD = (1 - t) * BC + t * CD;

   result = (1 - t) * ABC + t * BCD;

The next four high-level and so on. The third order is commonly used in daily life, that is, four points determine a curve.

Application in unity

The purpose is to obtain the points on the curve through the Bezier curve in order to establish the motion path data.

Create a Bezier tool through the editing extension tool of the interface.

#if UNITY_EDITOR
    public class BesselPathCreat : ScriptableWizard
    {
        public string Name = "Path";
        // 点的半径
        public float radius = 1;
        // 曲线取点的密度
        public int densityCurve = 1;
        /// <summary>
        /// 绘制曲线控制点 -- 此脚本的子物体
        /// </summary>
        public List<GameObject> PathPointList = new List<GameObject>();

        DrawGizmosLine drawGizmosLint;
        GameObject game;

        [MenuItem("FrameWorkSong//FrameWork/3.创建贝塞尔路径", false, 3)]
        static void CreateBasselPath()
        {
            ScriptableWizard.DisplayWizard<BesselPathCreat>("CreateBasselPath", "创建", "加点");

        }
        /// <summary>
        /// 创建按钮触发
        /// </summary>
        void OnWizardCreate()
        {
            if (PathPointList.Count > 4)
            {
                var level = ScriptableObject.CreateInstance<BasselPathTemplet>();
                level.BasselPathPoints = drawGizmosLint.CurvePoints;
                AssetDatabase.CreateAsset(level, @"Assets/FrameWorkSong/Data/" + Name + ".asset");//在传入的路径中创建资源
                AssetDatabase.SaveAssets(); //存储资源
                AssetDatabase.Refresh(); //刷新

            }


            DestroyObject();
        }
        /// <summary>
        /// 关闭触发
        /// </summary>
        void DestroyObject()
        {
            if (game)
            {
                DestroyImmediate(game);
            }
            for (int i = 0; i < PathPointList.Count; i++)
            {
                DestroyImmediate(PathPointList[i]);
            }
        }
        void OnWizardUpdate()
        {
            
        }
        /// <summary>
        /// 加点按钮触发
        /// </summary>
        // When the user presses the "Apply" button OnWizardOtherButton is called.
        void OnWizardOtherButton()
        {

            if (PathPointList.Count == 0)
            {
                game = new GameObject();
                drawGizmosLint = game.AddComponent<DrawGizmosLine>();
            }
            BasselPath basselPath = new BasselPath();
            DrawGizmosPointLine drawGizmos = basselPath.MianPiont.AddComponent<DrawGizmosPointLine>();
            PathPointList.Add(basselPath.FrontPiont);
            PathPointList.Add(basselPath.MianPiont);
            PathPointList.Add(basselPath.BackePiont);
            drawGizmos.SelfPoint = basselPath.Piont;
            drawGizmosLint.SelfPoint = PathPointList;
            drawGizmosLint.densityCurve = densityCurve;
            drawGizmosLint.radius = radius;
        }
        void OnDestroy()
        {
            DestroyObject();
        }


    }
#endif

Used here, the class is derived to create editor wizards. For details, please refer to the official api https://docs.unity3d.com/cn/current/ScriptReference/ScriptableWizard.html

How to create Bezier

 public class BasselPath
    {
        List<GameObject> piont = new List<GameObject>();
        GameObject mianPiont;
        GameObject frontPiont;
        GameObject backePiont;
        public BasselPath()
        {
            mianPiont = new GameObject();
            mianPiont.transform.position = Vector3.zero;
            frontPiont = new GameObject();
            frontPiont.transform.position = Vector3.zero + (Vector3.right * 5);

            backePiont = new GameObject();
            backePiont.transform.position = Vector3.zero + (Vector3.left * 5);

            piont.Add(frontPiont);
            piont.Add(mianPiont);
            piont.Add(backePiont);
            backePiont.transform.SetParent(mianPiont.transform);
            frontPiont.transform.SetParent(mianPiont.transform);
            mianPiont.AddComponent<DrawGizmosPoint>();
            frontPiont.AddComponent<DrawGizmosPoint>();
            backePiont.AddComponent<DrawGizmosPoint>();
        }

        public GameObject MianPiont { get => mianPiont; set => mianPiont = value; }
        public GameObject FrontPiont { get => frontPiont; }
        public GameObject BackePiont { get => backePiont; }
        public List<GameObject> Piont { get => piont; }
    }



    /// <summary>
    /// 绘制节点
    /// </summary>
    public class DrawGizmosPoint : MonoBehaviour
    {
        public float radius = 1;
        private void OnDrawGizmos()
        {
            //绘制点
            Gizmos.color = Color.blue;
            Gizmos.DrawSphere(transform.position, radius * 0.5f);
        }
    }
    /// <summary>
    /// 绘制节点线
    /// </summary>
    public class DrawGizmosPointLine : MonoBehaviour
    {
        public float radius = 1;
        public List<GameObject> SelfPoint = new List<GameObject>();
        private void OnDrawGizmos()
        {
            List<Vector3> controlPointPos = SelfPoint.Select(point => point.transform.position).ToList();



            //绘制曲线控制点连线
            Gizmos.color = Color.red;
            for (int i = 0; i < controlPointPos.Count - 1; i += 3)
            {
                Gizmos.DrawLine(controlPointPos[i], controlPointPos[i + 1]);
                Gizmos.DrawLine(controlPointPos[i + 1], controlPointPos[i + 2]);
            }
        }
    }
    /// <summary>
    /// 绘制曲线
    /// </summary>
    public class DrawGizmosLine : MonoBehaviour
    {
        public float radius;
        public int densityCurve;
        public List<GameObject> SelfPoint;
        public List<Vector3> CurvePoints;
        private void OnDrawGizmos()
        {
            List<Vector3> controlPointPos = SelfPoint.Select(point => point.transform.position).ToList();
            if (controlPointPos != null)
            {
                CurvePoints = GetDrawingPoints(controlPointPos, densityCurve);
            }

            //绘制曲线
            if (CurvePoints.Count >= 4)
            {
                Gizmos.color = Color.green;
                //点密度
                foreach (var item in CurvePoints)
                {
                    Gizmos.DrawSphere(item, radius * 0.5f);
                }
                //曲线
                for (int i = 0; i < CurvePoints.Count - 1; i++)
                {
                    Gizmos.DrawLine(CurvePoints[i], CurvePoints[i + 1]);
                }
            }


        }
        /// <summary>
        /// 获取绘制点
        /// </summary>
        /// <param name="controlPoints"></param>
        /// <param name="segmentsPerCurve"></param>
        /// <returns></returns>
        public List<Vector3> GetDrawingPoints(List<Vector3> controlPoints, int segmentsPerCurve)
        {
            List<Vector3> points = new List<Vector3>();
            // 下一段的起始点和上段终点是一个,所以是 i+=3
            for (int i = 1; i < controlPoints.Count - 4; i += 3)
            {

                var p0 = controlPoints[i];
                var p1 = controlPoints[i + 1];
                var p2 = controlPoints[i + 2];
                var p3 = controlPoints[i + 3];
                float dis = Vector3.Distance(p0, p3);
                int count = Mathf.CeilToInt(segmentsPerCurve * dis);
                if (count < segmentsPerCurve)
                {
                    count = segmentsPerCurve;
                }

                for (int j = 0; j <= count; j++)
                {
                    var t = j / (float)count;
                    points.Add(CalculateBezierPoint(t, p0, p1, p2, p3));
                }
            }
            return points;
        }
        // 三阶公式
        Vector3 CalculateBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3)
        {
            Vector3 result;

            Vector3 p0p1 = (1 - t) * p0 + t * p1;
            Vector3 p1p2 = (1 - t) * p1 + t * p2;
            Vector3 p2p3 = (1 - t) * p2 + t * p3;

            Vector3 p0p1p2 = (1 - t) * p0p1 + t * p1p2;
            Vector3 p1p2p3 = (1 - t) * p1p2 + t * p2p3;

            result = (1 - t) * p0p1p2 + t * p1p2p3;
            return result;
        }

    }


Guess you like

Origin blog.csdn.net/dxs1990/article/details/125932828