Cách nhanh nhất để kiểm tra nếu hai AABB di chuyển giao nhau là gì?


12

Tôi có hai AABB đang di chuyển, cách nhanh nhất để kiểm tra xem chúng có giao nhau dưới khung không?

Bằng cách di chuyển, ý tôi không chỉ là kiểm tra bằng phương pháp giao nhau hình chữ nhật thông thường, ý tôi là một loại thử nghiệm quét đơn giản dễ dàng chỉ trả về một boolean, không có thời gian nhấn hay bất cứ thứ gì khác.

Những gì tôi nghĩ là chỉ đơn giản là làm như thế này:

Điều này

Nhưng hình lục giác đó khá phức tạp và tôi không biết cách tính AABB - Giao điểm đa giác, có cách nào dễ hơn không?

Bất kỳ ngôn ngữ lập trình nào mà bạn thích nhất, tôi có thể dễ dàng chuyển nó.

Cảm ơn.


3
Tôi bối rối. Bạn đặc biệt đề cập đến "thử nghiệm quét", bạn đã thử thử nghiệm quét AABB điển hình chưa? Nó làm chính xác những gì bạn muốn.
SomeWritesReserved

1
Tôi đồng ý với nhận xét ở trên - có gì sai với bài kiểm tra "cổ điển"? Hơn nữa, hầu hết các giải pháp được đề xuất ở đây rõ ràng chậm hơn thế ... cộng với một số trong số chúng có thể cho kết quả sai (không mạnh mẽ).
wonderra

Bạn có thể thử các tách Axis thử nghiệm gamedevelopment.tutsplus.com/tutorials/...
Pharap

Câu trả lời:


8

Sử dụng tổng số Minkowski

Một cách tốt để giải quyết vấn đề này là xem xét giao điểm giữa một đường chuyển động ( v ) được dịch sang gốc ( v ' ) và tổng số Minkowski của A xoay 180 độ tại điểm gốc ( A' ) và các chướng ngại vật của nó (chỉ B trong trường hợp này): A'B .

Trong hình sau đây, tôi đặt một smack-dab trong nguồn gốc của một hệ tọa độ tùy ý. Điều này đơn giản hóa sự hiểu biết khi xoay A 180 độ kết quả trong A 'v được dịch sang gốc bằng v' .

Tổng số Minkowski là hình chữ nhật màu xanh lá cây, và các điểm giao nhau của A di chuyển và B cố định có thể được tìm thấy bằng cách thực hiện giao cắt đường-AABB . Những điểm này được đánh dấu bằng các vòng tròn màu xanh.

Minkowski sum - trường hợp thoái hóa

Trong hình sau đây, một nguồn gốc khác nhau đã được sử dụng và các điểm giao nhau giống nhau được tìm thấy.

Tổng cộng Minkowski - trường hợp tổng quát hơn

Nhiều AABB di chuyển

Để làm cho công việc này cho hai AABB di chuyển theo kiểu tuyến tính trong một khoảng thời gian cụ thể, bạn sẽ trừ vectơ vận tốc của B khỏi vectơ vận tốc của A và sử dụng nó làm đoạn thẳng cho giao điểm AABB.

Mã giả

def normalize(aabb):
    return {x1: min(aabb.x1, aabb.x2), x2: max(aabb.x1, aabb.x2),
            y1: min(aabb.y1, aabb.y2), y2: max(aabb.y1, aabb.y2),

def rotate_about_origin(aabb):
    return normalize({x1: -aabb.x1, x2: -aabb.x2
                      y1: -aabb.y1, y2: -aabb.y2})

# given normalized aabb's
def minkowski_sum(aabb1, aabb2):
    return {x1: aabb1.x1+aabb2.x1, x2: aabb1.x2+aabb2.x2,
            y1: aabb1.y1+aabb2.y1, y2: aabb1.y2+aabb2.y2}

def get_line_segment_from_origin(v):
    return {x1: 0, y1: 0, x2: v.x, y2: v.y}

def moving_objects_with_aabb_intersection(object1, object2):
    A = object1.get_aabb()
    B = object2.get_aabb()

    # get A'⊕B
    rotated_A = rotate_about_origin(A)
    sum_aabb = minkowski_sum(rotated_A, B)

    # get v'
    total_relative_velocity = vector_subtract(object1.get_relative_velocity(), object2.get_relative_velocity())
    line_segment = get_line_segment_from_origin(total_relative_velocity)

    # call your favorite line clipping algorithm
    return line_aabb_intersection(line_segment, sum_aabb)

Phản ứng va chạm

Tùy thuộc vào lối chơi, bạn sẽ thực hiện phát hiện va chạm chi tiết hơn (có thể là AABB có chứa các mắt lưới) hoặc chuyển sang giai đoạn tiếp theo: phản ứng va chạm.

Khi có xung đột, thuật toán giao tuyến AABB sẽ trả về 1 hoặc 2 điểm giao nhau tùy thuộc vào việc A kết thúc chuyển động của nó bên trong B hay đi qua nó, tương ứng. (Đây là chiết khấu cho các trường hợp thoái hóa trong đó A gặm cỏ B dọc theo hai bên hoặc dọc theo một trong các góc tương ứng của chúng.)

Dù bằng cách nào, điểm giao nhau đầu tiên dọc theo đoạn đường là điểm va chạm, bạn dịch nó trở lại vị trí chính xác trong hệ tọa độ thế giới (vòng tròn màu xanh nhạt đầu tiên trong hình thứ hai dọc theo v gốc , gọi nó là p ) và sau đó quyết định (ví dụ: đối với va chạm đàn hồi bằng cách phản xạ v dọc theo va chạm bình thường tại p ) vị trí thực tế của A ở cuối khung sẽ là ( At + 1 ).

Phản ứng va chạm

Nếu có nhiều hơn chỉ 2 máy va chạm thì điều này sẽ phức tạp hơn một chút, vì bạn muốn thực hiện phát hiện va chạm cho lần thứ hai, được phản ánh, một phần của v .


Cảm ơn, thú vị nhất. Bạn có thể giải thích làm thế nào để bạn xử lý trường hợp khi A và B giao nhau trong quá trình di chuyển, nhưng kết thúc việc di chuyển mà không giao nhau?
Nhà hóa học trò chơi

@GameAlchemist Đó sẽ là phản ứng va chạm và không phát hiện va chạm quá nhiều (chủ đề ban đầu của câu hỏi). Nhưng tôi thích Paint, vì vậy hãy kiểm tra chỉnh sửa. :-)
Eric

Cảm ơn đã cập nhật (và vượt qua các kế hoạch :-)), đây không phải là câu hỏi của tôi nhưng đã giúp tôi hiểu rằng thuật toán của bạn đã xử lý trường hợp khi A hoàn toàn vượt qua B.
GameAlchemist

5

OBB - Hộp giới hạn định hướng. Đây là một hướng dẫn

Thực tế, một hộp giới hạn được căn chỉnh với vectơ Vận tốc của đối tượng A là trục y (lên). Chiều rộng và chiều cao của nó có thể được tính bằng điểm bắt đầu và điểm kết thúc của đối tượng A. Sau đó, bạn so sánh điều này với AABB của đối tượng B (coi nó là OOBB) và vàng của bạn.

Nếu bạn chỉ đang tìm kiếm một thử nghiệm giao cắt nhanh để xem NẾU họ CÓ THỂ giao nhau, bạn có thể tạo AABB bao quanh AABB của đối tượng A ở cả vị trí bắt đầu và kết thúc. Nếu một AABB không giao nhau với tất cả AABB này, thì không có giao lộ; Tuy nhiên, điều này có thể dẫn đến dương tính giả, vì vậy bạn chỉ nên sử dụng nó như một thử nghiệm sơ bộ.


4

Bạn không cần OOB và bạn không cần sử dụng phát hiện va chạm theo thời gian. Chỉ cần sử dụng thử nghiệm quét AABB bình thường, xem liên kết này . Về bản chất, nó thực hiện chính xác những gì bạn có trong sơ đồ của mình: AABB di chuyển bị "quét" từ điểm bắt đầu đến điểm kết thúc và sau đó được sử dụng để phát hiện va chạm với các AABB tĩnh khác.

Nếu bạn lo lắng rằng thử nghiệm quét này đắt hơn vì nó trả về "thời gian tác động", tôi nghĩ bạn sẽ tối ưu hóa sớm.

Thông tin sâu hơn về các bài kiểm tra quét có thể được tìm thấy trong cuốn sách tuyệt vời: Phát hiện va chạm thời gian thực của Christer Ericson.


3

AABB điểm yếu gần đúng trường hợp cạnh

Trước tiên, bạn sẽ cần phân tách chuyển động thành các bước nhỏ hơn và sử dụng thông tin đó để tính toán AABB cấp cao. Nếu giao điểm của AABB lớn, thì bạn có thể kiểm tra các bước nhỏ hơn để chính xác hơn.

Ước tính liệu có thể có va chạm hay không bằng cách kiểm tra AABB (hoặc OOBB) chỉ bằng cách sử dụng vị trí bắt đầu và kết thúc có thể bỏ lỡ va chạm nếu một trong hai đối tượng quay nhanh và dài hơn một chiều so với chiều khác.

Để tính toán AABB ước tính chính xác hơn, hãy phân tách chuyển động thành các bước nhỏ hơn và chỉ sử dụng AABB ban đầu (không phải lưới đối tượng), xoay AABB (bây giờ chỉ là một hộp, không phải là trục được căn chỉnh) vì mỗi đối tượng sẽ xoay và di chuyển bươc. Điểm tối đa và tối thiểu cho mỗi trục sẽ cung cấp cho bạn AABB bao quanh toàn bộ chuyển động của đối tượng.

Nếu có một giao điểm với AABB lớn hơn, thì bạn có thể sử dụng các AABB nhỏ hơn đã được tính toán để xác định nơi xảy ra va chạm. Đối với mỗi AABB nhỏ hơn giao nhau với đối tượng khác, sau đó bạn có thể thực hiện phát hiện giao cắt lưới đắt tiền hơn.


2
hoặc tính toán trước chiều rộng tối đa mà BB có thể cho bất kỳ vòng quay nào và sử dụng điều đó
ratchet freak

2

Bạn sẽ phải phân tách chuyển động thành các bước di chuyển nhỏ hơn. Ví dụ:

Bạn muốn phân tách chuyển động bằng cách sử dụng thành phần lớn hơn (trong trường hợp này là trục X), sau đó kiểm tra va chạm trong mỗi bước.

Điều này có thể trông quá đắt đỏ, nhưng hãy tính đến việc một vật thể di chuyển nhanh hơn chiều rộng của chính nó, mỗi chu kỳ sẽ TUYỆT VỜI nhanh chóng, vì vậy kịch bản này không phổ biến như bạn nghĩ trước tiên.


2
Phương pháp này rất tệ, vì nó sẽ không bắt được một số trường hợp (ví dụ: một hộp gần với thứ nhất và thứ hai bạn đã vẽ) và việc lấy mẫu sẽ tăng lên quá mức cần thiết. Kiểm tra đa giác đơn giản bằng SAT phải đủ nhanh và đáng tin cậy.
Sốt

1
Vâng, đây là một giải pháp OK nhưng không quá tuyệt vời. Độ chính xác giảm nhanh khi va chạm gần các góc của vật thể, hiệu suất giảm khi tốc độ tăng (hoặc độ chính xác, tùy thuộc vào việc thực hiện) và đó chỉ là hack không cần thiết.
BWG

2

Bạn cũng nên sử dụng tốc độ tương đối cho kiểm tra va chạm để một AABB là "tĩnh" và một tốc độ khác di chuyển với tốc độ của chính nó trừ đi tốc độ của "tĩnh".

Cách nhanh nhất để xem họ có thể giao nhau hay không là chỉ cần mở rộng AABB đang di chuyển với tốc độ.

ví dụ AABB đang di chuyển sang phải với 0,1 x / khung hình, sau đó bạn mở rộng nó để cạnh trái giữ nguyên và cạnh phải là 0,1. Sau đó, bạn có thể kiểm tra với AABB mới. Nếu sai thì không có va chạm. (trở lại sớm và chính xác cho tốc độ nhỏ).

Sau đó, bạn có thể kiểm tra xem kết thúc và bắt đầu AABB của đối tượng chuyển động có giao nhau không. nếu đúng thì trả về đúng.

Nếu không, bạn cần kiểm tra xem đường chéo có giao nhau với ABB tĩnh hay không.

Điều này liên quan đến việc lấy tọa độ của đường chéo trong đó x = cạnh trái của tĩnh và cạnh phải xem liệu y có ở dưới cùng và trên cùng không. (lặp lại cách khác)

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.