在遊戲中,我們進行物理模擬時,如果採用不同的積分法,對於模擬結果會有重大影響。若從數學定義上,難以理解各種數值積分的差異,不妨試著從實際的物理運動來理解,會是不錯的切入方向。

直覺的積分法

遊戲進行物理模擬時,若物體有速度,如何讓物體看來像是在移動?

電腦是逐個影格(Frame)進行繪圖,影格間的時間差與速度的乘積就是位移,加上物體目前位置就是新位置,若影格間的時間差極短,在每個影格不斷地繪製新位置、連續播放影格,就會讓物體看來像是在移動。曾用繪圖API製作簡單動畫的開發者,應該都知道這種方式,那麼這跟積分有何關係?

先來談微分吧!若物體在某時間點的位置以方程式表示,方程式的微分就是導數,代表著某時間點的速度,也就是極小時間內位移的變化量,就這點來看,假設影格間的時間差極短,求得當前影格時物體的速度,就是微分的概念。

反過來說,如果有個速度方程式,其積分函式在某時間點的值,就是將該時間點前每個極短時間的位移量累積起來,繪圖時影格間的極短時間差與速度的乘積是位移,每次影格計算時,持續累計在物體的位置上,就是積分的概念。簡單來說,如果我們曾實作連續播放影格、讓物體看來像是在移動,不知不覺就用到了微積分的概念了。

「只不過是繪製物體移動,扯什麼微積分?」若速度是線性的,過程中不會變化,確實不用扯什麼微分、積分,因為,在每一次的迭代時,用影格時間差與速度來計算位移是直覺做法。問題就在於,這種直覺做法,在速度是非線性時會有問題,像是物體在運動過程中,會受到外力影響而改變速度的方向時,這種方式依舊適用嗎?

例如,行星會持續受到恆星向心力影響,行星的速度(向量)會不斷地改變(方向),這才有了繞著恆星的軌道運動,若想模擬這種運動,在影格間時間差是t,每個影格的向心力是確定可求的情況下,目前影格的行星位置是X,速度向量是V,接下來的行星位置就會是Xn=X+V*t,若目前依向心力得到加速度向量為A,接下來的速度就會是Vn=V+A*t,也就是程式實作時可採用:

Xn=X+V*t
Vn=V+A*t

你會採用這樣直覺的做法嗎?如果答案是YES!很可惜地,你的行星最初不會繞著恆星轉,而是逐漸遠離恆星,因為在某個影格時,方才的做法表示行星以切線方向移動後,這時離恆星比較遠了,基於向心力計算得到加速度就會小一些,用來取得下一次速度的話,朝恆星的速度分量相對會小一些,不斷重複的結果就是:若遠離恆星一段距離後,行星不再受到向心力影響,最後奔向了宇宙的盡頭。

半隱式歐拉積分

現實中的運動是連續的,電腦中的時間是離散的,在每個影格進行的資料計算,其實,就是忽略影格與影格間的連續性,直接「預測」物體下個影格時的狀態。若將每個影格間物體的位置連起來,實際上,會是條折線,只不過,眾多短小的折線,在人眼裡看似曲線罷了。

方才的做法,通常被稱為顯式歐拉積分(Explicit Euler Integration),然而並不適用於非線性的物體運動,想像一下,如果事先不知道這是顆行星,想透過歐拉積分來模擬出路線,模擬結果會讓你以為,這不過是顆湊巧略過恒星旁的巨大隕石。

如果修改一下方才的計算順序,我們先計算出Vn=V+A*t,然後用Vn來計算Xn=X+Vn*t,行星就會在過一陣子之後,穩定繞著恆星轉了。想像一下,行星速度向量就是切線方向,用A來計算Vn,就是將目前速度方向往恆星拉,這表示計算出的Xn會往恒星靠一些,重複地迭代計算後,最後慢慢地穩定為軌道路線。

而上述這樣的做法,一般稱為半隱式歐拉積分(Semi-Implicit Euler Integration),在程式實作上,跟顯式歐拉積分一樣,只需目前物體的位置、速度與加速度,接著,就可以求得物體下一個影格時的狀態,也就是只需簡單的迭代,實作時只需要:

Vn=V+A*t
Xn=X+Vn*t

有些物理引擎採用了半隱式歐拉積分,既然有半隱式,那麼,有沒有隱式呢?有的!它會用下個影格的狀態,例如,以下個影格的加速度An來求得Vn=V+An*t,然後,用Vn來求Xn=X+Vn*t,也就是使用了未來的資訊來調整預測,這能擁有更好的穩定度,然而,因為必須使用到未來的狀態,實作上就複雜許多。

韋爾萊積分

如果只能測得物體的位置X,以及作用於其上的加速度A(從作用力計算而得),該如何預測物體接下來的位置呢?韋爾萊積分(Verlet Integration)可以用來解決這個問題,出發點是將半隱式歐拉積分的Xn=X+Vn*t,使用Vn=V+A*t代入,得到Xn=X+V*t+A*t*t。

問題在於無法得到速度啊?這時,可採用前一次物體位置Xp與目前位置來權充計算一下,也就是V=(X-Xp)/t,得到Xn=X+(X-Xp)+A*t*t,這是一個不涉及速度的式子,只要能記錄先前狀態Xp,在程式實作上也就只需簡單的迭代:

Xn=X+(X-Xp)+A*t*t

有些物理引擎採用了韋爾萊積分,但這並不是為了實作物理引擎而發明的。在1960年,法國物理學家Loup Verlet就將這個積分方式,應用於分子動力學計算,也是其名稱的由來。實際上,在更早、1907年,Carl Størmer就曾用來求磁場中運動粒子的軌跡,因此,也稱為Størmer方法。

因為其計算的特性,對於粒子系統方面的模擬,採用韋爾萊積分的物理引擎就特別適合,擁有與半隱式歐拉積分相同的穩定性,然而全域誤差比較小,想知道誤差部份的細節,我們可以參考〈Are S.I. Euler and Verlet the same thing?〉

不過顯然地,韋爾萊積分的速度落後於目前位置,也就是說,若真要求物體的速度,是用V=(X-Xp)/t來求得,實際上,求得的會是上一個狀態的速度,也就是上一狀態位置Xp,在速度V下經過t時間,才來到目前狀態的位置X。

更多的積分法

半隱式歐拉與韋爾萊是遊戲或物理引擎中常採用的積分法,另外,還有中點法(Midpoint Method),它會先以目前速度預測半個影格後的位置,也就是X+V*t/2,求得該時間與位的速度Vm,接著用X+Vm*t來預測物體下一個位置。

龍格-庫塔(Runge-Kutta)積分的出發點像是中點法,只是分為更多階段,以求得更高的精確度。若對這些積分方式有興趣,可在〈Math for Game Developers〉系列影片,找到講解。

實際上,這些積分法,並不只用在遊戲或物理模擬之中。因為,這些方法的本質,是在基於可確定的資訊預測(或說是模擬)後續的狀態,因此,若我們從數學的定義上難以理解這類積分法,試著改從實際的物理運動來理解,的確會是個不錯的切入方向。

專欄作者

熱門新聞

Advertisement