二维球碰撞问题:能量不守恒

发布于 2024-10-17 16:17:16 字数 3420 浏览 6 评论 0原文

我正在尝试编写一个简单的物理模拟,其中具有不同半径和质量的球在完美弹性和无摩擦的环境中弹跳。我按照此资源编写了自己的代码: http://www.vobarian.com/collisions/2dcollisions2 .pdf,我还测试了这里的代码:球对球碰撞 - 检测和处理

问题已编辑

在 Rick Goldstein 和 Ralph 的帮助下,我的代码可以正常工作(有一个拼写错误..)。非常感谢你的帮助。然而,我仍然很困惑为什么其他算法不适合我。球沿着正确的方向反弹,但系统的总能量永远不守恒。速度变得越来越快,直到球在屏幕上的静态位置开始闪烁。我实际上想在我的程序中使用这段代码,因为它比我编写的简洁得多。

这是我编写的函数算法(尽管我确实从其他来源获取了第一部分)。它在一个 Bubble 类中:

public void resolveCollision(Bubble b)
{
    // get the minimum translation distance
    Vector2 delta = (position.subtract(b.position));
    float d = delta.getMagnitude();
    // minimum translation distance to push balls apart after intersecting
    Vector2 mtd = delta.multiply(((getRadius() + b.getRadius())-d)/d); 

    // resolve intersection --
    // inverse mass quantities
    float im1 = 1 / getMass(); 
    float im2 = 1 / b.getMass();

    // push-pull them apart based off their mass
    position = position.add(mtd.multiply(im1 / (im1 + im2)));
    b.position = b.position.subtract(mtd.multiply(im2 / (im1 + im2)));

    //get the unit normal and unit tanget vectors
    Vector2 uN = b.position.subtract(this.position).normalize();
    Vector2 uT = new Vector2(-uN.Y, uN.X);

    //project ball 1 & 2 's velocities onto the collision axis
    float v1n = uN.dot(this.velocity);
    float v1t = uT.dot(this.velocity);
    float v2n = uN.dot(b.velocity);
    float v2t = uT.dot(b.velocity);

    //calculate the post collision normal velocities (tangent velocities don't change)
    float v1nPost = (v1n*(this.mass-b.mass) + 2*b.mass*v2n)/(this.mass+b.mass);
    float v2nPost = (v2n*(b.mass-this.mass) + 2*this.mass*v1n)/(this.mass+b.mass);

    //convert scalar velocities to vectors
    Vector2 postV1N = uN.multiply(v1nPost);
    Vector2 postV1T = uT.multiply(v1t);
    Vector2 postV2N = uN.multiply(v2nPost);
    Vector2 postV2T = uT.multiply(v2t);

    //change the balls velocities
    this.velocity = postV1N.add(postV1T);
    b.velocity = postV2N.add(postV2T);
}

这是一个不起作用的类,

public void resolveCollision(Bubble b)
{
    // get the minimum translation distance
    Vector2 delta = (position.subtract(b.position));
    float d = delta.getMagnitude();
    // minimum translation distance to push balls apart after intersecting
    Vector2 mtd = delta.multiply(((getRadius() + b.getRadius())-d)/d); 

    // resolve intersection --
    // inverse mass quantities
    float im1 = 1 / getMass(); 
    float im2 = 1 / b.getMass();

    // push-pull them apart based off their mass
    position = position.add(mtd.multiply(im1 / (im1 + im2)));
    b.position = b.position.subtract(mtd.multiply(im2 / (im1 + im2)));

    // impact speed
    Vector2 v = (this.velocity.subtract(b.velocity));
    float vn = v.dot(mtd.normalize());

    // sphere intersecting but moving away from each other already
    if (vn > 0.0f) return;

    // collision impulse (1f is the coefficient of restitution)
    float i = (-(1.0f + 1f) * vn) / (im1 + im2);
    Vector2 impulse = mtd.multiply(i);

    // change in momentum
    this.velocity = this.velocity.add(impulse.multiply(im1));
    b.velocity = b.velocity.subtract(impulse.multiply(im2));
}

如果您发现任何东西,请告诉我。谢谢

I am trying to write a simple physics simulation where balls with varying radii and masses bounce around in a perfectly elastic and frictionless environment. I wrote my own code following this resource: http://www.vobarian.com/collisions/2dcollisions2.pdf and I also tested the code from here: Ball to Ball Collision - Detection and Handling

QUESTION EDITED

With the help of Rick Goldstein and Ralph, I have gotten my code to work (there was a typo..). Thanks so much for you help. However I am still confused as to why the other algorithm isn't working for me. The balls bounce off in the correct directions, but the total energy of the system is never conserved. The velocities get faster and faster until the balls just start blinking in static positions on the screen. I actually want to use this code in my program, because it is a lot more concise than the one I wrote.

Here is the functional algorithm that I wrote (although I did take the first bit from that other source). Its in a Bubble class:

public void resolveCollision(Bubble b)
{
    // get the minimum translation distance
    Vector2 delta = (position.subtract(b.position));
    float d = delta.getMagnitude();
    // minimum translation distance to push balls apart after intersecting
    Vector2 mtd = delta.multiply(((getRadius() + b.getRadius())-d)/d); 

    // resolve intersection --
    // inverse mass quantities
    float im1 = 1 / getMass(); 
    float im2 = 1 / b.getMass();

    // push-pull them apart based off their mass
    position = position.add(mtd.multiply(im1 / (im1 + im2)));
    b.position = b.position.subtract(mtd.multiply(im2 / (im1 + im2)));

    //get the unit normal and unit tanget vectors
    Vector2 uN = b.position.subtract(this.position).normalize();
    Vector2 uT = new Vector2(-uN.Y, uN.X);

    //project ball 1 & 2 's velocities onto the collision axis
    float v1n = uN.dot(this.velocity);
    float v1t = uT.dot(this.velocity);
    float v2n = uN.dot(b.velocity);
    float v2t = uT.dot(b.velocity);

    //calculate the post collision normal velocities (tangent velocities don't change)
    float v1nPost = (v1n*(this.mass-b.mass) + 2*b.mass*v2n)/(this.mass+b.mass);
    float v2nPost = (v2n*(b.mass-this.mass) + 2*this.mass*v1n)/(this.mass+b.mass);

    //convert scalar velocities to vectors
    Vector2 postV1N = uN.multiply(v1nPost);
    Vector2 postV1T = uT.multiply(v1t);
    Vector2 postV2N = uN.multiply(v2nPost);
    Vector2 postV2T = uT.multiply(v2t);

    //change the balls velocities
    this.velocity = postV1N.add(postV1T);
    b.velocity = postV2N.add(postV2T);
}

And here is the one that doesn't work

public void resolveCollision(Bubble b)
{
    // get the minimum translation distance
    Vector2 delta = (position.subtract(b.position));
    float d = delta.getMagnitude();
    // minimum translation distance to push balls apart after intersecting
    Vector2 mtd = delta.multiply(((getRadius() + b.getRadius())-d)/d); 

    // resolve intersection --
    // inverse mass quantities
    float im1 = 1 / getMass(); 
    float im2 = 1 / b.getMass();

    // push-pull them apart based off their mass
    position = position.add(mtd.multiply(im1 / (im1 + im2)));
    b.position = b.position.subtract(mtd.multiply(im2 / (im1 + im2)));

    // impact speed
    Vector2 v = (this.velocity.subtract(b.velocity));
    float vn = v.dot(mtd.normalize());

    // sphere intersecting but moving away from each other already
    if (vn > 0.0f) return;

    // collision impulse (1f is the coefficient of restitution)
    float i = (-(1.0f + 1f) * vn) / (im1 + im2);
    Vector2 impulse = mtd.multiply(i);

    // change in momentum
    this.velocity = this.velocity.add(impulse.multiply(im1));
    b.velocity = b.velocity.subtract(impulse.multiply(im2));
}

Let me know if you find anything. Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

天暗了我发光 2024-10-24 16:17:16

设置 v1nPost 的行是否有拼写错误?看起来分母应该是 this.mass + b.mass,而不是 this.mass * b.mass

另外,因为您正在计算 thisb 之间的碰撞,所以您是否要检查以确保您不会在 b 之间进行相同的碰撞code> 和 this,从而使碰撞中每个参与气泡的增量加倍?

Is there a typo in the line that sets v1nPost? Looks like the denominator should be this.mass + b.mass, not this.mass * b.mass.

Also, because you're computing a collision between this and b, are you checking to make sure you're not also doing the same collision between b and this, thus doubling the delta applied to each participating bubble in the collision?

山色无中 2024-10-24 16:17:16

我做了第一个猜测: getMass() 返回一个整数(或 int)(而不是浮点数或双精度数)?

如果这是真的,那么您的问题是 1 / getMass() 将产生一个整数值(并且只能为 1 或大多数情况下为 0))。要解决此问题,请将 1 替换为 1.01.0f

因为一般规则很简单:
如果你有一个数学运算(+、-、*、/),如果两个运算都不是浮点数据结构(双精度或浮点),则结果类型将是整数

无论如何:可能会有第二个问题,可能你的计算不够精确。那么你应该使用 double 而不是 float。

I do a first guess: getMass() return an integer(or int) (and not a float or double)?

If this is true, than you problem is that 1 / getMass() will result in an integer value (and can be only 1 or most time 0)). To fix this replace 1 by 1.0 or 1.0f

Because the general rule is simple:
If you have a math operation (+,-,*,/) the resulting type will be integer if none of the both operants is a floating point data structure (double or float)

Anyway: there could be a second problem, may your calcualtion is not precise enougth. Then you should use double instead of float.

因为看清所以看轻 2024-10-24 16:17:16

有一个部分看起来很奇怪:

两个计算:

float v1nPost = (v1n*(this.mass-b.mass) + 2*b.mass*v2n)/(this.mass*b.mass);
float v2nPost = (v2n*(b.mass-this.mass) + 2*this.mass*v1n)/(this.mass+b.mass);

是对称的,除了最后一个操作,第一个是 * 第二个是 +

There is a part that looks strange:

The two calculations:

float v1nPost = (v1n*(this.mass-b.mass) + 2*b.mass*v2n)/(this.mass*b.mass);
float v2nPost = (v2n*(b.mass-this.mass) + 2*this.mass*v1n)/(this.mass+b.mass);

are symmetric, except the last operation, in the first it is * in the second it is +

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文