日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

OpenGL三维小球碰撞实现方法(glm、glfw)

發布時間:2024/8/1 编程问答 70 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。