Unity ベジエ曲線の作成

Unity ベジエ曲線の作成

効果

写真の説明を追加してください

ベジエ曲線の原理

一般的に使用されるベジエ曲線は、2 次元グラフィックス アプリケーション用の数学的曲線です。曲線の定義: 始点、終点、制御点。コントロールポイントを調整することで、ベジエ曲線の形状が変化します。

一次直線

下の画像にCCを追加する方法C点は設定時間内、AA点A がBBに移動ポイントB ? ここで時刻t , t ∈ ( 0 , 1 ) t ,t \in(0,1) をt tε( 0 ,1 )

設定するOA ⃗ \vec{OA}in time tおあ_ 同様にOE ⃗ \vec{OE}に短縮されます大江 OB ⃗ \vec{OB}OB の単位ベクトルはOF ⃗ \vec{OF}に拡張されます OE ⃗ = OA ⃗ ( 1 − t
) \vec{OE}=\vec{OA}(1-t)大江 =おあ_ ( 1t )
OF ⃗ = OB ⃗ × t \vec{OF}=\vec{OB}\times t =OB ×t
OC ⃗ = OA ⃗ ( 1 − t ) + OB ⃗ × t \vec{OC}=\vec{OA}(1-t)+\vec{OB}\times tOC =おあ_ ( 1t )+OB ×t

これでCCを取得できますC点は設定時間内、AA点A がBBに移動点Bの補間。

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

二次曲線

2 次は、AB ⃗ \vec{AB}を個別に処理する 1 次アルゴリズムに基づいています。A B BC ⃗ \vec{BC}紀元前

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

次にAB ⃗ \vec{AB}A B BC ⃗ \vec{BC}紀元前 一次アルゴリズム処理も行う

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

三次曲線

3 次は 2 次と同様で、蓄積し続けます。

   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;

次の 4 つの高レベルなど。三次は日常生活でよく使われます。つまり、4 点で曲線が決まります。

団結して適用

目的は、モーション パス データを確立するために、ベジエ曲線を介して曲線上のポイントを取得することです。

インターフェイスの編集拡張ツールを使用してベジエ ツールを作成します。

#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

ここで使用されるクラスは、エディター ウィザードを作成するために派生されます。詳細については、公式 API https://docs.unity3d.com/cn/current/ScriptReference/ScriptableWizard.html を参照してください。

ベジエの作り方

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

    }


おすすめ

転載: blog.csdn.net/dxs1990/article/details/125932828