关于贝塞尔曲线在游戏开发中的应用
发表于2019-01-25
贝塞尔曲线用到的地方太多了,unity里的曲线编辑器基本都是贝塞尔曲线,还有photoshop里的钢笔路径等等,那我们自己平时开发的时候能不能用上这个东西呢?答案是肯定的,比如各种动画,移动轨迹,还有一些漂亮的几何图形我们都可以使用它来完成,那我们我们来尝试自己应用一下这个神奇的曲线吧
贝塞尔曲线有好几种,最常用的是3次方的公式,就是由p0-3的4个点来确定的一条曲线,
看一个效果:
首先看一下公式,来自百度百科:
公式看着很简单,只有一个变量t,我们可以把它看成从起点到终点的距离的百分比/100.
来看一下把公式放到c#中的样子:
public static float GetBezierat(float a, float b, float c, float d, float t) { return (Mathf.Pow(1 - t, 3) * a + 3 * t * (Mathf.Pow(1 - t, 2)) * b + 3 * Mathf.Pow(t, 2) * (1 - t) * c + Mathf.Pow(t, 3) * d); }
现在我们尝试用这个公式在游戏中绘制一条贝塞尔曲线
创建测试脚本BezierTest,并放到游戏场景中。
定义一个数组,用来存储曲线的控制点
public List<GameObject> obj;
在编辑器中创建四个点作为曲线的控制点。然后放入到测试脚本的数组中。
然后实现一个方法,作用是输入4个坐标点,获取有这些点生成的曲线上的关键点,并存储到坐标列表中,用来绘制曲线。
public List<Vector3> poslist = new List<Vector3>(); void CreateLinePoint(Vector3[] vlist) { float rate = 0; while (rate < 1) { rate += 1f / step; float x = GetBezierat( vlist[0].x, vlist[1].x, vlist[2].x, vlist[3].x, rate); float y = GetBezierat( vlist[0].y, vlist[1].y, vlist[2].y, vlist[3].y, rate); poslist.Add(new Vector3(x, y, 0)); } }
注意在实际的使用过程中,我们需要分别计算x和y坐标。然后在Start方法中找到四个物体并把坐标点传入CreateLinePoint方法中:
void Start () {
Vector3[] vlist = new Vector3[4];
for (int i = 0; i < obj.Count; i ++){
vlist[i] = (obj[i].transform.position);
}
CreateLinePoint(vlist);
}
最后按照关键点绘制直线即可:
public void OnDrawGizmos() { #if UNITY_EDITOR Gizmos.color = Color.blue; Handles.color = Color.blue; for (int i = 0; i < poslist.Count; i++) { if (i == poslist.Count - 1) continue; Gizmos.DrawLine(poslist[i], poslist[i + 1]); } #endif }
这里需要引入命名空间:
#if UNITY_EDITOR using UnityEditor; #endif
看下效果:
我们可以看到曲线只会经过第1和第4个点,要想让曲线经过每个点的话,我们可以使用每2个相邻的点作为起点和终点,然后计算出2个辅助点的位置,这里我们使用最简单的办法,即把起始点的坐标向后平移最为第一个辅助点,然后把终点左标向前平移作为第二个辅助点,如下图:
现在来修改我们的代码,把Start中的代码改成这样:
void Start () { for (int i = 0; i < obj.Count; i++) { Vector3 v1 = obj[i].transform.position; int lastindex = Mathf.Min(i + 1, obj.Count - 1); Vector3 v4 = obj[lastindex].transform.position; Vector3 v2 = new Vector3(v1.x + (v4.x - v1.x) * 0.5f, v1.y, 0); Vector3 v3 = new Vector3(v4.x - (v4.x - v1.x) * 0.5f, v4.y, 0); Vector3[] vlist = new Vector3[4]; vlist[0] = v1; vlist[1] = v2; vlist[2] = v3; vlist[3] = v4; CreateLinePoint(vlist); } }
看看效果:
这样我们可以向数组中加入任意多的点都可以了,像这样:
曲线的应用就是这样,不是很复杂,但是想要使用它做出很多酷炫的效果就要靠大家的想象力了。