Tại sao các vật thể xen vào nhau trong bộ giải va chạm đơn giản này?


7

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?

Câu trả lời:


5

Tôi nghĩ vấn đề của bạn đến từ nhiều va chạm.

Xét ba hình cầu A, B & C.

A ngồi đó.

B đánh A. Tốt.

C đánh B. B bị đẩy vào A. Rất tiếc.


Đúng nhưng bây giờ C sẽ điều chỉnh vị trí của nó so với cả A và sau đó là B. Tôi hiểu ý của bạn, nhưng các ví dụ tôi đã thực hiện với 3 hình cầu dường như đã được giải quyết - vì vậy tôi không chắc đó có thực sự là vấn đề không. Ngoài ra, tôi tin rằng phương pháp lặp này chính xác là cách mà hầu hết các mô phỏng vật lý trò chơi giải quyết va chạm. Một lần nữa, tôi có thể sai, tôi không chắc chắn. Có thể giải quyết va chạm một lần theo cách này chỉ ngăn chặn sự thâm nhập nếu bạn sử dụng phát hiện va chạm liên tục.
Olhovsky

Điều này thực sự có thể chính xác là lý do. Brandon đề nghị một cái gì đó tương tự. +1 cho đóng góp hữu ích, cho dù đó là lý do chính xác hay không.
Olhovsky

5

Mã này đang thực hiện va chạm giữa hai quả cầu và di chuyển chúng dựa trên khối lượng và vận tốc của chúng.

Đây là một minh họa thực sự cơ bản để cho thấy tại sao có sự thâm nhập giữa một quả bóng màu xanh và một bức tường màu xanh lá cây.

nhập mô tả hình ảnh ở đây

Trong ví dụ này, tâm của quả bóng cách mép tường 5 feet. Quả bóng đang di chuyển với tốc độ 1 feet mỗi giây và bạn đang chạy với tốc độ khung hình 1 khung hình mỗi giây. Ở khung 4 không có sự thâm nhập, nhưng khung 5 sẽ có sự thâm nhập. Không có cách nào để biết rằng khung 5 sẽ va chạm, vì vậy bạn không thể nói dừng lại khi nó chạm vào tường. Thay vào đó bạn kiểm tra mọi khung hình nếu quả bóng nằm một phần bên trong bức tường. Nếu có, di chuyển nó trở lại theo mức độ thâm nhập và áp dụng tốc độ phản xạ. Đây là cách hầu hết các thuật toán phát hiện va chạm hoạt động. Cách khác là kiểm tra từng khung hình bao xa bạn va chạm theo một hướng nhất định. Vấn đề với đó là bạn cần biết hướng nào để kiểm tra. Điều này sẽ không hoạt động trong tình huống của bạn vì vậy tuyến đường bạn đang đi là đúng.

Hạn chế của phương pháp này là sự bồn chồn mà bạn có thể gặp phải. Khi kịch bản này bảo một quả bóng di chuyển dựa trên va chạm cuối cùng, thì nó có thể đang di chuyển để thâm nhập vào một quả bóng khác, sau đó sẽ đưa quả bóng trở lại để va chạm với quả bóng đầu tiên. Làm cho nó nhảy qua lại. Bạn có thể sửa đổi khối lượng của các đối tượng để giúp với điều này. Điều đó sẽ khiến chúng nhảy lùi nhẹ hơn một chút, hoặc giảm tốc độ va chạm ở nơi đầu tiên.


Trên thực tế, vấn đề không phải là "sự bồn chồn" (sự không ổn định). Tôi ổn với sự không ổn định và có thể sửa lỗi đó sau với ngưỡng điều chỉnh khoảng cách với chi phí chính xác. Vấn đề mà tôi đang gặp phải (tốt, và Microsoft đang gặp phải, vì đó là mã của họ), đó là sự thâm nhập không được giải quyết. Đó là, không chỉ là sự hốt hoảng, mà còn có rất nhiều sự thâm nhập lẫn nhau, mặc dù mã dường như để giải quyết sự thâm nhập. Bất cứ ý tưởng tại sao đó là? Tôi đã bỏ lỡ một cái gì đó trong câu trả lời của bạn? Cảm ơn cho btw đầu vào!
Olhovsky

Ồ, tôi nghĩ rằng bạn đang nói rằng nhiều va chạm không giải quyết chính xác do nhiều quả bóng bị đẩy ra khỏi nhau, tương tự như câu trả lời của Loren - đúng không?
Olhovsky

Phải, đó là sự bồn chồn, cũng khiến họ không va chạm chính xác
brandon

Vâng không thực sự. Không ổn định! = Interpenetration. Các đối tượng có thể jitter (do độ phân giải thâm nhập) mà không xen kẽ. Dù sao +1 :)
Olhovsky

5

Bạn nên đọc trên Danh bạ đầu cơ để biết khi nào sẽ xảy ra va chạm trước khi bạn kết thúc với kiểu thâm nhập này.


+1 cho liên kết tốt đó. Thật ra tôi đã mua một thành viên cho blog của Paul ngày hôm qua vì bài báo đó.
Olhovsky

1

SphereCollisionImplicit () được gọi sau khi các quả cầu đã di chuyển. Chuyển động đó có thể đã kết thúc với sự va chạm và thâm nhập, phương pháp này giải quyết điều đó.

khung bắt đầu:

  1. ở nơi khác trong mã của bạn, vị trí được cập nhật theo vận tốc.

  2. Sau đó, phương thức này được gọi để xem nếu điều đó dẫn đến va chạm / thâm nhập.

  3. nếu vậy, nó phân tách chúng & phản ánh / thay đổi vận tốc của chúng.

  4. khung tiếp theo, các vị trí được cập nhật với vận tốc mới / thay đổi ... goto 1.


Tôi không hiểu những gì bạn đang cố nói. Hiện tại trong mẫu XNA đó, nó thực hiện chính xác những gì viên đạn của bạn nói và việc vẽ các quả bóng xảy ra ngay sau bước 3. Vậy tại sao vẫn có sự xen kẽ? Giống như bạn đã nói, chúng tôi hy vọng bước 3 sẽ tách chúng ra.
Olhovsky

Bước 1 & 4 có thể gây ra sự thâm nhập, bước 3 loại bỏ sự xâm nhập nếu nó xảy ra.
Steve H

Điểm của câu hỏi này là sự thâm nhập không bị loại bỏ hoàn toàn. Xem câu trả lời khác cho lý do tại sao.
Olhovsky

1

Có sự thâm nhập bởi vì mỗi khi thay đổi vị trí và vận tốc của quả bóng, nó cần được kiểm tra để xem nó có va chạm với bất kỳ quả bóng nào khác đã được kiểm tra trước đó trong vòng không. Chẳng hạn, cho 3 quả bóng:

Bắt đầu 1. Bóng #A được kiểm tra đối với Bóng #B, không va chạm

  1. Bóng #A được kiểm tra đối với Bóng #C, không có va chạm

  2. Bóng #B được kiểm tra đối với Bóng #A, không có va chạm

  3. Bóng #B được kiểm tra đối với Bóng #C, phát hiện va chạm !! Bóng #B và #C được di chuyển.

  4. Bóng #C được kiểm tra đối với Bóng #A, không có va chạm

  5. Bóng #C được kiểm tra đối với Bóng #B, không có va chạm

Làm xong

Vì vậy, ... Bước 2 có thể đã chuyển Ball #B thành Ball #A, gây ra sự thâm nhập lẫn nhau.

Để khắc phục, tôi nghĩ rằng bất cứ khi nào một quả bóng được di chuyển, nó cần phải được kiểm tra lại với tất cả các quả bóng khác, bất cứ khi nào nó được di chuyển. Trong trường hợp này, Ball #B va vào Ball #C, Richocheting Ball #B thành Ball #A, richocheting Ball #A thành Ball #C!, Lại đánh Ball #B ....

Có bao nhiêu richochets bạn xử lý trong một khung? Bạn cũng cần phải kiểm tra lại tất cả các bức tường sau mỗi richochet?

Bắt đầu 1. Bóng #A được kiểm tra đối với Bóng #B, không va chạm

  1. Bóng #A được kiểm tra đối với Bóng #C, không có va chạm

  2. Bóng #B được kiểm tra đối với Bóng #A, không có va chạm

  3. Bóng #B được kiểm tra đối với Bóng #C, phát hiện va chạm !! Bóng #B và #C được di chuyển.

  4. Khởi động lại vòng lặp #B và #C ...

  5. Bóng #B được kiểm tra đối với Bóng #A, phát hiện va chạm !! Bóng #B và #A được di chuyển

  6. Khởi động lại vòng lặp #B và #A ...

  7. Bóng #A được kiểm tra đối với Bóng #B, không có va chạm

  8. Bóng #A được kiểm tra đối với Bóng #C, phát hiện va chạm !! Bóng #A và #C được di chuyển

  9. Khởi động lại vòng lặp #A và #C

  10. Bóng #A được kiểm tra đối với Bóng #B, không có va chạm

  11. Bóng #A được kiểm tra đối với Bóng #C, không có va chạm

  12. Bóng #B được kiểm tra đối với Bóng #A, không có va chạm

  13. Bóng #B được kiểm tra đối với Bóng #C, phát hiện va chạm !! Bóng #B và #C được di chuyển

  14. Khởi động lại vòng lặp #B và #C

  15. Bóng #B được kiểm tra đối với Bóng #A, không có va chạm

  16. Bóng #B được kiểm tra đối với Bóng #C, không có va chạm

  17. Bóng #C được kiểm tra đối với Bóng #A, không có va chạm

  18. Bóng #C được kiểm tra đối với Bóng #B, không có va chạm Xong


Thật ra không phải vậy. Va chạm được kiểm tra đối với tất cả các quả bóng khác, vấn đề là theo thứ tự của các kiểm tra (như được đề xuất bởi câu trả lời với dấu kiểm màu xanh lá cây :). Kiểm tra đối với tất cả các quả bóng khác là không đủ.
Olhovsky
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.