解读Box2D (1)核心入口 void b2World::Step
最近在轉型做游戲,那么閱讀Box2D當然是件必要且愉快的事情。
?
Box2D的源碼地址https://github.com/erincatto/Box2D
Box2D的官網?http://www.box2d.org
?
Paladin的Box2D克隆地址 https://github.com/PaladinDu/Box2D.git
這個克隆目前并沒有新增內容,只是增加了一些中文注釋。
在后續的學習過程中可能會添加一些demo到Testbed中。
?
選擇從void b2World::Step說起是因為Step是Box2D對一個邏輯針的實現。
我想這應該是一個物理引擎核心的代碼了。
了解了Step,你就了解了物理引擎的邏輯結構。
當然Box2D之所以這么優秀,與其背后高超的結構設計,碰撞算法,邏輯優化同樣密不可分。
不過本文旨在在流程上了解Box2D。
將只會對Step進行一定的展開。
首先讓我們看下step的聲明
?
/**@brief 處理一個邏輯幀*@param dt 邏輯幀的時間長度*@param velocityIterations 速度計算迭代次數,*@note 將一個邏輯幀內的速度計算迭代velocityIterations次,迭代的次數越多,碰撞傳導的速度越快*@param positionIterations 位移計算迭代次數*@note 迭代的次數越多,解決剛體重疊的速度越快*/void b2World::Step(float32 dt,int32 velocityIterations,int32 positionIterations);?
b2World::Step 的流程:
1 如果有新的剛體(Fixture)就執行一次基礎碰撞檢測。
這里有兩點需要說明:
1.1 Box2D創建了一個AABB碰撞樹,來對物體的碰撞進行基礎檢測。
1.1.1?先說AABB是什么鬼。
AABB的描述:
1.1.2 再說說AABB碰撞樹是什么鬼
AABB碰撞樹的描述:1.2.3 使用AABB碰撞樹進行初步檢測
使用AABB碰撞樹無疑是為了進行初步篩選,在AABB都無法碰撞的情況下剛體肯定無法碰撞。而且矩形碰撞檢測極其簡單(只需要檢測矩形的右上角是否在B的左下角的左邊或下邊和與B的右上角是否在A的左下角的左邊或下邊)。而在查詢的時候只需要使用剛體的AABB在樹中進行遍歷(剪掉節點AABB與剛體AABB不碰撞的節點及其子節點)就能初步獲取所有可能產生碰撞的剛體。并組成碰撞元素(Contact)。1.2 并不是說沒有新的剛體產生就不進行碰撞處理
由于老的剛體在上一幀的邏輯處理是就已經進行過初步碰撞檢測。所以這里是由于新的剛體沒有處理過所以需要進行一次初步碰撞檢測。2 進行準確碰撞檢測,并對真實碰撞的碰撞元素進行碰撞初始化
在進行準確碰撞檢測時會排除掉一些不活躍的、重復的、無效的碰撞元素。并根據剛體的類型進行碰撞初始化。詳細碰撞實現在 void b2Collide??(b2Manifold* manifold,constb2CircleShape* circleA,constb2Transform& xfA,constb2CircleShape* circleB,constb2Transform& xfB)? ??中。當??為一個剛體類型是,是同類型剛體碰撞否則將形如b2Collide{typeA}And{typeB}。
? ??不同類型的碰撞是有向的不會出現b2CollideTypeAAndTypeB與b2CollideTypeBAndTypeA兩種碰撞。
? ??碰撞初始化的內容主要是記錄碰撞體的發力點(point),以方便后續物理模擬計算。比如說圓與圓碰撞時point并不是交點二十圓心。
? ??碰撞完畢后還會更具條件觸發開始碰撞或者結束碰撞。
值得注意的是,如果一個剛體被標記為傳感器(sensor)的話,他是不會觸發碰撞初始化處理的。需要注意的是,他只會出發開始碰撞和結束碰撞,并不會持續發送碰撞信號。如果一個剛體沒有被標記為傳感器,在發送碰撞時她還會回調
virtual void PreSolve(b2Contact* contact,constb2Manifold* oldManifold)? ? 這個方法本意是允許用戶進行自定義個物理模擬。當然了,你也可以拿來作別的事情。
2.1. 傳感器是什么鬼
傳感器是一種會發送碰撞信號但不進行系統物理碰撞模擬的剛體(你也可以自己模擬碰撞效果)。 傳感器是可以穿過邊界的,他真不會進行任何系統的物理碰撞。所以如果一個傳感器在高速運動。你需要在有需要的時候銷毀它。 當我們要模擬一些技能效果的時候,就可以使用傳感器。當然傳感器并不只是這一個用途,至于其它用途就要看你的想象力了。3 在需要的時候進行物理模擬
Box2D在進行物理模擬(也包括下面的連續物理模擬)時使用到了island減小計算規模。Box2D將大量需要進行模擬的元素分為一個一個的island,然后再進行物理碰撞模擬。3.1 island是什么鬼 ?
island的定義:
? ? 大量的剛體,碰撞事件和連接器被分為多個island后可以有效的降低物理模擬是消耗的計算資源。原因是碰撞的算法復雜度為O(n2)。這也是為什么一個復雜機器我們會將其分為幾個小的模塊進行模擬,而不是使用單個動力驅動并將其組為一個整體。
3.2 連接器又是什么鬼
有的時候我們并不會實現整個物理結構的模擬(比如引擎帶動車輪旋轉),而是選擇在更宏觀的層面進行模擬(引擎運作時輪子就會轉,但實際上兩者之間沒有進行物理聯系),忽略掉這些細節是為了更高速的進行模擬。同樣的,連接器也是為了在較為宏觀的層面對一些看似簡單其實很復雜的物理邏輯進行模擬。 舉個栗子,b2PulleyJoint 滑輪連接器。 如果我們想要使用原始的物理定力進行模擬我們需要怎么做?(這還是在理想狀態進行模擬)? ? 綜上所訴,使用模擬的方式表現某些物理結構會更高效且真實。然后Box2D將這些模擬進行了一些整合,也就成了現在的連接器了。
3.3 物理碰撞模擬的流程
1.將碰撞元素,剛體,鏈接器分為一個個island。 2.進行island內部物理碰撞模擬。 2.1 更新整體的線速度,角速度。主要是環境產生的速度影響,如重力,阻尼,浮力。Box2D中對速度是有限制的。這是為了減輕物理沖突事件發生的概率(比如穿越),速度越快發生的可能性就越高。 2.2 多次迭代 連接器與碰撞元素 對剛體速度產生的影響。迭代次數越多越真實,因為在一個邏輯針的事件 類由于速度在改變實際上可能已經產生很遠的連鎖反應,需要多次迭代計算才可以將影響傳遞過去。 2.3 更具最新的速度更新位移。這里也做了速度限制。 2.4 多次迭代 位置修復,防止物體被擠的連到一起了。迭代次數越多修復效果越好。當然是在沒有空間的地方多次迭代會導致資源浪費。 2.5 出發碰撞元素影響信號。你可以在回調中獲取到碰撞中由速度產生的力(Impulses)。舉個栗子,你可以根據這個值來計算傷害,而不是簡單的使用碰撞給固定傷害。 2.6 標記不活躍剛體。這樣可以減少變化較少的剛體的計算。 3.更行AABB,以及基礎碰撞檢測以方便下一針的處理。 ?4 在需要的時候進行連續物理模擬
4.1 為什么要進行連續物理模擬
我們知道現實世界的時間是連續的。但是物理引擎中的時間確實粒子化的,無論幾秒中計算多少次都無法模擬連續的時間(更何況由于cpu或gpu算力有限,時間1秒進行的計算次數并不多)。這就產生了一個問題,如果一個物體移動速度夠快,在兩次物理模擬計算中間穿越了另一個物體,引擎是無法發現的(一般情況下)。而連續物理模擬就是為了緩解這一問題。4.2. 連續碰撞物理模擬的對象
連續碰撞只會針對標記為bullet的剛體進行處理。4.3 連續碰撞物理模擬的流程
1.?將Bullet 的碰撞元素,連接器分為一個個island。直到再也獲取不到island就會直接結束。 1.1 獲取一個bullet。 1.2 獲取bullet最塊發生的碰撞元素。 1.3 獲取該碰撞元素的兩個剛體小范圍內的碰撞元素(不會連續感染,速度太快了還沒傳遞過去?) 2.進行island內部物理碰撞模擬。 2.1 基本流程與物理模擬相同,區別的是這里只會更新速度,不會更新位移。不用太擔心(在一些極端情況下連續物理模擬還是會失效)在連續碰撞物理模擬前bullet就已經穿越了。實際上連續模擬是提前模擬了下一針的速度影響。 2.2 返回第1個步驟,尋找下一個最快碰撞的碰撞元素。 到此Step就說完啦。 期待下一次更新!!!?
?
?
?
總結
以上是生活随笔為你收集整理的解读Box2D (1)核心入口 void b2World::Step的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: dya19
- 下一篇: Win11勒索软件防护怎么打开?Win1