NGUI研究院之在Unity中使用贝塞尔曲线(六)

来源:互联网 发布:sql重复列只显示一条 编辑:程序博客网 时间:2024/06/06 02:29

原创文章如需转载请注明:转载自雨松MOMO程序研究院本文链接地址:NGUI研究院之在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        ifthis.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挂在摄像机上

view source
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}

 

 

NGUI部分的源码就不放出来,MOMO将第一个例子的源码放出来,最近生活与工作都有点郁闷,哎~~~ 日子是熬出来,程序也是写出来的,走一步看一步,加油!雨松MOMO祝大家学习愉快,哇咔咔。

下载地址:http://vdisk.weibo.com/s/aceMi

参考文章:http://forum.unity3d.com/threads/5082-Bezier-Curve

原创粉丝点击