## 算法—插值计算（二）——球形插值

### 第一种方式

``````    using UnityEngine;
using System.Collections;

public class MoveCurve : MonoBehaviour {

public GameObject t1;    //开始位置
public GameObject t2;     //结束位置
// Update is called once per frame
void Update () {
//两者中心点
Vector3 center = (t1.transform .position + t2.transform.position) * 0.5f;
center -= new Vector3(0, 1, 0);
Vector3 start = t1.transform.position - center;
Vector3 end = t2.transform.position - center;
//弧形插值
transform.position = Vector3.Slerp(start,end,Time.time);
transform.position += center;
}
}  ``````

### 第二种方式

``````    using UnityEngine;
using System.Collections;

public class ProjectileTest : MonoBehaviour
{
public GameObject target; //要到达的目标

public float speed = 10;  //速度

private float distanceToTarget;   //两者之间的距离
private bool move = true;
void Start()
{
//计算两者之间的距离
distanceToTarget = Vector3.Distance(this.transform.position, target.transform.position);
StartCoroutine(StartShoot());
}

IEnumerator StartShoot()
{

while (move)
{
Vector3 targetPos = target.transform.position;

//让始终它朝着目标
this.transform.LookAt(targetPos);

//计算弧线中的夹角
float angle = Mathf.Min(1, Vector3.Distance(this.transform.position,    targetPos) / distanceToTarget) * 45;
this.transform.rotation = this.transform.rotation *     Quaternion.Euler(Mathf.Clamp(-angle, -42, 42), 0, 0);
float currentDist = Vector3.Distance(this.transform.position, target.transform.position);
if (currentDist < 0.5f)
move = false;

this.transform.Translate(Vector3.forward * Mathf.Min(speed * Time.deltaTime, currentDist));
yield return null;
}
}
} ``````

### 球形插值的函数

static function Vector3 Slerp (Vector3 from, Vector3to, float t)

API例子：

``````using UnityEngine;
using System.Collections;

public class example : MonoBehaviour
{
public Transform sunrise;
public Transform sunset;
void Update()
{
//弧线的中心
Vector3 center = (sunrise.position + sunset.position) * 0.5f;
//向下移动中心，垂直于弧线
center -= new Vector3(0, 1, 0);
//相对于中心在弧线上插值
Vector3 riseRelCenter = sunrise.position - center;
Vector3 setRelCenter = sunset.position - center;
transform.position = Vector3.Slerp(riseRelCenter,setRelCenter, Time.time);
transform.position += center;
}
}``````

``````for (int i = 1; i < 10; ++i)
{
Vector3 drawVec = Vector3.Slerp(a, b, 0.1f * i);
Debug.DrawLine(Vector3.zero, drawVec, Color.yellow);
}``````

``````       //弧线的中心
Vector3 center = (a + b) * 0.5f;
//我们把中心点向下移动中心，垂直于弧线
center -= new Vector3(0, 0.5f, 0);
// 求出新的中心点到向量a和向量b的
Vector3 vecA = a - center;
Vector3 vecB = b - center;
for (int i = 0; i <= 10; ++i)
{
Vector3 drawVec = Vector3.Slerp(vecA, vecB, 0.1f * i);
Debug.DrawLine(center, drawVec, Color.yellow);
}
``````

（至于为什么要 求出新的中心点到向量a和向量b的vecA和vecB是因为，我们在球形插值的时候要的是两个vector3，而这个vector3是要向量a和向量b到中心点的向量，如果我们不求出vecA和vecB的话不论你怎么插值，其实都是从坐标原点进行的插值，你是控制不了插值的弧度的。）

``drawVec += center;``

``````     Vector3 centorProject = Vector3.Project(centor, mStart - mEnd); // 中心点在两点之间的投影
centor = Vector3.MoveTowards(centor, centorProject, 1f); // 沿着投影方向移动移动距离（距离越大弧度越小）
``````

``````using UnityEngine;
using System.Collections;
public class example : MonoBehaviour
{
public Transform sunrise;
public Transform sunset;
void Update()
{
//弧线的中心
Vector3 center = sunrise.position + sunset.position * 0.5f;
Vector3 centorProject = Vector3.Project(centor, sunrise.position - sunset.position); // 中心点在两点之间的投影
centor = Vector3.MoveTowards(centor, centorProject, 1f); // 沿着投影方向移动移动距离（距离越大弧度越小）
//相对于中心在弧线上插值
Vector3 riseRelCenter = sunrise.position - center;
Vector3 setRelCenter = sunset.position - center;
transform.position = Vector3.Slerp(riseRelCenter, setRelCenter, Time.time);
transform.position += center;
}
}``````

a（(2, 4, -1)）,b((-1, 1, 2))，看下效果图：

``    centor = Vector3.MoveTowards(centor, centorProject, 1f); // 沿着投影方向移动移动距离（距离越大弧度越小）``

``````private Vector3 mStart = new Vector3(2, 4, -1);
private Vector3 mEnd = new Vector3(-1, 1, 2);
// Update is called once per frame
private void Update()
{
Debug.DrawLine(new Vector3(-100, 0, 0), new Vector3(100, 0, 0), Color.green);
Debug.DrawLine(new Vector3(0, -100, 0), new Vector3(0, 100, 0), Color.green);
Debug.DrawLine(Vector3.zero, mStart, Color.red);
Debug.DrawLine(Vector3.zero, mEnd, Color.red);
Debug.DrawLine(mStart, mEnd, Color.red);
Vector3 centor = (mStart + mEnd) * 0.5f;
Vector3 centorProject = Vector3.Project(centor, mStart - mEnd); // 中心点在两点之间的投影
centor = Vector3.MoveTowards(centor, centorProject, 1f);        // 沿着投影方向移动移动距离（距离越大弧度越小）
Debug.DrawLine(centor, mStart, Color.blue);
Debug.DrawLine(centor, mEnd, Color.blue);
Debug.Log(string.Format("{0} : {1}", Vector3.Distance(centor, mStart), Vector3.Distance(centor, mEnd)));
for (int i = 1; i < 10; ++i)
{
Vector3 drawVec = Vector3.Slerp(mEnd - centor, mStart - centor, 0.1f * i);
drawVec += centor;
Debug.DrawLine(centor, drawVec, 5 == i ? Color.blue : Color.yellow);
}
}
``````