细说UE的碰撞与检测
序
本文从应用角度分析一下UE的碰撞和检测系统, 模型主要看静态模型即StaticMesh, 骨骼模型涉及到物理资产的使用和编辑, 本文暂不做分析
目录
碰撞类型
每一个参与物理世界的对象都必须配置一个碰撞类型(见下图), 在引擎中这个类型叫ObjectChannel
, 与其翻译成物体通道或者物体类型不如理解为碰撞类型更为确切
这里先要看一下UE默认的类型, 如下图
一般的理解
- WorldStatic: 场景中的静态物体
- WorldDynamic: 场景中的动态物体
- Pawn: 角色(默认包含了外层Capsule和骨骼模型)
- PhysicsBody: 开启物理的物体
- Vehicle: 载具
- Destructible: 可破碎物体
但是这个也只是建议, 很多时候根据项目需求可以视情况变动, 而且一般情况下, 这几个碰撞类型是远远不够的, 那么在哪里添加呢?
找到 ProjectSettings -> Collision -> ObjectChannels -> NewObjectChannel 添加即可, 也可以看下图
通道有数量限制, 自定义的所有Object和TraceChannel总数只能有18个, 系统已经带了7个(5个Object,2个Trace), 也就是自定义加起来最多只有11个
- 预设
下面可以设置预设, 预设非常有用, 可以方便我们给物体设置碰撞的时候直接使用, 毕竟custom还是有点麻烦的, 也不容易维护, 预设可以设定这个碰撞类型对其他类型的响应类型(Responses), 以及通道响应类型
配置预设的时候记得要设置碰撞是否开启, 是否开启物理或者查询
同一种碰撞类型有时候会设置成多种预设, 比如引擎自带的Pawn和ChacterMesh
两者的碰撞类型都是Pawn(还有一个不常用的Spectator也是Pawn), 但是这里的预设Pawn是给角色的Capsule用的, 而后者是给SkeletalMesh用的, 所以ChacterMesh的预设里就把对Pawn的响应设置成了Ignore了
碰撞响应
上面解释了物体的碰撞类型, 那么两个物体之间是怎么来处理这个相互间的碰撞的呢?
我们在编辑模型的碰撞的时候肯定会看到这3个CollisionResponses即碰撞响应类型
- ignore: 忽略
- overlap:重叠
- block: 阻挡
那么如果A对B的响应与B对A的响应不相同怎么办呢?
直接上图
简单总结
- 两者有ignore的那么一定ignore
- 没有ignore的情况那么有overlap一定是overlap
那么然后怎么使用呢?
首先碰撞事件接收方需要开启对应的事件, Overlap默认是开启的, Hit默认关闭
如果这个物体你确定不用参与overlap那么建议关闭这个选项, 开启是有开销的
上面的案例是2个Dynamic类型的物体, 相互间是Block的, 而且开启了Hit事件, 那么为什么没有收到Hit消息?
Hit事件的触发需要参与碰撞的2者中的任意一者开启了物理模拟效果, 当然角色是个例外, 角色的胶囊体也能触发Hit事件
如果是Overlap呢?
我们测试的2个对象改成相互Overlap
在这个情况下, 即使我们开启了接受Hit事件同时开了物理, Hit事件也是没有触发的. 然后两个对象都有BeginOverlap和EndOverlap事件
射线通道和射线检测
在上面也说到 碰撞类型和这个TraceChannel加起来一共能自定义11个, 那么这个TraceChannel又是什么?
这个Trace很容易造成一定歧义,很多新手同学会想当然的理解这个就是射线检测的类型, 这句话也对也不对, 这个确实是为射线准备的, 但是射线检测又不只是用这个TraceChannel.
对于射线检测, 如果简单直白的讲, 可以把TraceChannel和ObjectChannel理解为2个维度
下面用2个简单案例解释
先设定3个碰撞类型, 正方形,菱形和梯形
2个射线通道 四边形和平行四边形
设定3个预设, 已梯形举例
射线检测只接受Block
Overlap基本等价于Ignore
显而易见, 梯形是四边形但是不是平行四边形, 正方形和菱形都是四边形和平行四边形
所以我们把梯形的预设里面对平行四边形设置成Ignore, 对四边形设置成Block
我们选择通道平行四边形
来查询
结果显而易见如上图所示, 射线打到了第一个对平行四边形
Block的菱形
再来一个案例
如图中, 设置5个碰撞类型对应5种动物
3个射线通道对应的是另外的3种维度
我们还是用一样的方式查询四足动物
同学肯定会有疑问了, 猫不是四足动物吗?
因为我们调用射线API的时候勾选了 bTraceComplex(细节请看下面简单和复杂碰撞), 射线从猫的脚中间穿了过去
如果勾选了简单碰撞, 我们再结合看猫的简单碰撞, 结果就正确了
如果是查询爬行动物呢?
直接上结果
下一个问题, 如果我们不想射线打到前面的动物, 直接想打鲸鱼, 但是通过TraceChannel我们没法避开其他动物直接打到鲸鱼
这就要用到我们另外一种射线查询方式了, 也就是通过另外一种维度来查询
如上图, 我们就指定射线只查询碰撞类型:鲸鱼
另外, 这个通过ObjectType来查询的, 这个类型可以是数组, 我们可以用下图这种方式来同时查询多个碰撞类型
简单碰撞和复杂碰撞
前面对猫进行射线的时候已经遇到了这个问题, 那么什么是简单碰撞, 什么是复杂碰撞呢?
这个要进入模型碰撞编辑页面
上图红色框内的选项生成的都是简单碰撞, 复杂碰撞就是我们模型本身的多边形组成的形体(图中浅蓝色)
在右侧编辑栏有一个选项
一般保持默认或者SimpleAndComplex(简单和复杂共存)
简单和复杂碰撞是可以共存的!!!!!!
碰撞编辑
静态模型在导入的时候会有选项是否自动生成碰撞, 自动生成的碰撞对于一般的规则物体还凑合, 但是如果是遇到下图的这种就比较尴尬了
UE静态物体的编辑界面可以直接像控制碰撞体做移动/旋转/缩放编辑, 但是不能调整点线面
可以添加多个, 所以如果有必要也可以放进去很多个Box慢慢的调整
也可以通过引擎的几种不同算法生成碰撞体, 如下图
可以视情况尝试, 但是对于我们这个模型这里都不能提供较为满意的结果
这种情况可以打开ConvexDecomposition工具(默认关闭)
用默认参数点击Apply, 效果如下图, 已经不错了
如果把参数拉满, 则是下图的结果
- 外部软件的碰撞编辑
碰撞体也可以在外部的美术软件中编辑好以后导入到UE, 只需要遵循一个命名规范即可
用Box堆起来的碰撞体, 命名用 UCX_模型名字_序号
这种形式
导入UE的时候要去掉自动生成碰撞, 导进来以后就生成的跟maya中一样的碰撞
这种方式的优势也是有的, 毕竟在maya中编辑模型比UE中是要容易的多
Sweap和其他射线检测(美术同学请跳过)
前面的射线检测都是用Line的形式, UE其实封装了很多种类型的射线检测方式
搜索Trace可以看到下图中的检测方式
cpp中都放在UKismetSystemLibrary
中
可以看到不仅只有通道的选择, 还有各种形状的区别
这里要看一下源码
以LineTrace举例, 蓝图的LineTraceByChannel
在cpp中其实叫 LineTraceSingle
, LineTraceForObjects
叫LineTraceSingleForObjects
两者的实现如下
通过UWorld的中间层接口, 最终调用的都是物理层的接口
1 |
|
所以如果你熟悉UWorld的接口, 也可以自己构造这些参数, 直接用UWorld的接口也是可以的, 好不好用另说, 理论上可以支持同时支持TraceChannel和ObjectChannel的查询, 自己封装即可
使用起来还是Kismet的直观, 也方便
再看各种带形状的Trace
都是构造好一个定义形状的数据结构FCollisionShape
, 然后调用 UWorld::SweepSingleByChannel()
来做Sweap查询的
- 关于Multi和Single
Multi即字面意思多重, 查询会返回所有检测范围内的数据
Overlap检测
我们看物理层的接口就可以看到, 除了上面的射线和带形状的Sweap检测, 实际上还有一种Overlap检测, 到上层接口就是下图
顾名思义, 用Box的形状就检测这个空间的Actor或Components, 这个在做一些空间检查的时候还是蛮有用的
鼠标和触摸射线
如上图, 鼠标和手指触摸直接有封装好的API
其他
其实SetLocation本质上也给物体一个速度做瞬间偏移, 这个也可以打开Sweap检查, 也能收到
关于Custom
对于场景中的对象的碰撞类型是可以使用Custom
来自定义碰撞类型和响应等, 此举一般情况下是解决一些特殊的对象的碰撞检测, 实际情况一般还是推荐使用预设