以下のコードは、ここの Microsoft XNAサンプルからのものです。これは非常に単純なリジッドボディシミュレーションであり、多くの物理的効果(角運動量など)を無視しますが、オブジェクト(球)を押しのけて、互いに貫通しないようにします。
ただし、シミュレーションでは球体が貫通するだけでなく、多数の球体が相互に積み重ねられている場合、小さな球体が大きな球体の内側にほぼ完全に収まります。すべての球が同じ半径と質量を持つようにすると、シミュレーションは適度に実行されます(最小の相互浸透で)。
誰かが相互浸透がある理由を説明できますか?球の位置を移動させるので、相互侵入は不可能のようです。
シミュレーションの各球について、このメソッドは他のすべての球で呼び出されます。
/// <summary>
// Given 2 spheres with velocity, mass and size, evaluate whether
// a collision occured, and if so, excatly where, and move sphere 2
// at the contact point with sphere 1, and generate new velocities.
/// </summary>
private void SphereCollisionImplicit(Sphere sphere1, Sphere sphere2)
{
const float K_ELASTIC = 0.75f;
Vector3 relativepos = sphere2.Position - sphere1.Position;
float distance = relativepos.Length();
float radii = sphere1.Radius + sphere2.Radius;
if (distance >= radii)
{
return; // No collision
}
// Add epsilon to avoid NaN.
distance += 0.000001f;
Vector3 relativeUnit = relativepos * (1.0f / distance);
Vector3 penetration = relativeUnit * (radii - distance);
// Adjust the spheres' relative positions
float mass1 = sphere1.Mass;
float mass2 = sphere2.Mass;
float m_inv = 1.0f / (mass1 + mass2);
float weight1 = mass1 * m_inv; // relative weight of sphere 1
float weight2 = mass2 * m_inv; // relative weight of sphere 2. w1+w2==1.0
sphere1.Position -= weight2 * penetration;
sphere2.Position += weight1 * penetration;
// Adjust the objects’ relative velocities, if they are
// moving toward each other.
//
// Note that we're assuming no friction, or equivalently, no angular momentum.
//
// velocityTotal = velocity of v2 in v1 stationary ref. frame
// get reference frame of common center of mass
Vector3 velocity1 = sphere1.Velocity;
Vector3 velocity2 = sphere2.Velocity;
Vector3 velocityTotal = velocity1 * weight1 + velocity2 * weight2;
Vector3 i2 = (velocity2 - velocityTotal) * mass2;
if (Vector3.Dot(i2, relativeUnit) < 0)
{
// i1+i2 == 0, approx
Vector3 di = Vector3.Dot(i2, relativeUnit) * relativeUnit;
i2 -= di * (K_ELASTIC + 1);
sphere1.Velocity = (-i2) / mass1 + velocityTotal;
sphere2.Velocity = i2 / mass2 + velocityTotal;
}
}
特に、これは次のとおりです。
sphere1.Position -= weight2 * penetration;
sphere2.Position += weight1 * penetration;
相互侵入を完全に禁止する必要がありますが、それはなぜですか?