模擬布料運算之後的心得介紹。

首先,這是一篇牽扯到數學和物理知識的文章,如果您對文中所涉及的公式有所不明白的話,請在邊上擺上一本《高等數學》以及一些物理學常識的知識。

首先來講布,第一個問題是:爲什麼要模擬布的運動?遊戲中很多地方都有布,那麼目前大部分的做法是什麼樣的呢?目前大多數遊戲所採用的方法是對布建立骨骼,然後由美工針對每個動作做不同的布料骨骼動畫,這種做法帶來的弊端就是布料不會隨着周圍環境的變化來變化。比如說,周圍刮來一陣風,或者騎在馬上,披風不能披落在馬背上,等等之類的。而且如果遊戲中動作很多的情況下,針對每個動作都需要做不同的布料骨骼的調整,加大的美工的工作量以及工作複雜度,另外如果披風的骨骼的數目不多的話,還會導致即使是調出來的動作也會產生很不美觀的效果。

OK,羅嗦了一大堆,那麼我們要實現什麼呢?我們要實現一套針對布料的物理系統,要求在沒有風的情況下,布料會受重力的影響,慢慢的飄落,並且在有風刮起來的時候,你的布要能“隨風飄擺”。

下面來看看傳統物理中,布料的模型。根據流體力學來說,布料上每個頂點的力可以用聖維南方程組來求,但是在數學裏面來說,聖維南方程組是沒有精確解的,那麼我們就需來設計一種模型來求該方程的近似解。無數的物理高手,在模擬布的過程中,總結出了兩套經典的模型,一套是“質點-彈簧”模型,另外一套是由微軟中國研究院研究出來的“半鋼體-複雜擺”模型,在我的布料引擎中所用到的是“質點-彈簧”模型,理由是該模型所存在的時間比“半鋼體-複雜擺”模型要久很多,在穩定性,以及效率方面幾乎沒有風險。而如果採用“半鋼體-複雜擺”,這還只是一個實驗品,目前來講還沒有任何的應用,採用這種模型有一定的風險。

那麼我們下面就來詳細看看經典的“質點-彈簧”模型究竟是怎麼樣一回事:
在“質點-彈簧”模型中,任何的流體(柔體)都被分解爲由N個質點,每個質點之間由各種不同方式的彈簧連接着。主要的連接方式有三種,一種是矩形連接法,即每個質點和他的“上下左右”四個點用彈簧進行連接。另外一種是交叉連接法,即每個質點和他的“左上,右下,左下,右下”四個點用彈簧進行連接。最後一種方法叫隔點連接法,既每個質點和他的“左邊的左邊,右邊的右邊,上面的上面和下面的下面”四個點用彈簧體進行連接,這種連接方式主要是用來簡化之後的關於彈簧的彎取應力的計算,一般要和前兩種連接方式混合起來使用。在我的布料運算的DEMO中,我採用了第一中矩形連接法,然後自己精確計算彈簧的彎取應力來實現的。

物理模型選定之後,就需要我們來針對傳送進來的頂點進行編程進行建模,一般的方法是將布料的頂點,按照從左到右,從上到下的順序傳遞進來,然後按照布料的寬度來進行程序上的物理建模。當模型建立好之後,我們就需要每一幀對模型中的每一個質點進行物理運算:
那麼每個質點所受到的力具體該如何算呢?這裏分爲兩步來進行計算,首先是內力,然後是外力:
每個質點都受到由彈簧建立成的模型所帶來的彈簧的拉力,以及彈簧本身的彎取應力。
那麼首先來算彈簧的拉力,首先獲得當前質點在空間中的位置P0,然後獲得和他用彈簧相連的周圍各個質點的位置P1-P5,然後循環計算P1-P5和P0的距離,並用這個距離減去彈簧本身的長度,然後乘以彈簧的虎克係數,就是這個點在這一幀受到的彈簧拉力。

另外來算彈簧的彎取應力,在矩形模型中,則是通過計算“上面質點”和“下面質點”的夾角以及“左邊質點”和“右邊質點”的夾角來乘以一個彎取應係數來獲得一個以當前質點爲圓,兩個質點的距離爲半徑的圓在鄰質點的切線方向的一個力。

到這裏,布料的內力都已經計算完成了,那麼就需要來計算布料所受的外力了。
首先是重力,重力是根據質點的密度(質量)乘以重力加速度的一個值,然後是一個全局的阻力,否則彈簧會不停的彈來彈去沒有個完,注意,這裏的被乘數一定要是上一幀的速度向量,而不是當前的力向量。接下來就是風力,我對風力的處理可以理解爲在質點的法線方向施加的一個力,力的大小跟風力向量以及質點的方向的夾角有關,當夾角爲2*PI的時候,風力達到最大。

至此,質點的內力和外力都計算完畢,那麼接下來如果通過這個力來獲得下一幀的質點的位置呢?首先根據質點的質量和合力的大小來獲得一個帶方向的加速度,這一步只需要將算出來的力乘以1/質點的質量,得到加速度之後,就可以根據vt = v0 + at來計算這一幀的速度向量,隨後將當前質點在空間中的位置加上v * t就是下一幀的質點的位置。

至此,對於布的模擬已經完全搞定了,不用懷疑,就這麼簡單,但是目前所實現的東西還無法應用,爲什麼?很簡單,因爲還沒有做布的碰撞,如果一塊披風在人身上穿過來穿過去的,那麼做不做布還有什麼意義?

對布做精確碰撞檢測?這是不可能的,如果你要這樣做你的遊戲將只有20幀不到的FPS,用AABB包圍盒碰撞?你希望看到一陣風吹過來,你的披風貼在一個正正方方的“人”上面?那麼這裏就提出一個新的概念“橢球包圍體”碰撞。注意,這裏的橢球體是不存在的,只是一個數學模型,並不是由三角型等組成的,這種橢球體可以綁定在人物骨骼上,隨人物骨骼的運動而動,比如說人的頭,就是一個x-y-z軸相等的橢球體,髖骨,盆骨,肩胛骨等都可以比較好的用橢球體體現出來。

橢球體是個很有意思的東西,在做FPS類遊戲的時候,要實現上下樓梯的效果,用橢球包圍體碰撞就是個非常好的方法,而在這裏,不是橢球體跟三角型碰,而是頂點跟橢球體碰。那麼下面來看看究竟如何比較好的描敘,以及來使用一個橢球體:
橢球體用三個向量來進行描敘,一個是橢球體在空間中的中點,另外一個向量是儲存橢球體在x,y,z軸三個方向的半徑的長度,另外一個向量則是指定橢球體的方向,我在DEMO中是以橢球體x軸的方向爲橢球體的方向。

橢球體的方程是:
(x^2 / a^2 + y^2 / b^2 + z^2 / c^2) = 1
那麼相應的碰撞檢測就是將某個頂點的x,y,z三個值帶入方程,看結果是大於1還是小於1,如果小於1則發生了碰撞。那麼發生碰撞之後怎麼辦呢?首先需要把這個頂點強行移動到離橢球體表面最近的點,這一步通過解從橢球體中點,過那個頂點的射線和橢球體方程一起連解,可以獲得那個點,具體的推導這裏就不列出來了,化簡後方程如下:
設:x0,y0,z0爲橢球體中點,x1,y1,z1爲在橢球體內一點:
那麼離它最近的橢球體表面一點爲:
t = sqrt(1 / (sqr((x1-x0)/a) + sqr((y1-y0)/b) + sqr((z1-z0)/c)));
x = x0 + t*(x1-x0);
y = y0 + t*(y1-y0);
z = z0 + t*(z1-z0);
最後,由於整個布料的運算是基於物理模型的,所以並不能直接把它弄到橢球體表面就了事了,應該給它一個在橢球體上這一點的法線方向的支持力。
橢球體的法線的計算在化簡之後爲:
D3DXVECTOR3(sqr((x - x0) / a),sqr((y - y0) / b),sqr((z - z0) / c));
然後通過一個點乘算出當前質點所受的力在負法線方向的分量,然後用當前的力向量減去這個分量即可,之後再需要乘上一個這個橢球體的摩擦係數。

至此,整個布料運算+橢球體碰撞的模型介紹完畢。

發佈了68 篇原創文章 · 獲贊 1 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章