无主之地2配置高吗|看真人裸体BBBBB|秋草莓丝瓜黄瓜榴莲色多多|真人強奷112分钟|精品一卡2卡3卡四卡新区|日本成人深夜苍井空|八十年代动画片

網易首頁 > 網易號 > 正文 申請入駐

UE5 Chaos物理|物理查詢的實現

0
分享至


【USparkle專欄】如果你深懷絕技,愛“搞點研究”,樂于分享也博采眾長,我們期待你的加入,讓智慧的火花碰撞交織,讓知識的傳遞生生不息!

這是侑虎科技第1977篇文章,感謝作者南京周潤發供稿。歡迎轉發分享,未經作者授權請勿轉載。如果您有任何獨到的見解或者發現也歡迎聯系我們,一起探討。(QQ群:793972859)

作者主頁:

https://www.zhihu.com/people/xu-chen-71-65

射線檢測接口

游戲業務常見的需求就是做各種射線檢測/Overlap檢測/Sweep檢測,比如Character Movement Component。

下面例子是使用Visibility Channel做Line Trace,StaticMesh對其是Block的。




各種Trace,最終都調用到SceneTrace。


使用的TraceChannel,ObjectType等條件,最終都編碼成四個4B的Word,下面是TraceChannel的例子。


物理查詢,主要就是對AABB Tree的查詢。

SceneTrace

ReadLock

要對物理場景做查詢,首先加讀鎖。可以和其他Trace請求同時執行,但和寫物理場景操作互斥。



然后獲取加速結構Collection,里面有Static AABBTree和Dynamic AABBTree。


最后進到TSpatialAccelerationCollection::RaycastFast。

這里Types就是Buckets,TypeIdx是從0開始的下標,會逐個遍歷Buckets,然后對里面的每個AABBTree,調用RaycastFast函數。


注意第一個Bucket存了非常大的AABB,也就是說如果場景內有很多大的物體,是會拖慢射線檢測效率的。

TAABBTree::QueryImpl

比較大的函數,做AABBTree的遍歷。

AABBTree非葉節點的遍歷

經典的BVH檢測方式,先檢查射線和左右子樹AABB是否相交,然后根據相交情況,不斷對左右子樹做遍歷。加速方式為SIMD的應用,以及非遞歸的遍歷AABBTree。


示意圖如下:


SIMD版本的Slab算法值得一看,判斷射線與AABB是否相交,并計算射線在AABB內經過的距離。全程無if...else...。


里面的VectorMax和VectorSwizzle的組合比較巧妙,用于在三個數中取最大的。

Slab算法簡介

Slab算法(Slab Method)是計算機圖形學和物理引擎中用于檢測射線(Ray)與軸對齊包圍盒(AABB)是否相交的最經典、最高效的算法。

它的核心思想非常簡單直觀:將3D的AABB盒子看作是三組無限大的“平板對”(Slabs)的交集。

假設射線的起點為P,方向為Dir,把射線寫成時間t的方程:


射線進入每個“平板對”,都會有進入時間t0和離開時間t1,如果要與AABB發生重疊,三組t0和t1必定有都重疊的部分。

示意圖如下:


處理葉節點

對于一個Leave節點,射線檢測會執行RaycastFastSimd。


每個Leave節點默認最多有8個Element,它們沒有位置關系,因此要逐個對這些Element做射線檢測了。

對于Leave中的一個Element,計算和射線是否相交,會經過三道判斷。第一道是檢查Shape的AABB和射線是否相交,第二道是檢查Shape的Channel和QueryChannel是否是Overlap或者Block關系,第三道是真正檢查射線和Sphere、Box、凸包等幾何體是否相交。前兩道是輕量的,算BroadPhase,第三道很重,是NarrowPhase。



把Channel Response檢查放到中間也是挺有意思的。按照正常人類思考邏輯,應該是射線碰到一個Geometry后,再判斷這個Geometry對射線Channel響應是Block還是Overlap,但判斷射線和Shape相交的操作比較重,尤其是面對凸包。因此從代碼效率邏輯出發,就變成了不管Shape和射線是否真的相交,先判斷Geometry對Channel的響應,如果是Ignore,就直接不管了。具體做法如下:

第一道,射線和AABB Bounds檢查是否相交。

同樣的,用SIMD判斷射線和AABB是否相交,不再贅述。

第二道,射線檢測用的Channel和Geometry的ResponseChannel & BlockChannel是否有重疊。

ResponseChannel & BlockChannel是兩個int32,本身是每個Geometry的屬性,但AABBTree為了效率,在Payload里都緩存了一份,為UnionQueryFilterData和UnionSimFilterData,CachedUniqueIdx則是所屬UObject的UniqueIdx緩存。

具體的Channel Response過濾方法。

PrePreQueryFilter


首先從Word0中獲取射線檢測使用的Channel,然后檢查Geometry自身的Word1和Word2,分別是BlockingChannel和OverlapChannel,做bit and操作,看是否有交集。


注意這里的函數名是PrePreQueryFilter,說明后面還有PreQueryFilter流程。

射線和各種幾何體相交判斷

第三道,真正的射線和幾何體相交檢測。


PreQueryFilter

幾何檢測前,先執行一些自定義邏輯的Filter做過濾,判斷是否要做對Shape的射線檢測,可以做游戲業務相關的操作。注意到例子中的射線檢測是按照LineTrace BlockChannel做的,但目前OverlapChannel的Shape也還沒被排除,排除操作就是在PreQueryFilter階段做的,實際會調用FCollisionQueryFilterCallback::PreFilterBaseImp函數。

首先對比查詢的Channel,和Shape的OverlapChannel & BlockingChannel,判斷這次查詢是Touch還是Block,稱為CollisionQueryHitType。

如果是LineTraceSingle,那么只關心BlockingChannel,TouchChannel的Shape可以忽略。


查詢的Touch/Block和Shape的ResponseChannel比對通過后,再判斷IgnoreActors和IgnoreComponents是否需要過濾,LineTrace時通常會設置IgnoreActors。


FCollisionQueryFilterCallback::PreFilter檢查通過后,正式進入射線和幾何體相交計算。

世界空間坐標和Geometry局部空間坐標

此時射線的起點和方向都是世界坐標,在檢測前先變換到Geometry的坐標空間,后面計算起來會更加方便。比如對Box檢測時,直接用AABB射線檢測算法即可。


射線和不同幾何體相交計算

這里不僅要判斷是否相交,還要得到射線接觸的位置,初次接觸幾何體的距離,以及接觸點的法線。每個幾何體都實現了Raycast函數,觀察不同幾何體的實現。

TSphere

球形判斷是最簡單的。


令直線起點為P,方向為dir,直線方程為:


設圓心為C,半徑為R,直線和圓相交,需要滿足以下方程:


這是關于t的一元二次方程,用公式求出t即可。

有了時間t,就能快速求出交點坐標和交點法線了。


Tbox

最終執行的AABB,計算開銷比球體高些。


對于三組Slab,都分別計算進出時間t0、t1,然后取交集,得到時間t,再得到交點。法線總是XYZ三個方向,計算t0屬于哪個面即可。


FCapsule


Capsule可以想象成,到線段最短距離為r的點,形成的距離場,線段作為Capsule的軸心。


那么判斷射線和膠囊體是否相交,計算這個軸心線段到射線的最短距離即可,具體計算上,需要找出一對距離最近的點。

真正困難的地方在于,線段上的最近點,位于線段中間。直接貼一個已有算法,核心是找出兩個平面的相交線,理解起來需要點時間,但計算步驟并不多。

參考:

https://johnmayhk.wordpress.com/2012/02/02/shortest-distance-between-two-skew-lines/


如上所示,最短距離就是BD在MN上投影的長度,而MN同時垂直AB和CD,另外ABXCD得到的向量也同時垂直AB和CD,因此MN與(ABXCD)平行。由此可得到最短距離。

有了距離,就能解出兩個點了。

UE也實現了這個算法,封裝于SegmentDistToSegmentSafe函數,主要步驟如下:


當射線與Capsule相交后,還需要進一步求交點和normal。

分兩種情況:

1. 與上下兩個半球相交,normal從球心出發

2. 與中間圓柱體相交,計算圓柱體的normal

FConvex凸包

最復雜,使用了GJK算法,不再展開


和Shape發生碰撞后怎么辦?

當前的Hit類型是ChaosInterface::FLocationHit,先填充Hit的這幾個屬性:


之后再給個機會執行FCollisionQueryFilterCallback::PostFilter,如處理bDiscardInitialOverlaps過濾等。

然后把Time作為Distance記下,表示射線已經打了多遠,對后續Shape做射線檢測時,將從最新的Distance開始,繼續往后打射線。

回到AABB子樹的遍歷,如果要判斷多個子樹,但射線在之前已經Block了,就不用判斷之后的子樹了。


FHitResult的填充

FHitResult展開后有如下屬性,其中大部分在之前射線發生碰撞時已經可以得到,只有黃線畫出的幾個需要看下如何獲取。


PhysMat

命中點的物理材質,物理材質可以理解為類似渲染用的材質,只不過描述的是物體表面的摩擦力、密度等屬性。當前已經有了FaceIndex,而Geometry中記錄了FaceIndex和PhysicsMaterial的對應關系,因此可以得到PhysicsMaterial。


BoneName

命中點所屬骨骼的名稱。

對于示例中的StaticMesh,是沒有骨骼的,因此是None,只有對于SkeletalMesh,這個BoneName才有意義。


觀察SkeletalMesh的PhysicsAsset,多個骨骼上會掛接RigidBody,它們有各自對應的BodySetup,BoneName就存在BodySetup里。射線檢測時,可以根據命中的GeometryParticle獲取到BodyInstance,再獲取到BodySetup,最終得到BoneName。


HitItem & ElementIndex

都屬于一些Extra數據,不太重要。

HitItem是BodyInstance在整個PhysicsAsset中的序號,針對SkeletalMesh的情況。ElementIndex是Trace中Shape在Geometry的Shape數組中下標。對于示例中的StaticMeshComponent,它們都是0。


完整的LineTrace流程如下:


Overlap檢測

第二種碰撞檢測是Overlap檢測,比LineTrace更復雜些,會判斷一個體積內有沒有和其他物體相交。這里以Box碰撞體為例,需要傳入Box的位置和大小,區別于之前的LineTrace使用TraceChannel,這里使用了ObjectTypes,查詢Box范圍內重疊的其他Actor。但對于物理引擎而言,TraceChannel和ObjectTypes本質都是一樣的,都是CollisionChannel。



首先,把查詢的Geometry計算一個AABB包圍盒,傳入AABBTree做BroadPhase的檢測。


AABBTree的左右子樹Overlap

對左右子樹分別做AABB的碰撞檢測。



Leaf節點的處理

TAABBTreeLeafArray.OverlapFast

對Leaf中每個Payload Geometry,同樣先做AABB碰撞檢測。用了SIMD技術,四個Payload為一組。當AABB檢測通過后,依然先執行PrePreFilter,做Channel之類的判斷,再針對具體的Geometry Shape形狀,做Narrow Phase的Overlap檢測。


Shape可以有Sphere、Box、Capsule、凸包等各種幾何形狀,但它們都屬于凸包。要判斷兩個凸包是否Overlap,就要用GJK算法,UE的實現是GJKIntersection函數,自然也是SIMD實現。


GJK算法

關于GJK算法的詳細介紹,可以看這里:

看似簡單的復雜問題,奇怪而優雅的解決方式(GJK算法)

https://www.bilibili.com/video/BV16P4y1q7GZ/?spm_id_from=333.337.search-card.all.click&vd_source=43d3ce94d2854f1bf3d667631d4a0e98

總體過程是不斷通過Support函數,在兩個凸包上找一對點,計算閔可夫斯基差,然后讓形成的三角形包含原點。GJK算法有點復雜,不展開了,但不同Shape的Support函數實現可以看下,具體就是每個Shape的SupportCore函數。


所謂Support函數,就是給定一個方向,找到Shape在這個方向上最遠的一個點,下圖就是兩個例子。

簡單起見只看SupportCore普通版本,SIMD版本思想類似。

TBox

等價于對一個AABB求Support點。不難理解,AABB在某個方向上的最遠點必定是8個頂點之一,因此只要依次判斷三個軸,做三次方向二分即可,2^3 = 8。



TSphere

最簡單,球的中心加上半徑*方向即可。



FCapsule

看似復雜,實則和Sphere一樣簡單。Capsule的Support點必定出現在兩個半球上,因此首先根據Direction方向確定是哪個半球,然后類似Sphere處理即可。



FConvex

需要遍歷所有凸包的頂點,與方向做點乘,找到最遠的點。


這里實現也比較有意思,尋找凸包的Support點,理論上用啟發式的“爬山法”更快,即從上個Support點往后找鄰接點,不用遍歷所有頂點,而且UE是保存了邊的連接關系的:


那為什么不用爬山法?個人猜測是以下幾個原因:

  • 直接遍歷Vertices數組,CPU Cache更友好,在頂點數量不多(也是大部分情況)情況下可能更快。

  • 爬山法需要記錄上一次的Support點序號,但碰撞檢測可能多個線程并行,這樣就需要為每個線程都記錄一份上次的Support點了,實現有點麻煩,而且得保證線程安全。

如果要得到Overlap深度,就要使用GJKPenetration算法, 結合了GJK與EPA,這里不展開了。

Sweep檢測



最復雜的情況,以Box Sweep為示例,會得到Sweep路徑上發生重疊的物體。

BroadPhase

類似Overlap,但把Sweep經過的整個路徑,作為AABB,查詢與左右子樹的碰撞情況。



NarrowPhase

對于Leaf節點中的每個Geometry,同樣經過PrePreFilter,AABB檢測,PreFilter。

對Geometry中每個Shape的Sweep檢測,最后依然使用GJK算法。


如果是TriangleMesh復雜碰撞怎么辦?


首先,Shape就變成了FTriangleMeshImplicitObject,類似Mesh,沒有凸包的限制,可以表示任何形狀。因此,類似GJK這種精妙的幾何碰撞算法都不再適用,只能回歸最原始的三角形相交判斷。


Raycast & Overlap & Sweep

BroadPhase相同,使用AABBTree。

NarrowPhase不使用GJK算法了,而是每個TriangleMesh自己有一個BVH樹,用BVH的碰撞檢測方式。BVH子節點存儲了三角形,在檢測子節點內部碰撞時,采樣逐三角形檢測方式。

比如這個例子,BVH樹有379個節點,模型總共有5760個面,還是非常復雜的。

Tips

綜合上述碰撞檢測流程,可以對物理場景優化做一些指導:

  • 游戲中物體都設置專門的Simple Collision,避免查詢復雜碰撞

  • Shape的碰撞檢測效率排序:Sphere > Capsule > Box >> Convex >>>> Triangle Mesh,盡量用效率高的Shape做近似

  • 避免太長的LineTrace,以及范圍太大的Overlap和Sweep

  • LineTrace查詢的開銷最低,玩法上盡量用它

文末,再次感謝南京周潤發的分享, 作者主頁:https://www.zhihu.com/people/xu-chen-71-65, 如果您有任何獨到的見解或者發現也歡迎聯系我們,一起探討。(QQ群: 793972859 )。

近期精彩回顧



特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相關推薦
熱點推薦
33艘船通過,中巴爆發新爭端,我大使斬釘截鐵,撕毀契約后果自負

33艘船通過,中巴爆發新爭端,我大使斬釘截鐵,撕毀契約后果自負

面包夾知識
2026-06-25 23:11:00
外交部:堅決反對美國同中國臺灣地區開展任何形式的官方往來

外交部:堅決反對美國同中國臺灣地區開展任何形式的官方往來

澎湃新聞
2026-06-25 15:40:26
就是這張圖,劉亦菲讓內娛從水光變“啞光”,全身涂粉時代開啟

就是這張圖,劉亦菲讓內娛從水光變“啞光”,全身涂粉時代開啟

書咚咚
2026-06-25 18:46:30
比國足出線還復雜!韓國隊想晉級有多難?得看幾位亞洲兄弟臉色

比國足出線還復雜!韓國隊想晉級有多難?得看幾位亞洲兄弟臉色

足球大腕
2026-06-25 23:55:54
陳赫帶岳母阿那亞度假,182個頭高又壯很惹眼,倆人處得像親母子

陳赫帶岳母阿那亞度假,182個頭高又壯很惹眼,倆人處得像親母子

八怪娛
2026-06-25 15:30:26
山海關外的比基尼遠征

山海關外的比基尼遠征

中國新聞周刊
2026-06-25 11:51:54
3-0!1-0!瘋狂世界杯:倒數第1逆襲奪第2出線 韓國命懸一線

3-0!1-0!瘋狂世界杯:倒數第1逆襲奪第2出線 韓國命懸一線

葉青足球世界
2026-06-25 11:00:26
國乒抵達美國僅2天,換帥風波再次發酵,劉國梁的話終于有人信了

國乒抵達美國僅2天,換帥風波再次發酵,劉國梁的話終于有人信了

觀察鑒娛
2026-06-25 11:58:29
真漲價了!蘋果正式宣布產品迎來大漲價,漲價幅度巨大

真漲價了!蘋果正式宣布產品迎來大漲價,漲價幅度巨大

XCiOS俱樂部
2026-06-25 21:15:18
女衛生員懷孕咬定是我的,我被開除,5年后我開邁巴赫停在她攤前

女衛生員懷孕咬定是我的,我被開除,5年后我開邁巴赫停在她攤前

千秋文化
2026-06-24 19:59:19
Windows 11里的清理功能已經過剩,你還裝CCleaner圖個啥?

Windows 11里的清理功能已經過剩,你還裝CCleaner圖個啥?

報錯免疫體
2026-06-25 02:38:13
剛結婚就離婚?這次老夫少妻的殘酷,在尹子維身上展現的淋漓盡致

剛結婚就離婚?這次老夫少妻的殘酷,在尹子維身上展現的淋漓盡致

娛說瑜悅
2026-06-25 19:02:52
WTA最新戰報:王欣瑜2-0晉級,中國金花沖擊雙冠王

WTA最新戰報:王欣瑜2-0晉級,中國金花沖擊雙冠王

許穩很機智
2026-06-26 00:36:31
9.4分神劇《父母愛情》2026口碑大翻車!3大爭議內核,遭網友痛批

9.4分神劇《父母愛情》2026口碑大翻車!3大爭議內核,遭網友痛批

露珠聊影視
2026-06-25 22:31:19
《妻旅》格格不入的夫妻:懶、不上道、脾氣大,還沒孫楊這對舒服

《妻旅》格格不入的夫妻:懶、不上道、脾氣大,還沒孫楊這對舒服

一娛三分地
2026-06-25 19:09:02
重磅!曼城簽約23歲英格蘭中場達協議:轉會費1.5億歐 英超歷史第1

重磅!曼城簽約23歲英格蘭中場達協議:轉會費1.5億歐 英超歷史第1

風過鄉
2026-06-26 05:29:48
險被NBA選中!國手王浩然進入國王次輪選秀考察名單 曾打爆哈珀

險被NBA選中!國手王浩然進入國王次輪選秀考察名單 曾打爆哈珀

醉臥浮生
2026-06-25 17:52:47
癌癥是基因注定的,躲也躲不掉?父母得了5種癌,或遺傳給下一代

癌癥是基因注定的,躲也躲不掉?父母得了5種癌,或遺傳給下一代

39健康網
2026-06-25 08:30:42
一場1-0大冷!世界杯已有13隊出線,亞洲至今0隊,韓國意外掉第3

一場1-0大冷!世界杯已有13隊出線,亞洲至今0隊,韓國意外掉第3

侃球熊弟
2026-06-25 10:57:35
鮑鵬山:如果中國真的足夠強大!我們沒必要脆弱到那么害怕批評!

鮑鵬山:如果中國真的足夠強大!我們沒必要脆弱到那么害怕批評!

用冷眼洞悉世界
2026-06-24 00:44:14
2026-06-26 07:20:49
侑虎科技UWA incentive-icons
侑虎科技UWA
游戲/VR性能優化平臺
1590文章數 987關注度
往期回顧 全部

科技要聞

存儲成本壓力山大!蘋果罕見全球提價

頭條要聞

超巴西獨享第1 德國1-2厄瓜多爾時隔12年重返淘汰賽

頭條要聞

超巴西獨享第1 德國1-2厄瓜多爾時隔12年重返淘汰賽

體育要聞

世界杯最動人一吻:我若離世 你就改嫁吧

娛樂要聞

這國產劇太裝了,居然還熱播第一?

財經要聞

又有紙尿褲送檢后被檢測出甲酰胺!

汽車要聞

老板們的新座駕!65萬元起,尊界V800/V680開啟預訂

態度原創

時尚
家居
教育
本地
游戲

女人不管多大年紀,夏天都要準備一兩條過膝裙,舒適又提氣質

家居要聞

綠意盎然 自然之境

教育要聞

山東高考生注意!近800個高考志愿填報咨詢服務站,分兩時段開放 ,免費服務考生

本地新聞

2026世界杯全勤太難?這份保姆級攻略請收好

R星官宣《GTA6》開啟預購!官網現已開放購買入口

無障礙瀏覽 進入關懷版