IT圈老男孩1 发表于 2021-4-22 09:45

unity 中,物体快速移动,可能会导致一帧位移过大从而穿过物体,使得碰撞器检测失效,有什么好办法吗?

unity 中,物体快速移动,可能会导致一帧位移过大从而穿过物体,使得碰撞器检测失效,有什么好办法吗?

yukamu 发表于 2021-4-22 09:46

离散式的碰撞检测中,帧与帧之间是独立的,因此会遇到题主所述的问题,即碰撞体上一个帧没撞上墙,而下一个帧穿过了墙,该物体本身在任意一个帧独立来看都是不知道自己会撞墙的(物理学中管这个叫量子隧穿效应)。
连续式的碰撞检测则可以避免这一点。
原理和题主所述是一样的,就是射线检测法(Ray-casting)。当然额外的计算量也意味着额外的系统负担。

对于Unity引擎而言,是可以直接解决这个问题的。

Unity的Rigidbody里有个Collision Detection的碰撞检测属性。
该属性有三个选项:Discrete(离散), Continuous(连续), Continuous Dynamic(动态连续)。

官方Manual里的解释如下:
Collision DetectionUsed to prevent fast moving objects from passing through other objects without detecting collisions.

- Discrete: Use Discreet collision detection against all other colliders in the scene. Other colliders will use Discreet collision detection when testing for collision against it. Used for normal collisions (This is the default value).

-Continuous: Use Discrete collision detection against dynamic colliders (with a rigidbody) and continuous collision detection against static MeshColliders (without a rigidbody). Rigidbodies set to Continuous Dynamic will use continuous collision detection when testing for collision against this rigidbody. Other rigidbodies will use Discreet Collision detection. Used for objects which the Continuous Dynamic detection needs to collide with. (This has a big impact on physics performance, leave it set to Discrete, if you don’t have issues with collisions of fast objects)

-Continuous Dynamic: Use continuous collision detection against objects set to Continuous and Continuous Dynamic Collision. It will also use continuous collision detection against static MeshColliders (without a rigidbody). For all other colliders it uses discreet collision detection. Used for fast moving objects.Unity - Manual: Rigidbody
其中的Discreet一词应为笔误,实为Discrete(Discreet意为慎重,两者意思相差很大)。整个Manual里没有第二处用到Discreet的地方,也没有任何官方说明提到该词。
翻译过来基本上就是

碰撞检测属性:用于防止快速移动的物体穿过其他物体而不触发碰撞检测。

离散(Discrete):
- 碰撞体在遇到本场景其他碰撞体时使用离散式碰撞检测(Discrete)。
- 其他碰撞体在遇到它时会使用离散式碰撞检测(Discrete)。
- 用于正常碰撞。(这是默认值)

连续(Continuous):
- 碰撞体在遇到其他动态碰撞体(即包含rigidbody)使用离散式碰撞检测(Discrete),在遇到静态MechColliders(即不含rigidbody)时使用连续式碰撞检测(Continuous)。
- 设为动态连续(Continuous Dynamic)的碰撞体在遇到该物体时使用连续式碰撞检测(Continuous), 其他碰撞体在遇到该物体时使用离散式碰撞检测(Discrete)。
- 用于设定被动态连续(Continuous Dynamic)的物体所碰撞的物体。(会影响物理引擎的性能表现。如果你没有快速运动物体的碰撞问题,就乖乖设为离散吧)

动态连续(Continuous Dynamic):
- 碰撞体在遇到其他设为连续(Continuous)或动态连续(Continuous Dynamic)的物体时使用连续式碰撞检测(Continuous)。在遇到静态MeshColliders(即不含rigidbody)时也使用连续式的碰撞检测。遇到其他碰撞体则使用离散式碰撞检测(Discrete)。
- 用于快速运动的物体。

理成一个碰撞检测属性与碰撞检测方式的对应表格就是:

如果你有一个快速运动的小球,它会穿过一个静态的墙,那么将球设为Continuous即可解决问题。
但如果你有多个这样的小球,它们之间则依旧会遇到互相穿过对方的问题,那么将球都设为Continuous Dynamic更好。

所以遇到题主的问题时,将快速运动的物体设为Continuous/Continuous Dynamic即可。

理论上你可以设定所有物体为Continuous Dynamic,然而这样的物体数量一旦增加起来,对性能会有很大的影响。

xiaozongpeng 发表于 2021-4-22 09:56

开启一个属性:
CCD
连接碰撞检测

rustum 发表于 2021-4-22 10:00

原帖:http://www.u3dc.com/archives/1319

关于Unity(rigidbody)碰撞穿透13/09/2015
首先,说说碰撞的条件:1.rigidbody(刚体),一般用在主动移动的物体上,比如角色。2.collider,碰撞器,一般用于受力物体上,比如障碍块。
物理的碰撞当然是基于物理检测计算,而这个计算是消耗cpu和gpu的,那么,碰撞穿透是什么鬼?
发生概率即触发方式:
1.刚体速度足够快,被撞物体的collider足够薄。
2.刚体速度在一定的v,被撞物体也在一定的速度v(被撞物体可移动)。
3.暂时未发现的其他情况。
在分析这两种(3种)情况之前,先了解下一个刚体(rigidbody)属性参数:Collision Detection(碰撞检测):
它有三种选项:Discrete(离散),Continuous(连续),Continuous Dynamic(动态连续),我们参考下官方的解释:

该属性用于控制避免高速运动的游戏对象穿过其他的对象而未发生碰撞,有三项可供选择
Discrete:离散碰撞器。该模式与场景中其他的所有碰撞体进行碰撞检测。该项为默认值。
Continuous:连续碰撞检测。该模式用于检测与动态碰撞体(带有Rididbody)的碰撞,使用连续碰撞检测模式来检测与网格碰撞体(不带ridigbody)碰撞。(添加一句原文翻译漏了),Rigidbody设置为连续动态碰撞检测模式将使用连续碰撞来检测。其他刚体会采用离散碰撞模式。此模式适用于那些需要与采用连续动态检测的对象相碰撞的对象。这对物理性能会有很大影响,如果不需要对快速运动对象进行碰撞检测,就使用离散碰撞检测模式。
Continuous Dynamic:连续动态碰撞检测模式,该模式用于检测与采用连续碰撞撞模式或连续
动态碰撞模式对象的碰撞,也可用于检测没有rigidbody的静态网格碰撞体。对于与之碰撞的其他对象可采用离散碰撞检测。动态连续碰撞检测模式也可用于检测快速运动的游戏物体。
翻译就是这样的理解并不难:后面两项就是为了用来能够检测到快速运动的物体不至于
你的void OnCollisionEnter(Collision hit)函数检测不到,而至于一个为Continuous Dynamic的刚体和一个Discrete的刚体碰撞,前者会使用使用Continous(连续)碰撞,后
者离散碰撞再来总结下:当使用默认的离散式碰撞检测时,如果前一桢时对象在墙这一面,下一桢时对象已到到了墙另一面,那么碰撞检测算法将检测不到碰撞的发生,你可以将该对象的碰撞检测属性设置为Continuous,这时碰撞检测算法将会防止对象穿过所有的静态碰撞体,设置为Continuous Dynamic将还会防止穿过其他也设置为Continuous或者Continuous Dynamic的刚体。
这就很好理解,如果我们的主角在运动中碰到的都是静态collider,那么使用离散检测是可以满足的。如果我们在游戏中,主角将会碰撞到动态的collider,那么检测模式应该选择连续或者连续动态检测。这样可以很好的避免穿透现象。
然后,你以为这样就高枕勿忧了么?在实际的项目中,我们可能会发现,我们刚体上已经选择了连续检测甚至连续动态检测,依旧会有穿透问题,这就是我上面列举的两条(3条),被碰撞体的碰撞器太薄,被碰撞体的速度太快。这样依旧会导致穿透,那么原理是什么?我们知道unity中有fixedupdate,update这些更新方法,而这些更新中,都是有时间间隔更新的,更新的时候是用基础速度*时间,很有可能这个结果计算出来的时候车已经冲过了被碰撞体,就导致了我们的角色穿透,或者卡在被碰撞器的里面。
so,知道了这些,我们在项目中就知道如何规避这些所谓的“bug”了。
by优三帝同学 2015.9.13

yukamu 发表于 2021-4-22 10:09

加大碰撞盒尺寸。
碰撞盒在游戏中是不可见的,加大到一定程度,就不会出现你说的情况了(记得好像是每一帧物体移动的距离小于碰撞盒的尺寸吧,然后还要看你是检测碰撞的帧率)
特殊一点的需求,静态加大碰撞盒不行的,你搞一个脚本,可以根据速度动态控制碰撞盒尺寸应该就Ok了。
当年我写射击游戏,子弹就是这样处理的。

kyuskoj 发表于 2021-4-22 10:13

很久以前,我也碰到了这个问题,后来发现了这个脚本貌似效果还不错,可以参考下。
DontGoThroughThings

不过其他答案说unity5改了,那应该用不着了。

zt3ff3n 发表于 2021-4-22 10:18

我没用过unity
不过这种情况我的解决办法是
根据物体的速度动态更改碰撞盒的长度 速度越快扩大的系数越大
最后就是不知道unity是否能方便的动态修改碰撞盒的尺寸

mastertravels77 发表于 2021-4-22 10:28

如果一个碰撞器对象在一个FixedUpdate中完全通过另一个碰撞器,是不会检测到任何碰撞。可以通过ProgectSettings->Time->FixedTimestep 来增修改解决此问题(0.005-0.01)都行

yukamu 发表于 2021-4-22 10:31

谢谢各位的回答,没有一个水话题的,比百度强多了。以后就这里了。
我也做手机游戏,射击的。直接选连续动态,一点问题都没有。我的unity现在最新版,2017 .1.2

LiteralliJeff 发表于 2021-4-22 10:37

开ccd直接搞定。你提到的办法像样点的物理引擎早就解决了
页: [1] 2
查看完整版本: unity 中,物体快速移动,可能会导致一帧位移过大从而穿过物体,使得碰撞器检测失效,有什么好办法吗?