网易首页 > 网易号 > 正文 申请入驻

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.

相关推荐
热点推荐
洗衣机起火烧成残骸,品牌方要求证明是自家的才售后,发票购买记录全丢失,浙江男子凭电机和螺丝钉确定证据:不要赔偿,只要承认是其产品

洗衣机起火烧成残骸,品牌方要求证明是自家的才售后,发票购买记录全丢失,浙江男子凭电机和螺丝钉确定证据:不要赔偿,只要承认是其产品

极目新闻
2026-09-18 12:17:46
举手式睡姿是身体在求救?先别慌,医生把话说清楚了

举手式睡姿是身体在求救?先别慌,医生把话说清楚了

奶凶的小霸王
2026-09-17 15:58:19
杜塞尔多夫乒乓球俱乐部:樊振东确认出战2场德甲主场赛事

杜塞尔多夫乒乓球俱乐部:樊振东确认出战2场德甲主场赛事

鲁中晨报
2026-09-18 15:51:35
27岁结婚,28岁出轨,29,岁遭丈夫杀害,她告诫我们做人不要太贪心

27岁结婚,28岁出轨,29,岁遭丈夫杀害,她告诫我们做人不要太贪心

风月得自难寻
2026-09-19 02:05:56
全红婵蜕变!减肥成功颜值大变,万千网友盼她早日回归跳台

全红婵蜕变!减肥成功颜值大变,万千网友盼她早日回归跳台

大中国
2026-09-18 13:35:33
刷屏!东莞一工厂中秋大礼火了....

刷屏!东莞一工厂中秋大礼火了....

东莞好生活
2026-09-17 15:37:36
日本军事专家:如果中国导弹击沉横须贺美舰,日本全民将奋起一战

日本军事专家:如果中国导弹击沉横须贺美舰,日本全民将奋起一战

墨策史
2026-09-18 21:25:47
医生提醒:这5件事做错了,可能会让你的血压失控,千万要避免

医生提醒:这5件事做错了,可能会让你的血压失控,千万要避免

中医刘瑛大夫
2026-09-18 20:10:05
人民币汇率,重要突破

人民币汇率,重要突破

第一财经资讯
2026-09-18 12:31:51
中国28岁留学生嫖娼16岁日本女高中生,被抓狡辩:为了学日语!

中国28岁留学生嫖娼16岁日本女高中生,被抓狡辩:为了学日语!

圆圆神神神
2025-08-09 21:49:27
一知名商场大型水晶灯突然坠落,致1人重伤!深圳应急调查报告披露,多人被追责

一知名商场大型水晶灯突然坠落,致1人重伤!深圳应急调查报告披露,多人被追责

南方都市报
2026-09-18 22:49:38
现场直击iPhone 18新机发售:线上价格“破发”后,黄牛加价不如前代

现场直击iPhone 18新机发售:线上价格“破发”后,黄牛加价不如前代

第一财经资讯
2026-09-18 12:24:17
徐湖平的判罚下来了,很多人都在讨论“合理合法”

徐湖平的判罚下来了,很多人都在讨论“合理合法”

行者殷涛
2026-09-18 19:51:19
卡死中国EUV光刻机!美专家给对华芯片管制下结论:高度有效

卡死中国EUV光刻机!美专家给对华芯片管制下结论:高度有效

快科技
2026-09-17 12:54:06
以为坐3年牢就能保住赃款?判刑仅是开始!徐湖平案警示:不义之财终究一件都留不住

以为坐3年牢就能保住赃款?判刑仅是开始!徐湖平案警示:不义之财终究一件都留不住

魔都姐姐杂谈
2026-09-18 13:11:50
你还年轻,自然不懂端庄大气的魅力

你还年轻,自然不懂端庄大气的魅力

疾跑的小蜗牛
2026-09-17 19:30:20
商务部新闻发言人就媒体称欧盟希中国自愿限制混动汽车对欧出口答记者问

商务部新闻发言人就媒体称欧盟希中国自愿限制混动汽车对欧出口答记者问

每日经济新闻
2026-09-18 22:20:45
11比1僵持两天,唯一反对票陪审员:我根本没犹豫

11比1僵持两天,唯一反对票陪审员:我根本没犹豫

自愈小日子
2026-09-19 01:48:28
荣耀手机别乱删预装软件!这几个绝对不能动,删错直接报废

荣耀手机别乱删预装软件!这几个绝对不能动,删错直接报废

小柱解说游戏
2026-09-19 01:59:35
和你断联的人,又回来找你,无非有三个目的

和你断联的人,又回来找你,无非有三个目的

叶飞飞情感屋
2026-09-18 19:59:41
2026-09-19 02:59:00
侑虎科技UWA incentive-icons
侑虎科技UWA
游戏/VR性能优化平台
1624文章数 987关注度
往期回顾 全部

科技要闻

直击iPhone 18新机发售:黄牛加价不如前代

头条要闻

俄杜马选举拉夫罗夫"意外"登顶名单 梅德韦杰夫被拿下

头条要闻

俄杜马选举拉夫罗夫"意外"登顶名单 梅德韦杰夫被拿下

体育要闻

好吧,中国男篮辛苦了

娱乐要闻

陈思诚 佟丽娅不想让儿子知道两人离婚

财经要闻

研发0.25亿理财26亿,敷尔佳豪赌三类器械

汽车要闻

纯电/插混双动力+五座/六座双布局 海狮08应该怎么选?

态度原创

时尚
本地
房产
艺术
军事航空

直播|| 私藏几年的小众千元包,这5只越背越香!

本地新闻

中秋逛白塔寺,体验国医妙荟雅集

房产要闻

海口房价,降不动了!

艺术要闻

好色也分段位?这位时尚摄影大师,直接杀进王者局!

军事要闻

中方反对在安理会强推恢复对伊朗制裁

无障碍浏览 进入关怀版