[Unity基础]贝塞尔曲线

参考链接:http://www.xuanyusong.com/archives/1548


贝塞尔曲线算法:

using UnityEngine;
 
[System.Serializable]
public class Bezier : System.Object {
 
    public Vector3 p0;
    public Vector3 p1;
    public Vector3 p2;
    public Vector3 p3;
    public float ti = 0f;
    private Vector3 b0 = Vector3.zero;
    private Vector3 b1 = Vector3.zero;
    private Vector3 b2 = Vector3.zero;
    private Vector3 b3 = Vector3.zero;
 
    private float Ax;
    private float Ay;
    private float Az;
    private float Bx;
    private float By;
    private float Bz;
    private float Cx;
    private float Cy;
    private float Cz;
 
    // Init function v0 = 1st point, v1 = handle of the 1st point , v2 = handle of the 2nd point, v3 = 2nd point
    // handle1 = v0 + v1
    // handle2 = v3 + v2
    public Bezier( Vector3 v0, Vector3 v1, Vector3 v2, Vector3 v3 )
    {
        this.p0 = v0;
        this.p1 = v1;
        this.p2 = v2;
        this.p3 = v3;
    }
 
    // 0.0 >= t <= 1.0
    public Vector3 GetPointAtTime( float t )
    {
        this.CheckConstant();
        float t2 = t * t;
        float t3 = t * t * t;
        float x = this.Ax * t3 + this.Bx * t2 + this.Cx * t + p0.x;
        float y = this.Ay * t3 + this.By * t2 + this.Cy * t + p0.y;
        float z = this.Az * t3 + this.Bz * t2 + this.Cz * t + p0.z;
        return new Vector3( x, y, z );
    }
 
    private void SetConstant() 
    {
        this.Cx = 3f * ( ( this.p0.x + this.p1.x ) - this.p0.x );
        this.Bx = 3f * ( ( this.p3.x + this.p2.x ) - ( this.p0.x + this.p1.x ) ) - this.Cx;
        this.Ax = this.p3.x - this.p0.x - this.Cx - this.Bx;
        this.Cy = 3f * ( ( this.p0.y + this.p1.y ) - this.p0.y );
        this.By = 3f * ( ( this.p3.y + this.p2.y ) - ( this.p0.y + this.p1.y ) ) - this.Cy;
        this.Ay = this.p3.y - this.p0.y - this.Cy - this.By;
        this.Cz = 3f * ( ( this.p0.z + this.p1.z ) - this.p0.z );
        this.Bz = 3f * ( ( this.p3.z + this.p2.z ) - ( this.p0.z + this.p1.z ) ) - this.Cz;
        this.Az = this.p3.z - this.p0.z - this.Cz - this.Bz;
    }
 
    // Check if p0, p1, p2 or p3 have changed
    private void CheckConstant()
    {
        if( this.p0 != this.b0 || this.p1 != this.b1 || this.p2 != this.b2 || this.p3 != this.b3 )
        {
            this.SetConstant();
            this.b0 = this.p0;
            this.b1 = this.p1;
            this.b2 = this.p2;
            this.b3 = this.p3;
        }
    }
}

测试脚本:

using UnityEngine;
using System.Collections;

public class TestBezier : MonoBehaviour {

    public enum State
    {
        none,
        moveState,
        editState
    }
    public State state = State.none;

    private Bezier bezier;
    public GameObject line;//曲线的对象
    private LineRenderer lineRenderer;//曲线对象的曲线组件

    public Transform p1;
    public Transform p2;
    public Transform p3;
    public Transform p4;
    public Transform targetObj;//要移动的对象

    public int pointAmount = 100;//值越大曲线越平滑 
    public float pointTime = 0.01f;//每前进一个点的时间
    private Vector3 v1;

	void Start () 
	{
        lineRenderer = line.GetComponent<LineRenderer>();
        lineRenderer.SetVertexCount(pointAmount);
        v1 = p1.localPosition;//起点不变
	}
	
	void Update () 
	{
        if (state == State.editState)
        {
            float t = 1 / (float)pointAmount;
            bezier = new Bezier(v1, p2.localPosition, p3.localPosition, p4.localPosition);
            for (int i = 1; i <= pointAmount; i++)
            {
                //参数的取值范围 0 - 1 返回曲线每一点的位置
                //为了精确这里使用i * 0.01 得到当前点的坐标
                Vector3 vec = bezier.GetPointAtTime((float)(i * t));
                //把每条线段绘制出来 完成贝塞尔曲线的绘制
                lineRenderer.SetPosition(i - 1, vec);
            }
        }
        else if (state == State.moveState)
        {
            state = State.none;
            StartCoroutine(Move());
        }
	}

    IEnumerator Move()
    {
        bezier = new Bezier(v1, p2.localPosition, p3.localPosition, p4.localPosition);

        float t = 1 / (float)pointAmount;
        int count = 0;
        float timer = 0;

        while (count <= pointAmount)
        {
            if (timer < pointTime)
            {
                timer += Time.deltaTime;
                yield return new WaitForEndOfFrame();
            }
            else
            {
                timer = 0;
                targetObj.localPosition = bezier.GetPointAtTime((float)(count * t));
                count++;
            }
        }
    }
}

效果图:

[Unity基础]贝塞尔曲线_第1张图片

你可能感兴趣的:(贝塞尔曲线)