Mã dưới đây là từ một mẫu Microsoft XNA ở đây . Đây là một mô phỏng cơ thể cứng nhắc đơn giản, bỏ qua nhiều hiệu ứng vật lý (như động lượng góc), nhưng nó cố gắng đẩy các vật thể (hình cầu) ra xa nhau để chúng không xâm nhập lẫn nhau.
Tuy nhiên, mô phỏng cho phép các quả cầu không chỉ xâm nhập mà khi nhiều quả cầu được xếp chồng lên nhau, các quả cầu nhỏ có thể nằm gần như hoàn toàn bên trong các quả cầu lớn hơn. Nếu tôi làm cho tất cả các quả cầu có cùng bán kính và khối lượng, thì mô phỏng thực hiện khá tốt (với sự thâm nhập tối thiểu).
Ai đó có thể giải thích tại sao có bất kỳ sự thâm nhập nào không? Vì nó di chuyển vị trí của các quả cầu, nên có vẻ như không thể thâm nhập vào nhau.
Đối với mỗi hình cầu trong mô phỏng, phương pháp này được gọi trên mọi hình cầu khác.
/// <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;
}
}
Đặc biệt, tôi mặc dù điều này:
sphere1.Position -= weight2 * penetration;
sphere2.Position += weight1 * penetration;
Nên hoàn toàn không cho phép bất kỳ sự thâm nhập nào, tại sao không?