Unity中使用贝塞尔曲线

来源:互联网 发布:电子商务淘宝课程视频 编辑:程序博客网 时间:2024/06/04 20:03

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

 

 

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

 

 

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

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

 

view source
001using UnityEngine;
002  
003[System.Serializable]
004  
005public class Bezier : System.Object
006  
007{
008  
009    publicVector3 p0;
010  
011    publicVector3 p1;
012  
013    publicVector3 p2;
014  
015    publicVector3 p3;
016  
017    publicfloat ti = 0f;
018  
019    privateVector3 b0 = Vector3.zero;
020  
021    privateVector3 b1 = Vector3.zero;
022  
023    privateVector3 b2 = Vector3.zero;
024  
025    privateVector3 b3 = Vector3.zero;
026  
027    privatefloat Ax;
028  
029    privatefloat Ay;
030  
031    privatefloat Az;
032  
033    privatefloat Bx;
034  
035    privatefloat By;
036  
037    privatefloat Bz;
038  
039    privatefloat Cx;
040  
041    privatefloat Cy;
042  
043    privatefloat 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    publicBezier( 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    publicVector3 GetPointAtTime( floatt )
068  
069    {
070  
071        this.CheckConstant();
072  
073        floatt2 = t * t;
074  
075        floatt3 = t * t * t;
076  
077        floatx = this.Ax * t3 +this.Bx * t2 +this.Cx * t + p0.x;
078  
079        floaty = this.Ay * t3 +this.By * t2 +this.Cy * t + p0.y;
080  
081        floatz = this.Az * t3 +this.Bz * t2 +this.Cz * t + p0.z;
082  
083        returnnew Vector3( x, y, z );
084  
085    }
086  
087    privatevoid 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    privatevoid 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 把它直接挂在摄像机上 ,控制拖动条来控制贝塞尔曲线、

view source
01using UnityEngine;
02  
03public class MyBezier : MonoBehaviour
04  
05{
06  
07    //贝塞尔曲线算法类
08    publicBezier myBezier;
09  
10    //曲线的对象
11    publicGameObject Yellowline;
12  
13    //曲线对象的曲线组件
14    privateLineRenderer YellowlineRenderer;
15  
16    //拖动条用来控制贝塞尔曲线的两个点
17    publicfloat hSliderValue0;
18    publicfloat hSliderValue1;
19  
20    voidStart()
21    {
22        //得到曲线组件
23        YellowlineRenderer = Yellowline.GetComponent<LineRenderer>();
24        //为了让曲线更加美观,设置曲线由100个点来组成
25        YellowlineRenderer.SetVertexCount(100);
26    }
27  
28    voidOnGUI()
29    {
30        //拖动条得出 -5.0 - 5.0之间的一个数值
31        hSliderValue0 = GUI.HorizontalSlider(newRect(25, 25, 100, 30), hSliderValue0, -5.0F, 5.0F);
32        hSliderValue1 = GUI.HorizontalSlider(newRect(25, 70, 100, 30), hSliderValue1, -5.0F, 5.0F);
33    }
34  
35    voidUpdate()
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(inti =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绑定在这三个可以拖拽的点上,让拖动小球后小球可跟随手指移动。

view source
01using UnityEngine;
02using System.Collections;
03  
04public class BallMove : MonoBehaviour
05{
06  
07    voidOnDrag (Vector2 delta)
08    {
09  
10        floatmovex = transform.localPosition.x + (delta.x / 3);
11        floatmovey = 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    publicGameObject mark0;
14    publicGameObject mark1;
15    publicGameObject mark2;
16  
17    //算法公式类
18    privateBezier myBezier;
19  
20    voidStart ()
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    voidUpdate ()
35    {
36  
37        //mark0 表示中间的小球
38        //mark1 表示右边的小球
39        //mark2 表示左边的小球
40  
41        //中间的标志点分别减去左右两边的标志点,计算出曲线的X Y 的点
42        floaty = (mark0.transform.position.y  - mark2.transform.position.y)  ;
43        floatx = (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(inti =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}

 

原创粉丝点击