【问题标题】:Sphere - sphere collision detection -> reactionSphere - 球体碰撞检测 -> 反应
【发布时间】:2011-03-15 00:33:50
【问题描述】:

我需要制定一个算法来检测两个球体何时发生碰撞,以及碰撞后一个球体的方向。

比方说,想象一下,当您在桌球比赛中打开桌子时,所有的球都“随机”地相互碰撞。

所以,在开始自己编写代码之前,我在想是否已经有这样的实现。

提前谢谢!

Cyas.-

【问题讨论】:

  • 最困难的部分是旋转...
  • 我不关心旋转,我只需要碰撞和“平坦反应”。
  • 方向只是沿着连接中心的线。

标签: algorithm geometry collision-detection collision


【解决方案1】:

碰撞部分很容易。检查球心之间的距离是否小于它们的半径之和。

至于反弹,您需要交换对垂直于球体碰撞的总速度有贡献的速度量。 (假设所有球体的质量相同,不同质量的组合会有所不同)

struct Vec3 {
    double x, y, z;
}

Vec3 minus(const Vec3& v1, const Vec3& v2) {
    Vec3 r;
    r.x = v1.x - v2.x;
    r.y = v1.y - v2.y;
    r.z = v1.z - v2.z;
    return r;
}

double dotProduct(const Vec3& v1, const Vec3& v2) {
    return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}

Vec3 scale(const Vec3& v, double a) {
    Vec3 r;
    r.x = v.x * a;
    r.y = v.y * a;
    r.z = v.z * a;
    return r;
}

Vec3 projectUonV(const Vec3& u, const Vec3& v) {
    Vec3 r;
    r = scale(v, dotProduct(u, v) / dotProduct(v, v));
    return r;
}

int distanceSquared(const Vec3& v1, const Vec3& v2) {
    Vec3 delta = minus(v2, v1);
    return dotProduct(delta, delta);
}

struct Sphere {
    Vec3 position;
    Vec3 velocity;
    int radius;
}

bool doesItCollide(const Sphere& s1, const Sphere& s2) {
    int rSquared = s1.radius + s2.radius;
    rSquared *= rSquared;
    return distanceSquared(s1.position, s2.position) < rSquared;
}

void performCollision(Sphere& s1, Sphere& s2) {
    Vec3 nv1; // new velocity for sphere 1
    Vec3 nv2; // new velocity for sphere 2
    // this can probably be optimised a bit, but it basically swaps the velocity amounts
    // that are perpendicular to the surface of the collistion.
    // If the spheres had different masses, then u would need to scale the amounts of
    // velocities exchanged inversely proportional to their masses.
    nv1 = s1.velocity;
    nv1 += projectUonV(s2.velocity, minus(s2.position, s1.position));
    nv1 -= projectUonV(s1.velocity, minus(s1.position, s2.position));
    nv2 = s2.velocity;
    nv2 += projectUonV(s1.velocity, minus(s2.position, s1.position));
    nv2 -= projectUonV(s2.velocity, minus(s1.position, s2.position));
    s1.velocity = nv1;
    s2.velocity = nv2;
}

编辑:如果您需要更高的精度,那么在发生碰撞时,您应该计算两个碰撞球体向后移动多远,以便它们相互接触,然后触发执行碰撞功能。这样可以确保角度更准确。

【讨论】:

  • 效果很好 - 但我认为有一个问题:我从 10 个球开始(没有重叠),其中只有一个有速度 - 经过一段时间和很多弹跳后,它们都在移动。每隔一段时间,我总结所有速度 (abs(x) + abs(y)) - 如果我一开始是 8,它会迅速增长(这一定违反了守恒定律之一?)但过了一段时间它停止增长,只是在 20 左右波动.. 我很困惑,不确定我是否应该.. (注意:检测到碰撞后,我将第一个球向后移动,以分钟的步长,直到它们不再重叠,然后调用 performCollision )
  • 尝试为每个求和 (sqrt(vx^2 + vy^2))。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-06
  • 2010-09-25
相关资源
最近更新 更多