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

2021-03-31 10:42:19 字數 3209 閱讀 7757

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

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

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

然後通過乙個點乘算出當前質點所受的力在負法線方向的分量,然後用當前的力向量減去這個分量即可,之後再需要乘上乙個這個橢球體的摩擦係數。

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

基於OSG的布料模擬

進來腦海中突然想寫個布料模擬的程式,由於自己在現在是研究生,方向也是計算機圖形方面,所以說覺得實現這個布料模擬還是很容易的。然後就動手做了。剛開始的時候,我並沒有著手寫 而是去查詢些相關的 查詢了 以後,發現布料的模擬也確實簡單,簡述來說就是內力分析,外力分析 風力,空氣阻力等等 然後顯示。當然碰撞...

PhysX 3 2裡的布料模擬 1 基本概念

最近剛好遇到了一些跟physx 3.2裡面布料模擬相關的問題,那就約架不如偶遇,介紹一下physx 3.2中的布料模擬吧。這一篇中,我們先概要的介紹一下physx 3.2中的布料的一些基本概念,後續的文章中再詳細介紹如何建立 控制等問題。提到布料模擬,那麼我們可能會有這麼幾方面的問題 如何定義布料的...

shell的比較運算介紹

shell字串比較 判斷是否為數字 二元比較操作符mylxisegx,比較變數或者比較數字.注意數字與字串的區別.整數比較 eq 等於,如 if a eq b ne 不等於,如 if a ne b gt 大於,如 if a gt b ge 大於等於,如 if a ge b lt 小於,如 if a ...