OpenGL三维小球碰撞实现方法(glm、glfw)
小萌新剛開始學OpenGL,想做一個三維小球碰撞模擬。一開始試了好多寫法,但都有問題,不斷改進,終于完成了,感覺有必要記錄一下。
首先,為了能夠無限添加小球,我采用鏈表結構,并定義了小球結構體,其中包含小球的各個物理屬性。
struct ball {glm::vec3 position; //球心坐標glm::vec3 speed; //速度矢量glm::vec3 color;//可有可無float r; //小球半徑float m; //小球質量struct ball* next; };在渲染循環里面加上p->position += p->speed * deltaTime;實現小球移動。deltatime為渲染的時間間隔。
然后就是簡單的循環,用來篩選發生碰撞的小球。
struct ball* p = head; struct ball* q;while (p != NULL) { q = p->next;while ((q != NULL)) {if ((veclength(p->position - q->position) <= (p->r + q->r))) {}q = q->next;}p = p->next;}接著最關鍵的就是發生碰撞的兩個小球的代碼了。
一開始,我嘗試先在草稿紙上,把碰撞后的速度算出來。然后if他們之間的距離小于半徑之和,就給他們的速度附上碰撞后的值。
然而,當我滿懷期待地運行的時候,發現只有少數小球符合要求,大多數小球剛一碰撞,就直接飛走了。于是我只好回來再看代碼,發現可能是因為重復判定。也就是賦值完速度之后的下一幀,他們可能還沒有分離,這時候又會給速度賦值一次。
于是我添加了一個開關,當兩個球分離之前,只會執行一次碰撞速度賦值。
當我運行的時候又發現,當兩個球未分離的時候,如果有第三個球撞上來,那第一個球和第二個球就會發生重合。這也是不對的。
覺得這個問題過于復雜的我決定另辟蹊徑。想到了一種更接近自然界本質的方法,那就是彈力。小球碰撞速度的改變,終究還是因為他們之間的相互作用力,給了他們加速度。
于是我在小球屬性里面添加了加速度glm::vec3 a,并且在渲染循環里面添加了p->speed += p->a * deltaTime;當小球發生碰撞時,根據質量反比,賦給他們分離的加速度99999.0f/m。
if ((veclength(p->position - q->position) <= (p->r + q->r))) {p->a = glm::normalize(p->position - q->position) * 999999.0f / p->m;q->a = glm::normalize(q->position - p->position) * 999999.0f / q->m;}經過不斷實驗,我發現雖然這樣解決了上述問題,但是又出現了新的問題:
1、當兩個質量較小的球,即使以很慢的速度碰撞,碰撞之后速度會變得很大。
2、當多個小球豎直疊在一起時,會發生嚴重的彈跳。
3、同一個小球無法同時和多個小球同時碰撞
針對上述問題我又進行了改進。
對于問題1、2,是因為當兩個小球分離或者接觸的瞬間,和加速度改變的瞬間有誤差。這是由于小球的移動終究是離散的,不是移動的。于是我想到了把恒力改為隨小球距離變化的保守力。并且當小球剛接觸的時候,這個力得趨于0,并且要隨距離減少快速增加(防止球質量過大時吞球)。于是我選擇了指數函數,A^x^2-1.具體需要自己調試。
對于問題三,是因為一開始加速度用的是=,不能疊加,于是我改成了+=。完美(我覺得)解決了上述問題。
此外,由于自然界不存在完全彈性碰撞,因此我加了一個隨速度阻尼,保證熵增。
最終代碼如下:
void BALLMOVE() {struct ball* p = head;struct ball* q;while (p != NULL) { p->speed += p->a * deltaTime;p->speed += 30.0f * deltaTime * glm::vec3(0, -1, 0);//這是重力加速度p->position += p->speed * deltaTime;q = p->next;p->a = glm::vec3(0, 0, 0);while ((q != NULL)) {if ((veclength(p->position - q->position) <= (p->r + q->r))) {float k = fabs(veclength(p->position - q->position) - (p->r + q->r));float kn = pow(7,k*k)-1;p->a += kn*(glm::normalize(p->position - q->position) * 999999.0f - (p->speed - q->speed) * 100000.0f) / p->m;q->a += kn*(glm::normalize(q->position - p->position) * 999999.0f - (q->speed - p->speed)*100000.0f) / q->m; }q = q->next;}p = p->next;}}將這個函數插入到渲染循環里面,就可以實現小球碰撞啦。
?
總結
以上是生活随笔為你收集整理的OpenGL三维小球碰撞实现方法(glm、glfw)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 东莞钓鱼网
- 下一篇: qt linux 网络聊天室,QT tc