在Unity中使用贝塞尔曲线_02

作者: Foldcc | 来源:发表于2019-03-07 23:25 被阅读22次

    前言

    上一篇贝塞尔曲线的研究只能满足一段曲线的生成,今天将实现任意曲线生成(多节点连续曲线)。

    设计原理

    指定一段曲线的两个端点(p0,p3)以及两个控制点(p1,p2)然后使用三阶贝塞尔公式即可生成一段连续的曲线,将这一段曲线理解成第
    n个节点到n+1个节点之间的三阶贝塞尔。
    接下来就是创建N个节点了,每一个节点和其对应的下一个节点为一组曲线,最后一个节点不计算。

    如何处理多节点之间的平滑过渡

    每一个节点都有且仅有一个控制点,控制点左边的曲线相当于三阶贝塞尔中的p2点,而右侧则先计算其镜像的坐标作为公式中的p1,这样便可以做到一个控制点同时调节左右曲线的曲率,效果如下。

    两条曲线中间节点的控制点

    设计原理

    BezierNodeObject :节点对象,包含一个控制点属性

    public class BezierNodeObject : MonoBehaviour
    {
        public Transform BezierOffset;
    
        private BezierNode bezierNode;
    
        public BezierNode GetBezierNode()
        {
            bezierNode.nodeOffset = BezierOffset.position;
            bezierNode.nodePos = transform.position;
            return bezierNode;
        }
    
        private void Update()
        {
            Debug.DrawLine(BezierOffset.position, transform.position - (BezierOffset.position - transform.position), Color.yellow);
        }
    }
    

    BezierData : 将所有节点和控制点数据保存,并提供三阶贝塞尔函数接口

    [CreateAssetMenu(fileName = "BezierData", menuName = "Config/BezierData")]
    public class BezierData : ScriptableObject
    {
        [Header("数据集名称")]
        public string DataName;
        [Header("数据节点集")]
        public List<BezierNode> bezierNodes;
        [Header("精度系数,越大越平滑,性能消耗越高"), Range(10, 100)]
        public int accuracy = 10;
    
        /// <summary>
        /// 计算并返回指定一段曲线的坐标位置数组
        /// </summary>
        /// <param name="region">区间下标数值</param>
        /// <returns></returns>
        public Vector3[] GetBezierDatas(int region) {
            if (region < bezierNodes.Count) {
                Vector3[] datas = new Vector3[accuracy];
                for (int i = 0; i < accuracy; i++)
                {
                    BezierMath.Bezier_3ref(
                        ref datas[i],
                        bezierNodes[region].nodePos,
                        bezierNodes[region].getReverseNodeOffset(),
                        bezierNodes[region + 1].nodeOffset,
                        bezierNodes[region + 1].nodePos,
                        i/(accuracy-1.0f)
                    );
                }
                return datas;
            }
            return null;
        }
        public void SetBezierNode(List<BezierNodeObject> bezierNodeObjects) {
            if (bezierNodes == null) bezierNodes = new List<BezierNode>();
            bezierNodes.Clear();
    
            foreach (var item in bezierNodeObjects)
            {
                bezierNodes.Add(item.GetBezierNode());
            }
        }
    }
    

    BezierLine : 按照一定的精度从BezierData中获取每一段曲线上的坐标,将坐标信息传递给Unity的LineRenderer并绘制出line

    public class BezierDrawLine : MonoBehaviour
    {
        private List<BezierNodeObject> bezierNodeObjects;
        private BezierData bezierData;
        private List<Vector3> vector3s;
    
        public Transform NodesRoot;
    
        [Header("精度系数,表示每一段有多少个节点"),Range(10 , 100)]
        public int accuracy;
    
        private void Start()
        {
            bezierNodeObjects = new List<BezierNodeObject>();
            bezierData = new BezierData();
            vector3s = new List<Vector3>();
        }
    
        private void Update()
        {
            if (!NodesRoot) return;
            bezierNodeObjects.Clear();
            bezierNodeObjects.AddRange(NodesRoot.GetComponentsInChildren<BezierNodeObject>());
            bezierData.SetBezierNode(bezierNodeObjects);
            bezierData.accuracy = accuracy;
            drawline();
        }
    
        void drawline() {
            for (int i = 0; i < bezierNodeObjects.Count - 1; i++)
            {
                var lineRenderer = bezierNodeObjects[i].GetComponent<LineRenderer>();
                if (lineRenderer == null) lineRenderer = bezierNodeObjects[i].gameObject.AddComponent<LineRenderer>();
                lineRenderer.positionCount = accuracy;
                lineRenderer.SetPositions(bezierData.GetBezierDatas(i));
            }
        }
    }
    

    以上代码仅供参考,如果需要,下方将提供git项目地址。

    实际效果展示

    多节点贝塞尔曲线 可调细分程度

    [项目地址:BezierTool]

    相关文章

      网友评论

        本文标题:在Unity中使用贝塞尔曲线_02

        本文链接:https://www.haomeiwen.com/subject/sfskpqtx.html