NGUI研究之在Unity中使用贝塞尔曲线

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

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

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

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

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;

}

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

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;

}

}

}

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

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>();
//为了让曲线更加美观,设置曲线由100个点来组成
YellowlineRenderer.SetVertexCount(100);
}

void OnGUI()
{
//拖动条得出 -5.0 - 5.0之间的一个数值
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()
{
//在这里来计算贝塞尔曲线
//四个参数 表示当前贝塞尔曲线上的4个点 第一个点和第四个点
//我们是不需要移动的,中间的两个点是由拖动条来控制的。
myBezier = new Bezier( new Vector3( -5f, 0f, 0f ), new Vector3( hSliderValue1, hSliderValue0 , 0f ), new Vector3( hSliderValue1, hSliderValue0, 0f ), new Vector3( 5f, 0f, 0f ) );

//循环100遍来绘制贝塞尔曲线每个线段
for(int i =1; i <= 100; i++)
{
//参数的取值范围 0 - 1 返回曲线没一点的位置
//为了精确这里使用i * 0.01 得到当前点的坐标
Vector3 vec = myBezier.GetPointAtTime( (float)(i *0.01) );
//把每条线段绘制出来 完成白塞尔曲线的绘制
YellowlineRenderer.SetPosition(i -1,vec);
}

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

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>();

//为了让曲线更加美观,设置曲线由100个点来组成

YellowlineRenderer.SetVertexCount(100);

}

void
OnGUI()

{

//拖动条得出 -5.0 - 5.0之间的一个数值

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()

{

//在这里来计算贝塞尔曲线

//四个参数 表示当前贝塞尔曲线上的4个点 第一个点和第四个点

//我们是不需要移动的,中间的两个点是由拖动条来控制的。

myBezier
= new
Bezier(
new Vector3(
-5f,
0f,
0f ),  new
Vector3(
hSliderValue1,
hSliderValue0
, 0f
),  new
Vector3(
hSliderValue1,
hSliderValue0,
0f ),
new Vector3(
5f,
0f,
0f )
);

//循环100遍来绘制贝塞尔曲线每个线段

for(int
i =1;
i <=
100;
i++)

{

//参数的取值范围 0 - 1 返回曲线没一点的位置

//为了精确这里使用i * 0.01 得到当前点的坐标

Vector3
vec =
myBezier.GetPointAtTime(
(float)(i *0.01)
);

//把每条线段绘制出来 完成白塞尔曲线的绘制

YellowlineRenderer.SetPosition(i
-1,vec);

}

}

}

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

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

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

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

using UnityEngine;
using System.Collections;

public class BallMove : MonoBehaviour
{

void OnDrag (Vector2 delta)
{

float movex = transform.localPosition.x + (delta.x / 3);
float movey = transform.localPosition.y + (delta.y / 3);
//避免越界操作,这里可以进行一些判断
transform.localPosition = new Vector3(movex,movey ,transform.localPosition.z);
}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

using
UnityEngine;

using System.Collections;

public class
BallMove :
MonoBehaviour

{

void
OnDrag (Vector2
delta)

{

float
movex =
transform.localPosition.x
+ (delta.x
/ 3);

float
movey =
transform.localPosition.y
+ (delta.y
/ 3);

//避免越界操作,这里可以进行一些判断

transform.localPosition
= new
Vector3(movex,movey
,transform.localPosition.z);

}

}

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

BallInit.cs挂在摄像机上

using UnityEngine;
using System.Collections;

public class BallInit : MonoBehaviour {

//黑色直角线段
LineRenderer lineRenderer0;
LineRenderer lineRenderer1;
//贝塞尔曲线
LineRenderer BezierRenderer;

//三个小球触摸对象
public GameObject mark0;
public GameObject mark1;
public GameObject mark2;

//算法公式类
private Bezier myBezier;

void Start ()
{
//分别得到黑色直角线段 与黄色贝塞尔曲线的 线段组件
lineRenderer0 = GameObject.Find("line0").GetComponent<LineRenderer>();
lineRenderer1 = GameObject.Find("line1").GetComponent<LineRenderer>();
BezierRenderer = GameObject.Find("Bezier").GetComponent<LineRenderer>();
//黑色直角是有两个线段组成
lineRenderer0.SetVertexCount(2);
lineRenderer1.SetVertexCount(2);
//为了让贝塞尔曲线细致一些 设置它有100个点组成
BezierRenderer.SetVertexCount(100);

}

void Update ()
{

//mark0 表示中间的小球
//mark1 表示右边的小球
//mark2 表示左边的小球

//中间的标志点分别减去左右两边的标志点,计算出曲线的X Y 的点
float y = (mark0.transform.position.y - mark2.transform.position.y) ;
float x = (mark0.transform.position.x - mark2.transform.position.x) ;

//因为我们是通过3个点来确定贝塞尔曲线, 所以参数3 设置为0 即可。
//这样参数1 表示起点 参数2表示中间点 参数3 忽略 参数4 表示结束点
myBezier = new Bezier( mark2.transform.position, new Vector3(x,y,0f), new Vector3(0f,0f,0f), mark1.transform.position );

//绘制贝塞尔曲线
for(int i =1; i <= 100; i++)
{
Vector3 vec = myBezier.GetPointAtTime( (float)(i * 0.01) );
BezierRenderer.SetPosition(i -1,vec);
}

//绘制直角黑色标志线段
lineRenderer0.SetPosition(0,mark0.transform.position);
lineRenderer0.SetPosition(1,mark2.transform.position);
lineRenderer1.SetPosition(0,mark0.transform.position);
lineRenderer1.SetPosition(1,mark1.transform.position);
}
}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

using
UnityEngine;

using System.Collections;

public class
BallInit :
MonoBehaviour
{

//黑色直角线段

LineRenderer
lineRenderer0;

LineRenderer lineRenderer1;

//贝塞尔曲线

LineRenderer BezierRenderer;

//三个小球触摸对象

public
GameObject mark0;

public
GameObject mark1;

public
GameObject mark2;

//算法公式类

private
Bezier myBezier;

void
Start ()

{

//分别得到黑色直角线段 与黄色贝塞尔曲线的 线段组件

lineRenderer0
= GameObject.Find("line0").GetComponent<LineRenderer>();

lineRenderer1
= GameObject.Find("line1").GetComponent<LineRenderer>();

BezierRenderer
= GameObject.Find("Bezier").GetComponent<LineRenderer>();

//黑色直角是有两个线段组成

lineRenderer0.SetVertexCount(2);

lineRenderer1.SetVertexCount(2);

//为了让贝塞尔曲线细致一些 设置它有100个点组成

BezierRenderer.SetVertexCount(100);

}

void
Update ()

{

//mark0 表示中间的小球

//mark1 表示右边的小球

//mark2 表示左边的小球

//中间的标志点分别减去左右两边的标志点,计算出曲线的X Y 的点

float
y =
(mark0.transform.position.y  -
mark2.transform.position.y)  ;

float
x =
(mark0.transform.position.x  -
mark2.transform.position.x)
;

//因为我们是通过3个点来确定贝塞尔曲线, 所以参数3 设置为0 即可。

//这样参数1 表示起点 参数2表示中间点 参数3 忽略 参数4 表示结束点

myBezier
= new
Bezier(
mark2.transform.position,  new
Vector3(x,y,0f),  new
Vector3(0f,0f,0f),
mark1.transform.position
);

//绘制贝塞尔曲线

for(int
i =1;
i <=
100;
i++)

{

Vector3 vec
= myBezier.GetPointAtTime(
(float)(i *
0.01)
);

BezierRenderer.SetPosition(i
-1,vec);

}

//绘制直角黑色标志线段

lineRenderer0.SetPosition(0,mark0.transform.position);

lineRenderer0.SetPosition(1,mark2.transform.position);

lineRenderer1.SetPosition(0,mark0.transform.position);

lineRenderer1.SetPosition(1,mark1.transform.position);

}

}

时间: 2024-10-22 17:00:50

NGUI研究之在Unity中使用贝塞尔曲线的相关文章

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

鼎鼎大名的贝塞尔曲线相信大家都耳熟能详.这两天因为工作的原因需要将贝塞尔曲线加在工程中,那么MOMO迅速的研究了一下成果就分享给大家了哦.贝塞尔曲线的原理是由两个点构成的任意角度的曲线,这两个点一个是起点,一个是终点.在这条曲线之上还会有两个可以任意移动的点来控制贝塞尔曲线的角度.如下图所示,点1 和点4 就是起点和终点,点2 和点3 就是控制曲线角度的两个动态点. 如下图所示.使用拖动条来让曲线发生旋转,大家会看的更加清晰.目前我们看到的被塞尔曲线是在平面中完成的,其实贝塞尔曲线是完全支持3D

在Unity中使用贝塞尔曲线(转)

鼎鼎大名的贝塞尔曲线相信大家都耳熟能详.这两天因为工作的原因需要将贝塞尔曲线加在工程中,那么MOMO迅速的研究了一下成果就分享给大家了哦.贝塞尔曲线的原理是由两个点构成的任意角度的曲线,这两个点一个是起点,一个是终点.在这条曲线之上还会有两个可以任意移动的点来控制贝塞尔曲线的角度.如下图所示,点1 和点4 就是起点和终点,点2 和点3 就是控制曲线角度的两个动态点. 如下图所示.使用拖动条来让曲线发生旋转,大家会看的更加清晰.目前我们看到的被塞尔曲线是在平面中完成的,其实贝塞尔曲线是完全 支持3

HTML5 Canvas中的贝塞尔曲线

在HTML5提供的画布功能,也就是Canvas中,getContext() 方法可返回一个对象,该对象提供了用于在画布上绘图的方法和属性.本文以getContext("2d")中提供的方法为例,简要研究了其中用于绘制曲线路径的贝塞尔曲线. JavaScript中的getContext("2d")为我们提供了两种绘制贝塞尔曲线路径的方法,分别是quadraticCurveTo()用于绘制二次贝塞尔曲线和bezierCurveTo()用于绘制三次贝塞尔曲线. 什么是贝塞

svg path中的贝塞尔曲线

首先介绍以下什么是贝塞尔曲线 贝塞尔曲线又叫贝茨曲线(Bezier),由两个端点以及若干个控制点组成,只有两个端点在曲线上,控制点不在曲线上,只是控制曲线的走向. 控制点个数为0时,它是一条直线; 控制点个数为1时,它是二次贝塞尔曲线; 控制点个数为2时,它是三次贝塞尔曲线: .... 数学公式 二次贝塞尔曲线 p0,p2是起始点,p1是控制点 分别把p0,p1,p2点的x,y坐标带入,求出曲线上的点的x,y坐标 三次贝塞尔曲线 p0,p3是起始点,p1,p2是控制点 svg的path中与贝塞尔

Unity游戏中使用贝塞尔曲线

孙广东   2015.8.15 比方在3D rpg游戏中.我们想设置弹道,不同的轨迹类型! 目的:这篇文章的主要目的是要给你关于在游戏怎样使用贝塞尔曲线的基本想法. 贝塞尔曲线是最主要的曲线,一般用在计算机 图形学和 图像处理. 贝塞尔曲线能够用来创建平滑的曲线的道路. 弯曲的路径就像 祖玛游戏. 弯曲型的河流等. 一条贝塞尔曲线是由一组定义的控制点 P0到 Pn,在 n 调用它的顺序 (n = 1 为线性.2 为二次,等.).第一个和最后一个控制点总是具有终结点的曲线;然而,中间两个控制点 (

Unity中三次样条插值曲线的实现

最近需要用到插值,但是总觉得线性插值得出来的太过硬了,所以想看一下三次样条曲线怎么做.关于算法和程序实现的文章已经有很多了.这一篇文章写下来主要的目的是为了 帮助自己理解,固化 已有的代码不是在unity平台上实现的,所以代码相对繁杂,这里进一步做简化 我的理解,分段三次样条曲线求解就是: 已知:n个点,n-1个三次方程(a+bx+cx^2+dx^3),而这些三次方程2一阶和二阶导数连续,这些三次方程当然在已知点上也是连续的 一阶二阶导数连续,就是在中间的连接点上(去掉头尾总共n-2个),前后两

关于Unity中的NGUI和UGUI

用Unity开发2D游戏,有三套关系 1.GUI:Unity本身的对象 2.NGUI:以前在Unity中广泛来做2D的,是第三方的包,需要安装 3.UGUI:Unity5.X后,Unity找到NGUI的作者,开发了UGUI,变成内置于Unity中的包,官方主推 所有的元素都在Unity的UI工具栏 3D做2D游戏的方法: 1: 使用正交摄像机;2: 使用透视摄像机,将2D元素移动到合适的距离. 例如设计分辨率为 960x640, 得到在3D世界里面一个图片的大小w*h米,将这个图片移动到一定的距

3D语音天气球——在Unity中使用Android语音服务

转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 开篇废话: 这个项目准备分四部分介绍: 一:创建可旋转的"3D球":3D语音天气球(源码分享)--创建可旋转的3D球 二:通过天气服务,从网络获取时实天气信息并动态生成"3D球":3D语音天气球(源码分享)--通过天气服务动态创建3D球 三:Android语音服务和Unity的消息传递 四:Unity3D端和Android端的结合 前两篇文章已经介绍了如何创

贝塞尔曲线解析-Cocos2dx 01

在数学的数值分析领域中,贝塞尔曲线(英语:Bézier curve)是电脑图形学中相当重要的参数曲线.更高维度的广泛化贝塞尔曲线就称作贝塞尔曲面,其中贝塞尔三角是一种特殊的实例. 贝塞尔曲线于1962年,由法国工程师皮埃尔·贝塞尔(Pierre Bézier)所广泛发表,他运用贝塞尔曲线来为汽车的主体进行设计.贝塞尔曲线最初由Paul de Casteljau于1959年运用de Casteljau算法开发,以稳定数值的方法求出贝塞尔曲线. 线性贝塞尔曲线[编辑] 给定点P0.P1,线性贝塞尔曲