Unity中使用贝塞尔曲线

鼎鼎大名的贝塞尔曲线相信大家都耳熟能详。这两天因为工作的原因需要将贝塞尔曲线加在工程中,那么MOMO迅速的研究了一下成果就分享给大家了哦。贝塞尔曲线的原理是由两个点构成的任意角度的曲线,这两个点一个是起点,一个是终点。在这条曲线之上还会有两个可以任意移动的点来控制贝塞尔曲线的角度。如下图所示,点1 和点4 就是起点和终点,点2 和点3 就是控制曲线角度的两个动态点。

 

 

如下图所示。使用拖动条来让曲线发生旋转,大家会看的更加清晰。目前我们看到的被塞尔曲线是在平面中完成的,其实贝塞尔曲线是完全支持3D中完成,这里是为了让大家看的更加清楚MOMO将忽略Z曲线的Z轴。UnityAPI文档中有贝塞尔曲线的方法,可是只支持编辑器中使用,也就是说无法在程序中使用。那么本篇文章我们利用贝塞尔曲线的数学原理以及LineRenderer组件来完成在Unity中使用贝塞尔曲线。

 

 

创建一个U3D的工程,创建一个新游戏对象,绑定LineRenderer组件。

Bezier.cs 这里是贝塞尔曲线的公式C#版本

 

001using UnityEngine;
002  
003[System.Serializable]
004  
005public class Bezier : System.Object
006  
007{
008  
009    public Vector3 p0;
010  
011    public Vector3 p1;
012  
013    public Vector3 p2;
014  
015    public Vector3 p3;
016  
017    public float ti = 0f;
018  
019    private Vector3 b0 = Vector3.zero;
020  
021    private Vector3 b1 = Vector3.zero;
022  
023    private Vector3 b2 = Vector3.zero;
024  
025    private Vector3 b3 = Vector3.zero;
026  
027    private float Ax;
028  
029    private float Ay;
030  
031    private float Az;
032  
033    private float Bx;
034  
035    private float By;
036  
037    private float Bz;
038  
039    private float Cx;
040  
041    private float Cy;
042  
043    private float Cz;
044  
045    // Init function v0 = 1st point, v1 = handle of the 1st point , v2 = handle of the 2nd point, v3 = 2nd point
046  
047    // handle1 = v0 + v1
048  
049    // handle2 = v3 + v2
050  
051    public Bezier( Vector3 v0, Vector3 v1, Vector3 v2, Vector3 v3 )
052  
053    {
054  
055        this.p0 = v0;
056  
057        this.p1 = v1;
058  
059        this.p2 = v2;
060  
061        this.p3 = v3;
062  
063    }
064  
065    // 0.0 >= t <= 1.0
066  
067    public Vector3 GetPointAtTime( float t )
068  
069    {
070  
071        this.CheckConstant();
072  
073        float t2 = t * t;
074  
075        float t3 = t * t * t;
076  
077        float x = this.Ax * t3 + this.Bx * t2 + this.Cx * t + p0.x;
078  
079        float y = this.Ay * t3 + this.By * t2 + this.Cy * t + p0.y;
080  
081        float z = this.Az * t3 + this.Bz * t2 + this.Cz * t + p0.z;
082  
083        return new Vector3( x, y, z );
084  
085    }
086  
087    private void SetConstant()
088  
089    {
090  
091        this.Cx = 3f * ( ( this.p0.x + this.p1.x ) - this.p0.x );
092  
093        this.Bx = 3f * ( ( this.p3.x + this.p2.x ) - ( this.p0.x + this.p1.x ) ) - this.Cx;
094  
095        this.Ax = this.p3.x - this.p0.x - this.Cx - this.Bx;
096  
097        this.Cy = 3f * ( ( this.p0.y + this.p1.y ) - this.p0.y );
098  
099        this.By = 3f * ( ( this.p3.y + this.p2.y ) - ( this.p0.y + this.p1.y ) ) - this.Cy;
100  
101        this.Ay = this.p3.y - this.p0.y - this.Cy - this.By;
102  
103        this.Cz = 3f * ( ( this.p0.z + this.p1.z ) - this.p0.z );
104  
105        this.Bz = 3f * ( ( this.p3.z + this.p2.z ) - ( this.p0.z + this.p1.z ) ) - this.Cz;
106  
107        this.Az = this.p3.z - this.p0.z - this.Cz - this.Bz;
108  
109    }
110  
111    // Check if p0, p1, p2 or p3 have changed
112  
113    private void CheckConstant()
114  
115    {
116  
117        if( this.p0 != this.b0 || this.p1 != this.b1 || this.p2 != this.b2 || this.p3 != this.b3 )
118  
119        {
120  
121            this.SetConstant();
122  
123            this.b0 = this.p0;
124  
125            this.b1 = this.p1;
126  
127            this.b2 = this.p2;
128  
129            this.b3 = this.p3;
130  
131        }
132  
133    }
134  
135}

 

MyBezier.cs 把它直接挂在摄像机上 ,控制拖动条来控制贝塞尔曲线、

01using UnityEngine;
02  
03public class MyBezier : MonoBehaviour
04  
05{
06  
07    //贝塞尔曲线算法类
08    public Bezier myBezier;
09  
10    //曲线的对象
11    public GameObject Yellowline;
12  
13    //曲线对象的曲线组件
14    private LineRenderer YellowlineRenderer;
15  
16    //拖动条用来控制贝塞尔曲线的两个点
17    public float hSliderValue0;
18    public float hSliderValue1;
19  
20    void Start()
21    {
22        //得到曲线组件
23        YellowlineRenderer = Yellowline.GetComponent<LineRenderer>();
24        //为了让曲线更加美观,设置曲线由100个点来组成
25        YellowlineRenderer.SetVertexCount(100);
26    }
27  
28    void OnGUI()
29    {
30        //拖动条得出 -5.0 - 5.0之间的一个数值
31        hSliderValue0 = GUI.HorizontalSlider(new Rect(25, 25, 100, 30), hSliderValue0, -5.0F, 5.0F);
32        hSliderValue1 = GUI.HorizontalSlider(new Rect(25, 70, 100, 30), hSliderValue1, -5.0F, 5.0F);
33    }
34  
35    void Update()
36    {
37        //在这里来计算贝塞尔曲线
38        //四个参数 表示当前贝塞尔曲线上的4个点 第一个点和第四个点
39        //我们是不需要移动的,中间的两个点是由拖动条来控制的。
40        myBezier = new Bezier( new Vector3( -5f, 0f, 0f ),  new Vector3( hSliderValue1, hSliderValue0 , 0f ),  new Vector3( hSliderValue1, hSliderValue0, 0f ), new Vector3( 5f, 0f, 0f ) );
41  
42        //循环100遍来绘制贝塞尔曲线每个线段
43        for(int i =1; i <= 100; i++)
44        {
45            //参数的取值范围 0 - 1 返回曲线没一点的位置
46            //为了精确这里使用i * 0.01 得到当前点的坐标
47            Vector3 vec = myBezier.GetPointAtTime( (float)(i *0.01) );
48            //把每条线段绘制出来 完成白塞尔曲线的绘制
49            YellowlineRenderer.SetPosition(i -1,vec);
50        }
51  
52    }
53  
54}

 

OK 这里贝塞尔曲线的原理就已经完毕。下面我们学习在NGUI中如何使用贝塞尔曲线。刚刚我们说过贝塞尔曲线是由2个固定点 加两个动态点来完成的,其实我们在开发中往往只需要3个点。1 起点 2 中间点 3 结束点 拖动这三个点都可以重新计算曲线的轨迹这样才比较完美。如下图所示,这三个点都是可以任意拖动的,拖动结束后,黑色的线为用户拖拽点连接的直角线段,我们根据这三个点组成的直角线段计算它们之间的贝塞尔曲线,也就是图中黄色的线段。

 

 

简单的进行拖拽一下,是不是感觉贝塞尔曲线很酷炫呢?哇咔咔。

 

 

我们来看看代码实现的部分,其实原理和上面完全一样。

BallMove.cs绑定在这三个可以拖拽的点上,让拖动小球后小球可跟随手指移动。

01using UnityEngine;
02using System.Collections;
03  
04public class BallMove : MonoBehaviour
05{
06  
07    void OnDrag (Vector2 delta)
08    {
09  
10        float movex = transform.localPosition.x + (delta.x / 3);
11        float movey = transform.localPosition.y + (delta.y / 3);
12         //避免越界操作,这里可以进行一些判断
13        transform.localPosition = new Vector3(movex,movey ,transform.localPosition.z);
14    }
15  
16}

 

如此一来触摸小球后,小球将跟随用户手指移动。下面我们将监听用户触摸小球后的坐标来计算它们三点之间的贝塞尔曲线。

BallInit.cs挂在摄像机上

01using UnityEngine;
02using System.Collections;
03  
04public class BallInit : MonoBehaviour {
05  
06    //黑色直角线段
07    LineRenderer lineRenderer0;
08    LineRenderer lineRenderer1;
09    //贝塞尔曲线
10    LineRenderer BezierRenderer;
11  
12    //三个小球触摸对象
13    public GameObject mark0;
14    public GameObject mark1;
15    public GameObject mark2;
16  
17    //算法公式类
18    private Bezier myBezier;
19  
20    void Start ()
21    {
22        //分别得到黑色直角线段 与黄色贝塞尔曲线的 线段组件
23        lineRenderer0 = GameObject.Find("line0").GetComponent<LineRenderer>();
24        lineRenderer1 = GameObject.Find("line1").GetComponent<LineRenderer>();
25        BezierRenderer = GameObject.Find("Bezier").GetComponent<LineRenderer>();
26        //黑色直角是有两个线段组成
27        lineRenderer0.SetVertexCount(2);
28        lineRenderer1.SetVertexCount(2);
29        //为了让贝塞尔曲线细致一些 设置它有100个点组成
30        BezierRenderer.SetVertexCount(100);
31  
32    }
33  
34    void Update ()
35    {
36  
37        //mark0 表示中间的小球
38        //mark1 表示右边的小球
39        //mark2 表示左边的小球
40  
41        //中间的标志点分别减去左右两边的标志点,计算出曲线的X Y 的点
42        float y = (mark0.transform.position.y  - mark2.transform.position.y)  ;
43        float x = (mark0.transform.position.x  - mark2.transform.position.x) ; 
44  
45        //因为我们是通过3个点来确定贝塞尔曲线, 所以参数3 设置为0 即可。
46        //这样参数1 表示起点 参数2表示中间点 参数3 忽略 参数4 表示结束点
47        myBezier = new Bezier( mark2.transform.position,  new Vector3(x,y,0f),  new Vector3(0f,0f,0f), mark1.transform.position );
48  
49        //绘制贝塞尔曲线
50        for(int i =1; i <= 100; i++)
51        {
52            Vector3 vec = myBezier.GetPointAtTime( (float)(i * 0.01) );
53            BezierRenderer.SetPosition(i -1,vec);
54        }
55  
56        //绘制直角黑色标志线段
57        lineRenderer0.SetPosition(0,mark0.transform.position);
58        lineRenderer0.SetPosition(1,mark2.transform.position);
59        lineRenderer1.SetPosition(0,mark0.transform.position);
60        lineRenderer1.SetPosition(1,mark1.transform.position);
61    }
62}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值