1. 程式人生 > >UE4物理系統淺析

UE4物理系統淺析

1、概述

UE4(4.16)採用的物理系統為PhysX,版本為3.4。引擎層僅做介面的呼叫。物理以及渲染決定了一個遊戲的美術表現。

2、碰撞體

UE4的碰撞體分為複雜碰撞和簡單碰撞。碰撞體本身的作用就是為了提高碰撞的檢測速度,用相對簡單的包圍盒把原物體包圍起來,進行碰撞檢測。

如果使用複雜碰撞,也就是直接使用場景中物件的頂點以及三角面作為碰撞體的話,在進行碰撞檢測時是非常複雜的。因此使用簡單碰撞來代替複雜碰撞是非常有必要的。

    2.1 碰撞檢測演算法中的圖元

從原理上可以區分為三類:

   1. 軸對齊包圍盒(Axis-Aligned Bounding Box , AABB)

   2. 有向包圍盒(Oriented Bounding Box , OBB)

   3. 離散有向包圍盒(Discrete Oriented Polytope , k-DOP)

它的長寬高三個軸與遊戲內的是一致的,運算速度最快,但缺點是包圍的不嚴密

它的XYZ軸向是可以自定義的,可以相對精確的包圍,運算速度快

k-DOP可以最精確的包圍,但運算速度最慢

   2.2 與PhyX的互動

PhysX中物件的基本單位與UE4中的資料互動通過結構體FBodyInatance來完成,包括頂點資料,位置,物理材質等等。

例如我們要改變一個Actor的位置,我們是在UE4中設定Actor的Location去完成的。實際上是通過了UPrimitiveComponent中的FBodyInstance把位置賦到PxRigidBody中Shape上的Mesh去實現的。

3、碰撞檢測

碰撞檢測是遊戲邏輯的重要組成部分,移動,自動瞄準,邏輯出發等等。

    3.1 碰撞檢測的分類

我們遊戲中主要用到的碰撞檢測(Query Only)分為三類:

    1. Raycast(零大小的射線檢測,即有向線段碰撞檢測)

SingleLineTrace

    2. Sweeps(非零大小的檢測,即掃描體積)

SingleSphereTrace,SingleBoxTrace

   3. Overlaps(空間體積相交檢測)

Raycast:

Sweeps:

Overlaps:

   3.1.1 Charactor的移動

UE4中Charactor的移動並不是物理模擬的,也就是說Charactor並不會受實際的重力,摩擦力以及其他的一些力影響的,而是在邏輯層中首先對Charactor在當前的速度方向上進行一個很短的距離移動,然後通過Sweeps對這個Charactor與場景以及其他物體進行一個自上而下的碰撞檢測,得到碰撞的位置,最後通過一個介面,強行把Charactor挪到這個位置去。

實際上並不是通過PhysX的物理模擬去完成的。

大家有空可以思考一下,為什麼會這樣設計,挺有意思的。

   3.1.2 主動相交檢測與內建相交檢測

主動相交檢測:

例如,如果需要實現類似手雷爆炸造成傷害這類需求,就可使用主動相交檢測

內建相交檢測:

例如,如果需要實現類似陷阱的需求,就可使用內建相交檢測

每次發生位置改變時都會更新Overlaps的資訊

Generate Overlap Events勾選開關後,可以監聽訊息,分為開始相交和結束相交

需要注意的是,這個overlaps的操作是在移動後增加的,會有一些額外的損耗

最後主動相交檢測與內建相交檢測的區別以及注意點在於:

    1.Overlaps介面為主動測試

    2.bGenerateOverlapEvent標記為呼叫Sweeps介面後,UE4底層程式碼主動執行Overlap介面

    3.因為每個骨骼都有一個碰撞盒,所以需要儘量避免開啟SkinMesh碰撞體的bGenerateOverlapEvent。

    3.2 物理通道

首先要說明以點,PhysX中並沒有物理通道這個東西。

上圖就是在UE4中,我們經常接觸的碰撞通道。

在物理檢測中,碰撞通道實際上是PxFilterData中的一組掩碼。物理查詢通過PxSceneQueryFilterCallBack的繼承,也就是說PhysX他提供了一個Query介面給使用者去自定義自己的邏輯,重寫preFilter與posFilter實現了邏輯層的通道邏輯。在UE4中,如果他發現兩者掩碼的與值為1,這時在preFilter中返回一個Ignore的結果,就說明這個物件不是檢測所需要的物件。

所以當我們在物理通道上如果碰到一些瓶頸時,我們就可以通過重寫preFilter與posFilter去實現一些比較特殊的功能,比如說在UE4中的碰撞檢測中有個IngoreActor的功能,他就是通過儲存一個Actor的唯一ID,然後preFilter中去判斷檢測物體的唯一ID是否和儲存的ID是否相同,最後去通過是否需要Ignore。

在物理模擬中,通過增加FPhysSceneShaderInfo的filterShader,實現了物理模擬中的邏輯層的通道邏輯。

4. 物理模擬

物理模擬通過設定SimulatePhysics來開啟或關閉。

一旦開啟物理模擬,也就意味著這個物體的所有運動狀態都交由PhysX物理世界全權控制,它會受到相關的很多力的影響,例如重力,摩擦力,空氣阻力等等。

在UE4中,邏輯層不提供直接的介面來直接控制物理狀態,但可以通過UE4提供的一些介面強行設定一些物理狀態,例如速度。

但是需要注意的是,這樣強行設定之後,Actor的物理就會變得非常奇怪,會有一些意想不到的表現。

所以如果我們使用了物理模擬,我們需要做的,就是把Actor的所有運動狀態交給物理引擎去模擬,而儘量不要自己人為的去控制。(比如一些流體的模擬,以及物體破碎,汽車等載具的模擬)

    4.1 SimulatePhyscis的一些引數

   1. PxRigidDynamicFlag::eKINEMATIC標記:設定為Ture時表示物體作為可以移動、不受外力的物體,否則可以受到重力等其他外力的影響。

    2.  Damping:阻尼,阻尼運動狀態變化的引數,僅當eKINEMATIC為false的時候,即SimulatePhyscis時候生效

    3.  Constrains:物理行為約束,影響物理模擬的結果

需要注意的是,不管有沒有勾選SimulatePhyscis,物體其實都是存在於PhysScene中的。

有一種錯誤的理解是如果沒有勾選SimulatePhyscis,那麼Actor是不和PhysX互動的,這是一個錯誤的理解,而對於PhysX來說,SimulatePhyscis可以理解為只是在PhysX層的一個標記而已,表示這個物體的物理狀態是由邏輯層全權控制還是由物理層全權控制。

Physics下面的所有屬性設定,都是在勾選了SimulatePhyscis的前提下,才生效的。

    4.2 SimulatePhysics的一些介面

    1. 這些介面需要在開啟SimulatePhysics的Component上面呼叫。

    2. Force的效果是持續的,有一定的過程,需要在Tick裡面呼叫。

    3. Impulse的效果是瞬時的,直接改變物體的速度。

    4. Force是通過改變物體的加速度從而改變物體的運動狀態的,有一定的延遲。

    4.3 物理材質

物理材質是描述當前物理體與物理世界互動的相關物理屬性,它本質是一組引數,並不是和渲染相關的材質。

物理材質通過UE4邏輯層傳遞給PhysX來描述物理的一些特質,例如摩擦力,彈力,膨脹係數等等。

實際應用當中,主要用於根據物理材質的表面型別不同,去定製化的表現一些特效以及音效;以及為物理模擬提供引數。

需要注意的是在UE4中不存在物理材質為NULL的情況,在編輯器裡如果不賦值物理材質,則實際存在一個預設的物理材質,不存在沒有物理材質的情況。

5.碰撞檢測與物理模擬的區別

碰撞檢測:

    1.主動或者被動的對場景進行相關的碰撞檢測,返回查詢的結果

    2.通過邏輯層呼叫PhysX的介面raycast,sweep和overlap實現

物理模擬:

1.把物體的運動狀態交由物理系統來全權管理

2.不需要任何的介面呼叫,通過PxScene::simulate對場景進行模擬

區別:

    1.碰撞檢測是靜態的,查詢場景中滿足給定Filter的Shape,處理eSCENE_QUERY_SHAP標記(Query Only)的Shape。像上面介紹的Charactor的移動,並沒有開啟物理模擬,而是通過碰撞檢測去實現的。

    2.物理模擬是動態的,處理eSIMULATION_SHAPE標記的Shape。

    3.碰撞的可控性比較強,而對於物理模擬,如果要改變他的運動狀態,那麼只能通過新增力或衝量,或者是改變物理引數來改變模擬的結果。

    4.雖然不管碰撞檢測還是物理模擬在UE4中看起來都是使用一樣的物理通道,但實際的底層實現是不一樣的,在物理層當中,這兩個是完全沒有任何關係的。

    5.碰撞檢測是UE4與PhysX的PxScene進行互動,而物理模擬是UE4通過FBodyInstance與PhysX的PxRigidBody互動。

最後,是一張UE4物理系統大致的框架圖:

如有不對的地方,歡迎各位大佬留言修正!

感謝