Der folgende Code stammt aus einem Microsoft XNA-Beispiel hier . Dies ist eine recht einfache Starrkörpersimulation, bei der viele physikalische Effekte (z. B. Drehimpuls) ignoriert werden. Es wird jedoch versucht, Objekte (Kugeln) auseinander zu drücken, damit sie sich nicht gegenseitig durchdringen.
Die Simulation ermöglicht jedoch nicht nur das Eindringen von Kugeln, sondern wenn viele Kugeln übereinander gestapelt sind, können sich kleine Kugeln fast vollständig in größeren Kugeln befinden. Wenn ich dafür sorge, dass alle Kugeln den gleichen Radius und die gleiche Masse haben, funktioniert die Simulation recht gut (mit minimaler Durchdringung).
Kann jemand erklären, warum es überhaupt eine gegenseitige Durchdringung gibt? Da es die Positionen der Kugeln bewegt, scheint es, dass eine gegenseitige Durchdringung unmöglich sein sollte.
Für jede Kugel in der Simulation wird diese Methode für jede andere Kugel aufgerufen.
/// <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;
}
}
Insbesondere denke ich, dass dies:
sphere1.Position -= weight2 * penetration;
sphere2.Position += weight1 * penetration;
Sollte eine gegenseitige Durchdringung völlig verboten sein, warum nicht?