为什么碰撞反应允许反弹的球体最终通过平面
本文关键字:平面 碰撞 许反弹 为什么 | 更新日期: 2023-09-27 18:25:48
我目前正在Unity(C#)中复制一个粒子系统。我将物理添加到每个粒子(由球体表示)中,使其能够从位于原点的平面上反弹。受重力影响,粒子会反弹多次。当反弹变小时,球体开始穿过平面,直到最终落下。重力将持续作用在粒子上。将球体停在平面顶部的正确方法是什么?
到目前为止,我已经包含了我的实现,但代码最终总是允许球体穿过平面。
检测:
public bool SpherePlaneCollisionDetection(Particle part)
{
Vector3 sphereCenter = part.position;
Vector3 planeCenter = Vector3.zero;
Vector3 normal = Vector3.up;
double radius = 0.5;
Vector3 dist1 = (sphereCenter - planeCenter);
float finalDist = Vector3.Dot (dist1, normal);
if (finalDist > radius) {
return false;
} else {
//Debug.Log ("COLLISION HAS OCCURED");
//Debug.Log ("POSITION: " + part.position);
//Debug.Log ("FINAL DIST: " + finalDist);
return true;
}
}
响应:
public void HandlePlaneCollision()
{
for (int i=0; i<Particles.Count; i++) {
//Particle p1temp = Particle[i];
Particle tempParticle = (Particle)Particles[i];
//Particle part = tempParticle.GetComponent<Particle>();
float dampning = 0.8f;
float bounce = -1f;
if(SpherePlaneCollisionDetection(tempParticle))
{
tempParticle.velocity.y *= (bounce*dampning);
tempParticle.velocity.x *= friction;
tempParticle.velocity.z *= friction;
Debug.Log(tempParticle.velocity.y);
Particles[i] = tempParticle;
}
}
}
非常感谢您的帮助。
我不使用Unity,但我之前对物理模拟进行了编码,这种情况通常发生是因为:
-
阻尼+浮动圆误差
是的,你是阻尼的,所以如果你的物体在下降,它会再次反弹(高度
h0
),再次下降,然后再次反弹(深度h1<h0
)。。。所以它以越来越低的振幅振荡,但从不为零。如果你使用的引擎/框架进行了一些性能调整以加快碰撞测试,或者没有以比振荡更高的精度处理碰撞测试,那么它可能会错过边界命中,特别是在只有平面边界而不是体积的情况下,或者如果命中接近边界的顶点。
您可以通过消除我在评论中提到的振幅较低的振荡来避免这种情况,因此:
if (|speed|<some_minimal_safe_speed)
然后将其设置为零以停止反弹,更好的是只保留表面切线速度部分而不是零 -
错误的边界定义
一些边界碰撞测试系统要求以特定的方式定义边界对象,如
- 多边形绕组
- 按轴或某个角度排序
- 按大小排序
- 按命中概率排序
因此,请在文档中检查它,并在需要时更正
-
采样率与模拟速度
您正在采样对象的位置、速度、状态。。。在某些时间间隔内。在碰撞检测时间中,对象通常已经在边界表面以下/之后,但通常不完全(取决于速度和时间间隔)。当
speed*time_interval
足够高时,物体被检测为碰撞,因此其速度被表面反射并阻尼。但由于下一次迭代中的阻尼,位置仍然在边界后面,因此在迭代中,它被处理为正常的边界碰撞和反弹,以错误的方式进行。这种情况发生在较高的速度上,而不是较低的速度上。。。您可以通过将位置设置为表面命中点(如@Imapler所评论的)和/或+表面上的一些增量来防止这种情况