一提到曲线,很多新手就头疼了,包括我。查了很多资料,终于有个大概的了解。想深入了解曲线原理的,推荐一个链接
之前写了一篇博文,里面用到了曲线插值,这里算是对上篇博文的一个补充
先看一下曲线的效果
在使用NGUI的过程中,发现iTween.cs里面有两个很有用的方法,一个是输入指定路点数组,一个就是曲线的插值算法。今天我们主要就用到这两个方法来实现曲线效果。
1 public static Vector3[] PathControlPointGenerator(Vector3[] path) 2 { 3 Vector3[] suppliedPath; 4 Vector3[] vector3s; 5 6 //create and store path points: 7 suppliedPath = path; 8 9 //populate calculate path;10 int offset = 2;11 vector3s = new Vector3[suppliedPath.Length + offset];12 Array.Copy(suppliedPath, 0, vector3s, 1, suppliedPath.Length);13 14 //populate start and end control points:15 //vector3s[0] = vector3s[1] - vector3s[2];16 vector3s[0] = vector3s[1] + (vector3s[1] - vector3s[2]);17 vector3s[vector3s.Length - 1] = vector3s[vector3s.Length - 2] + (vector3s[vector3s.Length - 2] - vector3s[vector3s.Length - 3]);18 19 //is this a closed, continuous loop? yes? well then so let's make a continuous Catmull-Rom spline!20 if (vector3s[1] == vector3s[vector3s.Length - 2])21 {22 Vector3[] tmpLoopSpline = new Vector3[vector3s.Length];23 Array.Copy(vector3s, tmpLoopSpline, vector3s.Length);24 tmpLoopSpline[0] = tmpLoopSpline[tmpLoopSpline.Length - 3];25 tmpLoopSpline[tmpLoopSpline.Length - 1] = tmpLoopSpline[2];26 vector3s = new Vector3[tmpLoopSpline.Length];27 Array.Copy(tmpLoopSpline, vector3s, tmpLoopSpline.Length);28 }29 30 return (vector3s);31 }32 33 //andeeee from the Unity forum's steller Catmull-Rom class ( http://forum.unity3d.com/viewtopic.php?p=218400#218400 ):34 public static Vector3 Interp(Vector3[] pts, float t)35 {36 int numSections = pts.Length - 3;37 int currPt = Mathf.Min(Mathf.FloorToInt(t * (float)numSections), numSections - 1);38 float u = t * (float)numSections - (float)currPt;39 40 if(currPt == 0)41 {42 int dsd = 0;43 }44 45 Vector3 a = pts[currPt];46 Vector3 b = pts[currPt + 1];47 Vector3 c = pts[currPt + 2];48 Vector3 d = pts[currPt + 3];49 50 return .5f * (51 (-a + 3f * b - 3f * c + d) * (u * u * u)52 + (2f * a - 5f * b + 4f * c - d) * (u * u)53 + (-a + c) * u54 + 2f * b55 );56 }
直接上完整代码,把这个脚本放到相机上,然后在场景中拖几个物件作为路点,就可以实现上面的效果
1 using System; 2 using System.Collections.Generic; 3 using UnityEngine; 4 5 namespace Fish.Study.Curve 6 { 7 ///8 /// 曲线测试 9 /// 10 public class CurveTest : MonoBehaviour 11 { 12 //路点 13 public GameObject[] GameObjectList; 14 //各路点的坐标 15 public ListTransDataList = new List (); 16 17 void Start() 18 { 19 } 20 21 //Gizmos 22 void OnDrawGizmos() 23 { 24 //1个点是不能画出曲线的,2个点实际上是直线 25 if (GameObjectList.Length <= 1) return; 26 27 TransDataList.Clear(); 28 for (int i = 0; i < GameObjectList.Length; ++i) 29 { 30 TransDataList.Add(GameObjectList[i].transform.position); 31 } 32 33 if (TransDataList != null && TransDataList.Count > 1) 34 { 35 DrawPathHelper(TransDataList.ToArray(), Color.red); 36 } 37 } 38 39 public Vector3[] GetCurveData() 40 { 41 if (TransDataList != null && TransDataList.Count > 1) 42 { 43 var v3 = (TransDataList.ToArray()); 44 Vector3[] vector3s = PathControlPointGenerator(v3); 45 return vector3s; 46 } 47 48 return null; 49 } 50 51 //NGUI iTween.cs中的方法,输入路径点 52 public static Vector3[] PathControlPointGenerator(Vector3[] path) 53 { 54 Vector3[] suppliedPath; 55 Vector3[] vector3s; 56 57 //create and store path points: 58 suppliedPath = path; 59 60 //populate calculate path; 61 int offset = 2; 62 vector3s = new Vector3[suppliedPath.Length + offset]; 63 Array.Copy(suppliedPath, 0, vector3s, 1, suppliedPath.Length); 64 65 //populate start and end control points: 66 vector3s[0] = vector3s[1] + (vector3s[1] - vector3s[2]); 67 vector3s[vector3s.Length - 1] = vector3s[vector3s.Length - 2] + (vector3s[vector3s.Length - 2] - vector3s[vector3s.Length - 3]); 68 69 //is this a closed, continuous loop? yes? well then so let's make a continuous Catmull-Rom spline! 70 if (vector3s[1] == vector3s[vector3s.Length - 2]) 71 { 72 Vector3[] tmpLoopSpline = new Vector3[vector3s.Length]; 73 Array.Copy(vector3s, tmpLoopSpline, vector3s.Length); 74 tmpLoopSpline[0] = tmpLoopSpline[tmpLoopSpline.Length - 3]; 75 tmpLoopSpline[tmpLoopSpline.Length - 1] = tmpLoopSpline[2]; 76 vector3s = new Vector3[tmpLoopSpline.Length]; 77 Array.Copy(tmpLoopSpline, vector3s, tmpLoopSpline.Length); 78 } 79 80 return (vector3s); 81 } 82 83 //曲线插值函数 84 public static Vector3 Interp(Vector3[] pts, float t) 85 { 86 int numSections = pts.Length - 3; 87 int currPt = Mathf.Min(Mathf.FloorToInt(t * (float)numSections), numSections - 1); 88 float u = t * (float)numSections - (float)currPt; 89 90 Vector3 a = pts[currPt]; 91 Vector3 b = pts[currPt + 1]; 92 Vector3 c = pts[currPt + 2]; 93 Vector3 d = pts[currPt + 3]; 94 95 return .5f * ( 96 (-a + 3f * b - 3f * c + d) * (u * u * u) 97 + (2f * a - 5f * b + 4f * c - d) * (u * u) 98 + (-a + c) * u 99 + 2f * b100 );101 }102 103 //画曲线104 private void DrawPathHelper(Vector3[] path, Color color)105 {106 Vector3[] vector3s = PathControlPointGenerator(path);107 108 //Line Draw:109 Vector3 prevPt = Interp(vector3s, 0);110 int SmoothAmount = path.Length * 20;111 for (int i = 1; i <= SmoothAmount; i++)112 {113 float pm = (float)i / SmoothAmount;114 Vector3 currPt = Interp(vector3s, pm);115 116 Gizmos.color = color;117 Gizmos.DrawSphere(currPt, 0.2f);118 prevPt = currPt;119 }120 }121 }122 }