天天看點

遊戲中的數學之各種插值1.線性插值 之在規定時間内位移到指定位置3.附球形插值詳解

目錄

1.線性插值 之在規定時間内位移到指定位置

2.球形插值 實作 聲音pitch 由低變高 模拟汽車聲浪

3.附球形插值詳解

1.線性插值 之在規定時間内位移到指定位置

void Update()
  {
       //需求: 在2s内移動到指定位置
        if (transform.position == Vector3.right * 10)
        {
            Debug.Log(Time.time);
        }
        else
        {
            //p [0-1]
            var p = Time.time / sumTime;

            // 具體公式:  position =v1+(v2-v1)*p
            transform.position = Vector3.Lerp(Vector3.zero, Vector3.right * 10,p );
        }
   }
           

2.球形插值 實作 聲音pitch 由低變高 模拟汽車聲浪

float sumTime = 10;
    float lerpTime = 0f;

    public AudioSource audioA;

    private void Init()
    {
        audioA.pitch = 0.5f;
        audioA.volume = 0.2f;
        s_v3 = new Vector3(audioA.pitch, audioA.volume);
        e_v3 = new Vector3(1.5f, 1f);
    }
    void Update()
    {
        lerpTime += Time.deltaTime;
        var t_update = lerpTime / sumTime;

        if (t_update >= 1)
        {
            lerpTime = 0;
            is_up = !is_up;
        }

        if (is_up)
        {
            //球形插值 實作 聲音pitch 由低變高 
            var newV = Vector3.Slerp(s_v3, e_v3, t_update);
            audioA.pitch = newV.x;
            audioA.volume = newV.y;

            Debug.Log(newV.z);
        }
        else
        {
            //球形插值 實作 聲音pitch 由低變高 
            var newV = Vector3.Slerp(e_v3, s_v3, t_update);
            audioA.pitch = newV.x;
            audioA.volume = newV.y;
        }
    }
           

3.附球形插值詳解

原文位址:http://www.manew.com/thread-43314-1-1.html

防丢失kao'bei

Vector3.Slerp 球形插值詳解

首先上官方的文檔資訊,方面還沒有看過的同學學習。

        static function Vector3 Slerp (Vector3 from, Vector3to, float t)         Description描述(翻譯資訊來自 U_鷹)         Spherically interpolates between two vectors.         球形插值在兩個向量之間。我感覺叫“弧線插值”更直覺一些。         Interpolates from towards to by amount t. The returned vector's magnitude will be interpolated between magnitudesof from and to.

        通過t數值在from和to之間插值。傳回的向量的長度将被插值到from到to的長度之間。

    另外官方API上面還給了一個例子如下 [C#] 純文字檢視 複制代碼

[/font][/size][/align][align=left][size=4][font=宋體]

//在日出和日落之間動畫弧線

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;

}

}

下面進入對這個函數的詳細解釋。

    初識這個函數的同學們對這個函數都不是很了解,既然是球形插值了,那麼為什麼用這個函數的時候卻這麼複雜呢,又要找中心點,又要中心點偏移的弄了半天。其實這是從這個函數的實作方法所決定的。咱們還是上例子來看比較清楚。

首先定義兩個向量 a(2,1,0); b(-2,1,0); 然後咱們以這兩個坐标點和原點來建構一個三角形,如下圖所示:

遊戲中的數學之各種插值1.線性插值 之在規定時間内位移到指定位置3.附球形插值詳解

咱們以a和b兩個向量來做插值,假設分10等份,代碼比較簡單,如下代碼 [C#] 純文字檢視 複制代碼

[/font][/align][align=left][font=宋體]        

for

(

int

i = 1; i < 10; ++i)

{

Vector3 drawVec = Vector3.Slerp(a, b, 0.1f * i);

Debug.DrawLine(Vector3.zero, drawVec, Color.yellow);

}

可以看到咱們并沒有像官方給的例子那樣,做那麼多的操作,效果也是杠杠滴!

遊戲中的數學之各種插值1.線性插值 之在規定時間内位移到指定位置3.附球形插值詳解

但是,你不能被表象所欺騙,這樣的效果雖然可以,但是卻無法控制插值的曲線,也就是那個弧度,雖然你可以調整向量a和向量b的值來調節弧度,比方說a(1,1,0),b(-1,1,0)效果如下,可以看到弧度已經明顯變平很多。

遊戲中的數學之各種插值1.線性插值 之在規定時間内位移到指定位置3.附球形插值詳解

但是我們在實際運用這個函數的時候往往向量a和向量b是固定的,我們想要的是控制這個弧度,那麼怎麼辦呢,其實也就是改變畫這個弧度的中心點位置。上面兩個示意圖上面中心點我們都是用的坐标原點,我們現在想要在不改變a和a的情況下來改變插值的弧度,就隻能自己找出一個中心點,這也就是官方執行個體中求中心點的由來了。 [C#] 純文字檢視 複制代碼

[/font][/align][align=left][font=宋體]        

//弧線的中心

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

}

求出中心點後我們再來畫一個示意圖看看

遊戲中的數學之各種插值1.線性插值 之在規定時間内位移到指定位置3.附球形插值詳解

(至于為什麼要 求出新的中心點到向量a和向量b的vecA和vecB是因為,我們在球形插值的時候要的是兩個vector3,而這個vector3是要向量a和向量b到中心點的向量,如果我們不求出vecA和vecB的話不論你怎麼插值,其實都是從坐标原點進行的插值,你是控制不了插值的弧度的。) 從上面的效果圖我們可以看到插值出來的弧度開始和結束點并不是a、b兩點,而是這兩個點向下的偏移量,而這個偏移量正好是向量conter的負值,是以我們在求出drawVec之後需要對其做修正處理。

在求出drawVec之後加上下面的代碼 [C#] 純文字檢視 複制代碼

drawVec += center;

然後再看效果圖

遊戲中的數學之各種插值1.線性插值 之在規定時間内位移到指定位置3.附球形插值詳解

現在的效果圖就是我們想要的插值效果了,要想控制弧度,隻用調節centor的偏移量就可以了。 比方說我們加上這樣一條center -= new Vector3(0, 2f, 0); 可以看到效果如下

遊戲中的數學之各種插值1.線性插值 之在規定時間内位移到指定位置3.附球形插值詳解

這個弧度是不是就更平了呢。   好,看到現在還沒有睡着的同學們,我隻能說一句你們有福了,下面可是大餐哦。

上面咱們介紹的都是有局限性的,比方說向量a和向量b對于Y軸可是左右對稱的,并且X,Y軸的值也是相等的,這在實際運用中可是非常不常見的,現在咱們對向量a做一個比較小的改動看看,把向量a改為(2,1,0),那麼效果如下所示

遊戲中的數學之各種插值1.線性插值 之在規定時間内位移到指定位置3.附球形插值詳解

哇咔咔,居然還是好好的球形插值啊,哈哈,各位同學别激動,咱們把向量a的Y軸也調整一下看看,把a改為(2,4,0)效果如下圖所示

遊戲中的數學之各種插值1.線性插值 之在規定時間内位移到指定位置3.附球形插值詳解

  哇咔咔。。效果是不是非常明顯啊,說好的球形插值呢?怎麼成了這個樣子!!哈哈,各位同學别着急啊,咱們這個球形插值和核心其實就是center點的位置,隻要我們求的這個center點的位置在a和b連線中心點的垂線上面,那麼就是一個完整的左右對稱的插值了。

下面咱們加入如下代碼 [C#] 純文字檢視 複制代碼

Vector3 centorProject = Vector3.Project(centor, mStart - mEnd); 

// 中心點在兩點之間的投影

centor = Vector3.MoveTowards(centor, centorProject, 1f); 

// 沿着投影方向移動移動距離(距離越大弧度越小)

效果如下所示(中心的垂線和起始兩條線用藍色标示出來了)

遊戲中的數學之各種插值1.線性插值 之在規定時間内位移到指定位置3.附球形插值詳解

是以我們完整的運用Vector3.Slerp的代碼應該是這樣子滴 [C#] 純文字檢視 複制代碼

[/font][/align][align=left][font=宋體]

//在日出和日落之間動畫弧線

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;

}

}

看到這裡各位同學是不是覺得已經掌握了Vector3.Slerp了呢?O(∩_∩)O哈哈~

NONONO!!!!

咱們上面的執行個體還是有局限性滴,誰告訴你了Vector3的Z軸必須是0了?,咱們對a和b的Z軸在做修改。a((2, 4, -1)),b((-1, 1, 2)),看下效果圖

遊戲中的數學之各種插值1.線性插值 之在規定時間内位移到指定位置3.附球形插值詳解

哇咔咔。。是不是又出問題了?還需要改代碼?NO!這是因為我們鎖定了視角方向來看的,看上面的2D 選項是不是已經選擇了啊,哈哈。 那麼既然Z軸有值了我們就不能已平面視角來看了,等我們把2D鎖定給關閉了轉換個視角看看。

遊戲中的數學之各種插值1.線性插值 之在規定時間内位移到指定位置3.附球形插值詳解

這樣看是不是就順眼多了呢?哈哈,至此我們的講解總算結束了,大家可以洗洗了,哈哈。。。   等下!誰說可以睡了?我可沒說哦,難道大家對我說的都這麼信嗎?有句古話說的好啊,盡信書則不如無書。。 [C#] 純文字檢視 複制代碼

centor = Vector3.MoveTowards(centor, centorProject, 1f); 

// 沿着投影方向移動移動距離(距離越大弧度越小)

在這句代碼中我寫了個注釋(距離越大弧度越小)那麼誰能告訴我距離越小會怎麼樣呢?大家是不是覺得距離越小弧度就越大呢?嘿嘿。。這就掉坑裡了吧。     這個距離的小是相對的,盡量是不能小于0.01的,至于為啥是0.01呢,我就試了下0.01和0.001。。。哈哈。。就是這麼不負責。。     如果這個距離小于0.01的話插值的方向就是不可控了,至于為什麼呢?因為過于小的話就是a到b兩點之間的一條線了,垂直于一條線的平面可是海裡去了,誰知道在哪裡呢。是以大家在用的時候切記這點啊,不能過于追求極限導緻結果不可控。還有。。我是不是比較啰嗦啊。。上面我說的是距離啊,是距離,不是值,這個值是可以為負值的啊,負值的話插值的弧線就在這邊了,轉個向而已。  

好了,講解總算是可以結束了。累死我了。。哇咔咔。。 下面是測試源碼,有興趣的同學玩玩吧 [C#] 純文字檢視 複制代碼

[/size][/font][/align][align=left][font=宋體][size=14.0pt]    

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

}

}