关于贝塞尔曲线知识(请具体阅读)转载自:http://www.cnblogs.com/jay-dong/archive/2012/09/26/2704188.html
这里直接讲解在U3D中的实现方式
直接拿三阶贝塞尔曲线为例,首先观察下图:
从图中可以看出,只有四个点是保持不变的,分别是P0,P1,P2,P3,这四个点两两相连得到三个线段
(1)在上四点构成的三个线段中,p0-p1上有到一个点,p1-p2上有到一个点,p2-p3上有到一个点,这三个点分别这在上三个线段做差值运算。现在以上三个点分别取名为A1,A2,A3,这三点两两相连得到绿色线
(2)继续观察可看出,上面得到的三个点构成二个线段,A1-A2上得到一点,A2-A2上有一个点。这两点分别在这二个线段上做差值运算,现将这两点分别为B1,B2。这两点相连得到蓝色线
(3)再观察蓝色线上可看出,有一点在这做差值运算,最终轨迹画成曲线。
方法一:
//实现代码如下:(这里我比上面多添加了一个点,最外层有5个点,依次4个,3个,2个)
//并添加了一个小球,没沿曲线上运动
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class DrawLine : MonoBehaviour {
public List<Transform> gameOjbet_tran = new List<Transform>();
private List<Vector3> point = new List<Vector3>();
public GameObject ball;
public float Speed = 1;
public float Time1 = 2f;
private float Timer = 0;
int i = 1;
// Use this for initialization
void Init()
{
point = new List<Vector3>();
for (int i = 0; i < 200; i++)
{
//一
Vector3 pos1 = Vector3.Lerp(gameOjbet_tran[0].position, gameOjbet_tran[1].position, i / 100f);
Vector3 pos2 = Vector3.Lerp(gameOjbet_tran[1].position, gameOjbet_tran[2].position, i / 100f);
Vector3 pos3 = Vector3.Lerp(gameOjbet_tran[2].position, gameOjbet_tran[3].position, i / 100f);
Vector3 pos4 = Vector3.Lerp(gameOjbet_tran[3].position, gameOjbet_tran[4].position, i / 100f);
//二
var pos1_0 = Vector3.Lerp(pos1, pos2, i / 100f);
var pos1_1 = Vector3.Lerp(pos2, pos3, i / 100f);
var pos1_2 = Vector3.Lerp(pos3, pos4, i / 100f);
//三
var pos2_0 = Vector3.Lerp(pos1_0, pos1_1, i / 100f);
var pos2_1 = Vector3.Lerp(pos1_1, pos1_2, i / 100f);
//四
Vector3 find = Vector3.Lerp(pos2_0, pos2_1, i / 100f);
point.Add(find);
}
}
void OnDrawGizmos()//画线
{
Init();
Gizmos.color = Color.yellow;
for (int i = 0; i < point.Count-1; i++)
{
Gizmos.DrawLine(point[i], point[i + 1]);
}
}
//------------------------------------------------------------------------------
//使小球没曲线运动
//这里不能直接在for里以Point使用差值运算,看不到小球运算效果
//定义一个计时器,在相隔时间内进行一次差值运算。
void Awake()
{
Init();
}
void Update()
{
Timer += Time.deltaTime;
if (Timer > Time1)
{
Timer = 0;
ball.transform.localPosition = Vector3.Lerp(point[i - 1], point[i], 1f);
i++;
if (i >= point.Count) i = 1;
}
}
}
方法二:
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;
}
}
}
绑定到场景中的脚本,要用line Renderer组件
using UnityEngine;
public class MyBezier : MonoBehaviour
{
public Bezier myBezier;
public GameObject Yellowline;
private LineRenderer YellowlineRenderer;
public float hSliderValue0;
public float hSliderValue1;
void Start()
{
YellowlineRenderer = Yellowline.GetComponent<LineRenderer>();
YellowlineRenderer.SetVertexCount(100);
}
void OnGUI()
{
hSliderValue0 = GUI.HorizontalSlider(new Rect(25, 25, 100, 30), hSliderValue0, -5.0F, 5.0F);
hSliderValue1 = GUI.HorizontalSlider(new Rect(25, 70, 100, 30), hSliderValue1, -5.0F, 5.0F);
}
void Update()
{
myBezier = new Bezier( new Vector3( -5f, 0f, 0f ), new Vector3( hSliderValue1, hSliderValue0 , 0f ), new Vector3( hSliderValue1, hSliderValue0, 0f ), new Vector3( 5f, 0f, 0f ) );
for(int i =1; i <= 100; i++)
{
Vector3 vec = myBezier.GetPointAtTime( (float)(i *0.01) );
YellowlineRenderer.SetPosition(i -1,vec);
}
}
}