欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

每天一个小技巧【8】·贝塞尔曲线

程序员文章站 2022-07-12 22:43:15
...

贝塞尔曲线是一种平滑曲线,常见于PS中的钢笔工具,在Unity中一般用来绘制弹道轨迹和轨道镜头  。其原理可以看成是将棱角沿中位线打磨,一直重复。这就要用到公式:

每天一个小技巧【8】·贝塞尔曲线

备忘:每天一个小技巧【8】·贝塞尔曲线

 

每天一个小技巧【8】·贝塞尔曲线

应用贝塞尔曲线公式实现运动轨迹:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 贝塞尔曲线应用
/// </summary>
public class BezierCurve : MonoBehaviour
{
    public Transform[] transes;
    Vector3[] points;
    public float useTime=2;
    public EasingEquation easeType;
    
    Vector3[] Points
    {
        get
        {
            if(points==null)
            {
                points = new Vector3[transes.Length];
                for(var i = 0; i < transes.Length; i++)
                {
                    points[i] = transes[i].position;
                }
            }
            return points;
        }
        set
        {
            points = value;
        }
    }
    public void SetPoints(Vector3[] _points)
    {
        points = _points;
    }
    [ContextMenu("Play")]
    public void Play()
    {
        StartCoroutine(IE_Play());
    }
    IEnumerator IE_Play()
    {
        var _end = false;
        var _v = 0f;
        var _timer = 0f;
        var _useTime = useTime;
        var _orgV1 = 0f;
        var _endV1 = 1f;
        var _curV1 = _orgV1;
        while (!_end)
        {
            _timer += Time.deltaTime;
            _v = Mathf.Clamp01(_timer / _useTime);
            if (_v >= 1)
            {
                _end = true;
            }
            _curV1 = Mathf.LerpUnclamped(_orgV1, _endV1,  EasingManager.GetEaseProgress(easeType,_v));
            transform.position = bezier_interpolation_func(_curV1, Points);
            yield return null;
        }
    }  
    private static float calc_combination_number(int n, int k)
    {
        float[] result = new float[n + 1];
        for (int i = 1; i <= n; i++)
        {
            result[i] = 1;
            for (int j = i - 1; j >= 1; j--)
                result[j] += result[j - 1];
            result[0] = 1;
        }
        return result[k];
    }
    //根据指定路径返回贝塞尔轨迹
    public static Vector3 bezier_interpolation_func(float t, Vector3[] points)
    {
        var count = points.Length;
        Vector3 PointF = new Vector3();
        //float[] part = new float[count];
        float sum_x = 0, sum_y = 0,sum_z=0;
        for (int i = 0; i < count; i++)
        {
            float tmp;
            int n_order = count-1 ;    // 阶数
            tmp = calc_combination_number(n_order, i);
            sum_x += (float)(tmp * points[i].x * Mathf.Pow((1 - t), n_order - i) *  Mathf.Pow(t, i));
            sum_y += (float)(tmp * points[i].y * Mathf.Pow((1 - t), n_order - i) *  Mathf.Pow(t, i));
            sum_z += (float)(tmp * points[i].z * Mathf.Pow((1 - t), n_order - i) *  Mathf.Pow(t, i));
        }
        PointF.x = sum_x;
        PointF.y = sum_y;
        PointF.z = sum_z;
        return PointF;
    }
}

应用贝塞尔曲线公式绘制Mesh:

每天一个小技巧【8】·贝塞尔曲线

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace GLA_Tool
{
    public class DrawCurveMesh_Horizontal : MonoBehaviour
    {
        #region AssetClass
        ModuleAssetClass module;
        public ModuleAssetClass Module
        {
            get
            {
                if (module == null)
                    module = GetComponentInParent<ModuleAssetClass>();
                return module;
            }
            set
            {
                module = value;
            }
        }
        private void OnEnable()
        {
            Module.E_Play += Play;
            //Module.E_Stop += Stop;
            Module.Text.text = "创建贝塞尔曲线";
        }
        private void OnDisable()
        {
            Module.E_Play -= Play;
            //Module.E_Stop -= Stop;
        }
        void Play()
        {            
            CreateOne();
        }        
        #endregion
        #region Parameters
        Transform[] pointsTrans;
        Vector3[] pointsVec3;       
        public int count =10;
        public float width = 2;
        MeshFilter mf;
        #endregion
        #region Properties
        public Transform[] PointsTrans
        {
            get
            {
                    return transform.GetChildren().ToArray(); ;
            }
            set
            {
                pointsTrans = value;
            }
        }
        public Vector3[] PointsVec3
        {
            get
            {
                    pointsVec3 = new Vector3[PointsTrans.Length];
                for (var i = 0; i < pointsVec3.Length; i++)
                {
                    pointsVec3[i] = PointsTrans[i].localPosition;
                }
                return pointsVec3;
            }
            set
            {
                pointsVec3 = value;
            }
        }
        public MeshFilter Mf
        {
            get
            {
                if (mf == null)
                    mf = GetComponentInChildren<MeshFilter>();
                return mf;
            }
            set
            {
                mf = value;
            }
        }
        #endregion
        #region Private Methods  
        [ContextMenu("CreateOne")]
        void CreateOne()
        {
            var verticeList = new List<Vector3>();
            var indexList = new List<int>();
            var uvList = new List<Vector2>();
            for(var i = 0; i < count; i++)
            {
               var _vec0= BezierCurve.bezier_interpolation_func((float)i / (count -  1), PointsVec3);
                var _vec1 = _vec0 + Vector3.forward * width;
                verticeList.Add(_vec0);
                verticeList.Add(_vec1);
                uvList.Add(new Vector2(0, (float)i/(count-1)));
                uvList.Add(new Vector2(1, (float)i /( count-1)));
            }
            for(var i = 0; i < count-1; i++)
            {               
                    indexList.Add(i*2);
                    indexList.Add(i*2+1);
                    indexList.Add(i*2+2);             
                    indexList.Add(2*i+1);
                    indexList.Add(2*i+1+2);
                    indexList.Add(2*i+1+1);
            }
            var mesh = new Mesh();
            mesh.vertices = verticeList.ToArray();
            mesh.triangles = indexList.ToArray();
            mesh.uv = uvList.ToArray();
            Mf.mesh = mesh;
        }
        #endregion        
    }
}

返回目录:https://blog.csdn.net/yzy1987523/article/details/107739933