Unity教程之-在Unity3d中使用贝塞尔曲线

 

贝塞尔曲线相信大家都耳熟能详。这两天因为工作的原因需要将贝塞尔曲线加在工程中,那么下面我们将研究的成果就分享给大家了哦。贝塞尔曲线的原理是由两个点构成的任意角度的曲线,这两个点一个是起点,一个是终点。在这条曲线之上还会有两个可以任意移动的点来控制贝塞尔曲线的角度。下面我们来看下效果图,

贝塞尔曲线

废话不多说,我们来动手实现下我们自己的贝塞尔曲线插件,贴上代码先:

贝塞尔曲线算法:


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

好了,本篇unity3d教程关于贝塞尔曲线的学习到此结束,下篇我们再会!