鼎鼎大名的贝塞尔曲线相信大家都耳熟能详。这两天因为工作的原因需要将贝塞尔曲线加在工程中,那么MOMO迅速的研究了一下成果就分享给大家了哦。贝塞尔曲线的原理是由两个点构成的任意角度的曲线,这两个点一个是起点,一个是终点。在这条曲线之上还会有两个可以任意移动的点来控制贝塞尔曲线的角度。如下图所示,点1 和点4 就是起点和终点,点2 和点3 就是控制曲线角度的两个动态点。
如下图所示。使用拖动条来让曲线发生旋转,大家会看的更加清晰。目前我们看到的被塞尔曲线是在平面中完成的,其实贝塞尔曲线是完全支持3D中完成,这里是为了让大家看的更加清楚MOMO将忽略Z曲线的Z轴。UnityAPI文档中有贝塞尔曲线的方法,可是只支持编辑器中使用,也就是说无法在程序中使用。那么本篇文章我们利用贝塞尔曲线的数学原理以及LineRenderer组件来完成在Unity中使用贝塞尔曲线。
创建一个U3D的工程,创建一个新游戏对象,绑定LineRenderer组件。
Bezier.cs 这里是贝塞尔曲线的公式C#版本
005 | public class Bezier : System.Object |
017 | public float ti = 0f; |
019 | private Vector3 b0 = Vector3.zero; |
021 | private Vector3 b1 = Vector3.zero; |
023 | private Vector3 b2 = Vector3.zero; |
025 | private Vector3 b3 = Vector3.zero; |
051 | public Bezier( Vector3 v0, Vector3 v1, Vector3 v2, Vector3 v3 ) |
067 | public Vector3 GetPointAtTime( float t ) |
071 | this .CheckConstant(); |
075 | float t3 = t * t * t; |
077 | float x = this .Ax * t3 + this .Bx * t2 + this .Cx * t + p0.x; |
079 | float y = this .Ay * t3 + this .By * t2 + this .Cy * t + p0.y; |
081 | float z = this .Az * t3 + this .Bz * t2 + this .Cz * t + p0.z; |
083 | return new Vector3( x, y, z ); |
087 | private void SetConstant() |
091 | this .Cx = 3f * ( ( this .p0.x + this .p1.x ) - this .p0.x ); |
093 | this .Bx = 3f * ( ( this .p3.x + this .p2.x ) - ( this .p0.x + this .p1.x ) ) - this .Cx; |
095 | this .Ax = this .p3.x - this .p0.x - this .Cx - this .Bx; |
097 | this .Cy = 3f * ( ( this .p0.y + this .p1.y ) - this .p0.y ); |
099 | this .By = 3f * ( ( this .p3.y + this .p2.y ) - ( this .p0.y + this .p1.y ) ) - this .Cy; |
101 | this .Ay = this .p3.y - this .p0.y - this .Cy - this .By; |
103 | this .Cz = 3f * ( ( this .p0.z + this .p1.z ) - this .p0.z ); |
105 | this .Bz = 3f * ( ( this .p3.z + this .p2.z ) - ( this .p0.z + this .p1.z ) ) - this .Cz; |
107 | this .Az = this .p3.z - this .p0.z - this .Cz - this .Bz; |
113 | private void CheckConstant() |
117 | if ( this .p0 != this .b0 || this .p1 != this .b1 || this .p2 != this .b2 || this .p3 != this .b3 ) |
MyBezier.cs 把它直接挂在摄像机上 ,控制拖动条来控制贝塞尔曲线、
03 | public class MyBezier : MonoBehaviour |
08 | public Bezier myBezier; |
11 | public GameObject Yellowline; |
14 | private LineRenderer YellowlineRenderer; |
17 | public float hSliderValue0; |
18 | public float hSliderValue1; |
23 | YellowlineRenderer = Yellowline.GetComponent<LineRenderer>(); |
25 | YellowlineRenderer.SetVertexCount(100); |
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); |
40 | myBezier = new Bezier( new Vector3( -5f, 0f, 0f ), new Vector3( hSliderValue1, hSliderValue0 , 0f ), new Vector3( hSliderValue1, hSliderValue0, 0f ), new Vector3( 5f, 0f, 0f ) ); |
43 | for ( int i =1; i <= 100; i++) |
47 | Vector3 vec = myBezier.GetPointAtTime( ( float )(i *0.01) ); |
49 | YellowlineRenderer.SetPosition(i -1,vec); |
OK 这里贝塞尔曲线的原理就已经完毕。下面我们学习在NGUI中如何使用贝塞尔曲线。刚刚我们说过贝塞尔曲线是由2个固定点 加两个动态点来完成的,其实我们在开发中往往只需要3个点。1 起点 2 中间点 3 结束点 拖动这三个点都可以重新计算曲线的轨迹这样才比较完美。如下图所示,这三个点都是可以任意拖动的,拖动结束后,黑色的线为用户拖拽点连接的直角线段,我们根据这三个点组成的直角线段计算它们之间的贝塞尔曲线,也就是图中黄色的线段。
简单的进行拖拽一下,是不是感觉贝塞尔曲线很酷炫呢?哇咔咔。
我们来看看代码实现的部分,其实原理和上面完全一样。
BallMove.cs绑定在这三个可以拖拽的点上,让拖动小球后小球可跟随手指移动。
02 | using System.Collections; |
04 | public class BallMove : MonoBehaviour |
07 | void OnDrag (Vector2 delta) |
10 | float movex = transform.localPosition.x + (delta.x / 3); |
11 | float movey = transform.localPosition.y + (delta.y / 3); |
13 | transform.localPosition = new Vector3(movex,movey ,transform.localPosition.z); |
如此一来触摸小球后,小球将跟随用户手指移动。下面我们将监听用户触摸小球后的坐标来计算它们三点之间的贝塞尔曲线。
BallInit.cs挂在摄像机上
02 | using System.Collections; |
04 | public class BallInit : MonoBehaviour { |
07 | LineRenderer lineRenderer0; |
08 | LineRenderer lineRenderer1; |
10 | LineRenderer BezierRenderer; |
13 | public GameObject mark0; |
14 | public GameObject mark1; |
15 | public GameObject mark2; |
18 | private Bezier myBezier; |
23 | lineRenderer0 = GameObject.Find( "line0" ).GetComponent<LineRenderer>(); |
24 | lineRenderer1 = GameObject.Find( "line1" ).GetComponent<LineRenderer>(); |
25 | BezierRenderer = GameObject.Find( "Bezier" ).GetComponent<LineRenderer>(); |
27 | lineRenderer0.SetVertexCount(2); |
28 | lineRenderer1.SetVertexCount(2); |
30 | BezierRenderer.SetVertexCount(100); |
42 | float y = (mark0.transform.position.y - mark2.transform.position.y) ; |
43 | float x = (mark0.transform.position.x - mark2.transform.position.x) ; |
47 | myBezier = new Bezier( mark2.transform.position, new Vector3(x,y,0f), new Vector3(0f,0f,0f), mark1.transform.position ); |
50 | for ( int i =1; i <= 100; i++) |
52 | Vector3 vec = myBezier.GetPointAtTime( ( float )(i * 0.01) ); |
53 | BezierRenderer.SetPosition(i -1,vec); |
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); |