确定使用外力时球体和平面之间的静止接触

mmu*_*phy 9 c++ algorithm physics game-physics

这个问题有一个主要问题,还有一个小问题.我相信我在研究中的任何一个问题都是正确的,但不是两者都有.

对于我的物理循环,我做的第一件事就是对我TotalForce的刚体物体施加一个引力.然后我用我TotalForce和我检查碰撞Velocity.我TotalForce(0, 0, 0)在每次物理循环后重置,虽然我会保留我的velocity.

我熟悉在仅使用速度时在移动球体和静态平面之间进行碰撞检查.但是,如果我还有其他力量velocity,比如重力怎么办?我把其他力量放进去TotalForces(现在我只有引力).为了弥补这一点,当我确定球体当前没有与飞机重叠时,我这样做了

    Vector3 forces = (sphereTotalForces + sphereVelocity);
    Vector3 forcesDT = forces * fElapsedTime;
    float denom = Vec3Dot(&plane->GetNormal(), &forces);
Run Code Online (Sandbox Code Playgroud)

然而,这可能是我认为假设是静止接触的问题.我认为休息接触是通过计算的

denom * dist == 0.0f
Run Code Online (Sandbox Code Playgroud)

哪里dist

float dist = Vec3Dot(&plane->GetNormal(), &spherePosition) - plane->d;
Run Code Online (Sandbox Code Playgroud)

(作为参考,denom * dist > 0.0f球体远离飞机的明显意义)

但是,这永远不会成真.即使看起来有"休息接触".这是由于我forces上面的计算总是至少有-9.8(我的重力).y.当朝向法线为(denom0,1,0 )的平面移动时,将产生-9.8的ay .

我的问题是

1)我是否正确计算了我的前两个代码片段中提到的休息联系方式?

如果是这样,

2)我的"其他力量"如引力如何使用?我使用TotalForces不正确吗?

作为参考,我的时间步长是

  mAcceleration = mTotalForces / mMass;
  mVelocity += mAcceleration * fElapsedTime;
  Vector3 translation = (mVelocity * fElapsedTime);
Run Code Online (Sandbox Code Playgroud)

编辑

由于某些建议的更改似乎会改变我的碰撞代码,因此我会检测碰撞状态

if(fabs(dist) <= sphereRadius)
{ // There already is a collision }
else
{
    Vector3 forces = (sphereTotalForces + sphereVelocity);
    float denom = Vec3Dot(&plane->GetNormal(), &forces);

    // Resting contact
    if(dist == 0) { }
    // Sphere is moving away from plane
    else if(denom * dist > 0.0f) { }
    // There will eventually be a collision
    else
    {
        float fIntersectionTime = (sphereRadius - dist) / denom;
        float r;
        if(dist > 0.0f)
            r = sphereRadius;
        else
            r = -sphereRadius;

        Vector3 collisionPosition = spherePosition + fIntersectionTime * sphereVelocity - r * planeNormal;
    }
}
Run Code Online (Sandbox Code Playgroud)

Jak*_*ake 1

  1. 您应该使用if(fabs(dist) < 0.0001f) { /* collided */ }This is 来计算浮点精度。在大多数角度或接触情况下,您肯定不会得到精确的 0.0f。

  2. 如果为负值dist,则实际上是在物体穿过平面时将物体移回平面表面所需的实际量。sphere.position = sphere.position - plane.Normal * fabs(dist);

  3. 将其移回表面后,您可以选择使其沿平面法线的相反方向反弹;或者只是留在飞机上。

    parallel_vec = Vec3.dot(plane.normal, -sphere.velocity);

    perpendicular_vec = sphere.velocity - parallel_vec;

    bounce_velocity = parallel - perpendicular_vec;

  4. totalforce = external_force + velocity除非所有东西都有单位质量,否则你不能盲目地做。

编辑

  1. 要在 3D 空间中完全定义平面,平面结构应存储平面法向量和平面上的点。http://en.wikipedia.org/wiki/Plane_(几何)。

Vector3 planeToSphere = sphere.point - plane.point;

float dist = Vector3.dot(plane.normal, planeToSphere) - plane.radius;

if(dist < 0) { // collided. }

如果这是你不知道的部分,我建议你先学习更多的数学。

注意:抱歉,格式混乱......我无法将其标记为代码块。

编辑2:根据我对你的代码的理解,你要么错误地命名你的变量,要么正如我之前提到的,你需要修改你的数学和物理理论。这条线没有做任何有用的事情。

float denom = Vec3Dot(&plane->GetNormal(), &forces);

在任何时候,球体上的力可以是任何方向,与行进方向无关。因此 denom 本质上是计算平面方向上的力的大小,但不会告诉您球是否会撞击平面。例如,重力向下,但球可以具有向上的速度并撞击上方的平面。有了这个,你需要Vec3Dot(plane.normal, velocity)改为。

另外,马克·法里斯和格哈德·鲍威尔已经为您提供了线性运动学的物理方程,您可以使用它们直接计算未来的位置、速度和撞击时间。

例如s = 0.5 * (u + v) * t;给出未来时间 t 之后的位移。将该位移与距平面的距离进行比较,即可得知球体是否会撞击平面。所以,我再次建议您先阅读http://en.wikipedia.org/wiki/Linear_motion和简单的内容,然后再阅读http://en.wikipedia.org/wiki/Kinematics

还有另一种方法,如果您期望或假设没有其他力作用在球体上,那么您可以进行射线/平面碰撞测试来找到它撞击平面的时间 t,在这种情况下,请阅读http://en .wikipedia.org/wiki/Line-plane_intersection