美文网首页unity
Unity 中贝赛尔曲线的应用

Unity 中贝赛尔曲线的应用

作者: 罗卡恩 | 来源:发表于2019-03-25 15:28 被阅读79次

Unity中我们常见一些有弧度的曲线 足球射门之类的我们可以用到贝塞尔曲线

数学原理

线性贝塞尔曲线 线性贝塞尔曲线

看起来类似unity自带的Lerp一样

二次贝塞尔曲线 二次贝塞尔曲线

从绿色线的头部到尾部 同时绿色线的头从P0→P1
绿色线的尾从P1-P2

三次贝塞尔曲线和N次 三次贝塞尔曲线

然后我们发现三次两个绿线又出来个蓝线 根据蓝线移动

N次的图就没找到 反正就是在一堆点之内控制移动 N次依此类推

Unity应用

直接整一个工具类使用 这是常用的2次贝赛尔曲线

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 二次贝塞尔函数工具类
/// </summary>
public class BezierUtils : MonoBehaviour
{
    /// <summary>
    /// 根据T值,计算贝赛尔曲线上面对应的点
    /// </summary>
    /// <param name="t"></param>T值
    /// <param name="p0"></param>起始点
    /// <param name="p1"></param>控制点
    /// <param name="p2"></param>目标点
    /// <returns></returns>根据T值计算出来的贝赛尔曲线
    /// (1-t)2P0+2(1-t)tP1+t2P2
    static Vector3 CalculateCubicBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2)
    {
        float u = 1 - t;
        float tt = t * t;
        float uu = u * u;

        Vector3 p = uu * p0;//(1-t)2P0
        p += 2 * u * t * p1;//2(1-t)tP1
        p += tt * p2;//t2P2

        return p;
    }
    /// <summary>
    /// 获取一个贝赛尔曲线点的数组
    /// </summary>
    /// <param name="startPoint"></param>起始点
    /// <param name="contiolPoint"></param>控制点
    /// <param name="endPoint"></param>目标点
    /// <param name="segmentNum"></param>采样点的数量 精度
    /// <returns></returns>一个贝赛尔曲线的数组
    public static List<Vector3> GetBeizerList(Vector3 startPoint, Vector3 contiolPoint, Vector3 endPoint, int segmentNum)
    {
        List<Vector3> path = new List<Vector3>();
       // Vector3[] path = new Vector3[segmentNum];
        //若长度为5 采样点为 1/5 2/5 3/5 4/5 5/5k
        for (int i = 1; i <= segmentNum; i++)
        {
            float t = i / (float)segmentNum;
            Vector3 pixel = CalculateCubicBezierPoint(t, startPoint, contiolPoint, endPoint);
            path.Add(pixel);           
            Debug.Log(path[i - 1]);
        }
        return path;
    }
}

然后是测试类

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestBezier : MonoBehaviour
{
    [Header("开始目标")]
    public Transform targe1;
    [Header("控制点")]
    public Transform controlPoint;
    [Header("终点目标")]
    public Transform targe2;
    [Header("精确度")]
    public int accuracy = 5;
    [Header("速度")]
    public float speed = 1;
    float t;
    [Header("是否开始移动")]
    public bool isMove = false;//手动控制
    List<Vector3> path;

    void Awake()
    {
        path = BezierUtils.GetBeizerList(targe1.position, controlPoint.position, targe2.position, accuracy);
    }
    /// <summary>
    /// 寻路模拟
    /// </summary>
    /// <param name="path"></param>
    public void FindPath(List<Vector3> path)
    {
        t += Time.deltaTime;
        if (t >= speed)
        {
            t = 0;
            if (path != null && path.Count > 0)
            {
                var startPos = path[0];
                targe1.transform.position = startPos;
                path.Remove(startPos);
            }
        }
    }
    // Update is called once per frame
    void Update()
    {
        if (isMove == true)
        {
            FindPath(path);
        }

    }
}

控制点控制的是曲线的弯曲程度
精度就是那个List的长度 越长越精确计算量越大
速度就是移动到每一个点的速度(也是遍历速度)

image.png

这个要运行后勾选才可以动 因为一运行就动会卡顿一下 看着不爽 就麻烦点改为手动控制开始移动

但是有一个问题 他们移动时间是固定的 在除了两球距离其他不变的情况下 两个球距离越短 就看起来速度越慢 两球距离越长 速度就越快

然后开始优化
根据长度自动设置区间 (这个要找自己适应的规律) 控制最高点的球自动设置到两球中央一定高度

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 二次贝塞尔函数工具类
/// </summary>
public class BezierUtils 
{
    /// <summary>
    /// 根据T值,计算贝赛尔曲线上面对应的点
    /// </summary>
    /// <param name="t"></param>T值
    /// <param name="p0"></param>起始点
    /// <param name="p1"></param>控制点
    /// <param name="p2"></param>目标点
    /// <returns></returns>根据T值计算出来的贝赛尔曲线
    /// (1-t)2P0+2(1-t)tP1+t2P2
    static Vector3 CalculateCubicBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2)
    {
        float u = 1 - t;
        float tt = t * t;
        float uu = u * u;

        Vector3 p = uu * p0;//(1-t)2P0
        p += 2 * u * t * p1;//2(1-t)tP1
        p += tt * p2;//t2P2

        return p;
    }
    /// <summary>
    /// 获取一个贝赛尔曲线点的数组
    /// </summary>
    /// <param name="startPoint"></param>起始点
    /// <param name="contiolPoint"></param>控制点
    /// <param name="endPoint"></param>目标点
    /// <param name="segmentNum"></param>采样点的数量 精度
    /// <returns></returns>一个贝赛尔曲线的数组
    public static List<Vector3> GetBeizerList(Vector3 startPoint, Vector3 contiolPoint, Vector3 endPoint)
    {
        //计算所合适的区间数 优化远近差值速度 根据自身情况找规律设置 我的是按2D屏幕坐标左到右 从上到下
        var segmentNum =15+ (int)(Mathf.Abs(endPoint.x - startPoint.x) * 0.02f) +(int)(Mathf.Abs(endPoint.y - startPoint.y) * 0.02f);


        List<Vector3> path = new List<Vector3>();
       // Vector3[] path = new Vector3[segmentNum];
        //若长度为5 采样点为 1/5 2/5 3/5 4/5 5/5k
        for (int i = 1; i <= segmentNum; i++)
        {
            float t = i / (float)segmentNum;
            Vector3 pixel = CalculateCubicBezierPoint(t, startPoint, contiolPoint, endPoint);
            path.Add(pixel);           
           // Debug.Log(path[i - 1]);
        }
        return path;
    }

    /// <summary>
    /// 获得他们中心点向上一定距离的点 只适用2D
    /// </summary>
    /// <param name="startPoint"></param>
    /// <param name="endPoint"></param>
    /// <returns></returns>
   public static Vector3 GetControlPoint(Vector3 startPoint, Vector3 endPoint, float dValue)
    {
        Vector3 p1 = startPoint;
        Vector3 p2 = endPoint;
        //向量p1p2
        Vector3 p1p2 = (p2 - p1);
        Debug.Log(p1p2);
        //求中心开始向量和结束向量的一半向量
        Vector3 halfP1P2 = p1 + p1p2 * 0.5f;    
        //求他们的旋转向量的方法 把向量p2p1以Z轴旋转90度 如果end在start左边就p1p2为负数改变方向
        Vector3 pVertical = Quaternion.AngleAxis(90, Vector3.forward*p1p2.normalized.x) * p1p2;
        //那么中心点坐标为从一半开始的向量 加上pVertical的方向乘上长度
        Vector3 controlPoint = halfP1P2 + pVertical.normalized * dValue;
        return controlPoint;
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestBezier : MonoBehaviour
{
    public Transform targe3;
    [Header("开始目标")]
    public Transform targe1;
    [Header("控制点高度")]
    public float hight;
    [Header("终点目标")]
    public Transform targe2;
    [Header("速度")]
    public float speed = 1;
    float t;
    [Header("是否开始移动")]
    public bool isMove = false;//手动控制
    List<Vector3> path;

    void Awake()
    {
        var controlPoint = BezierUtils.GetControlPoint(targe1.position,targe2.position,hight);
        targe3.position = controlPoint;
        path = BezierUtils.GetBeizerList(targe1.position, controlPoint, targe2.position);
    }
    /// <summary>
    /// 寻路模拟
    /// </summary>
    /// <param name="path"></param>
    public void FindPath(List<Vector3> path)
    {
        t += Time.deltaTime;
        if (t >= speed)
        {
            t = 0;
            if (path != null && path.Count > 0)
            {
                var startPos = path[0];            
                targe1.transform.position = startPos;
                path.Remove(startPos);
            }
        }
    }
   
    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            isMove = true;
        }
        if (isMove == true)
        {
            FindPath(path);
        }

    }
}

按空格开始这样 距离远近速度就更平缓 中心点按高度设置 不过只能在两者中点
我觉得高度100 速度0.01就差不多

GIF.gif

这个是项目源码
https://github.com/1004019267/SecondOrderBezier/tree/master

相关文章

  • Unity 中贝赛尔曲线的应用

    Unity中我们常见一些有弧度的曲线 足球射门之类的我们可以用到贝塞尔曲线 数学原理 看起来类似unity自带的L...

  • 贝赛尔曲线实现css3动画效果

    一、什么叫做贝赛尔曲线 贝塞尔曲线(Bézier curve),又叫作贝兹曲线或贝济埃曲线,是应用于二维图形应用程...

  • 贝塞尔曲线

    首先我们要知道什么是贝赛尔曲线,贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形...

  • Bezier曲线切割

    贝塞尔曲线 目标:在unity中展示Bezier曲线。 贝塞尔曲线原理 用代码实现 bezier数学公式 Bezi...

  • 详解SVG路径path的贝塞尔曲线

    什么是贝塞尔曲线? “什么是贝塞尔曲线?”又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。贝塞尔曲线...

  • 在 Chrome 下调试贝塞尔曲线

    chrome、css、cubic-bezier 什么是贝塞尔曲线 贝塞尔曲线是应用于二维图形应用程序中的数学曲线,...

  • iOS开发:浅谈贝塞尔曲线

    贝塞尔曲线 贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。...

  • 开放的多点贝塞尔曲线实现

    开放的多点贝赛尔曲线实现 初识贝塞尔曲线 在实现开放的多点贝塞尔曲线之前,我们先了解下贝塞尔曲线的一些基本的知识....

  • 贝塞尔曲线动画效果

    效果 贝塞尔曲线 贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学...

  • Android-贝塞尔曲线的应用

    什么是贝塞尔曲线 贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学...

网友评论

    本文标题:Unity 中贝赛尔曲线的应用

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