Який найшвидший спосіб перевірити, чи перетинаються два рухомих AABB?


12

У мене є два AABB, які рухаються, який найшвидший спосіб перевірити, чи будуть вони перетинатися під кадром?

Під рухом я маю на увазі не просто перевірити звичайним методом перетину прямокутника, я маю на увазі якийсь простий простий тестовий тест, який повертає лише булевий, не час удару чи що-небудь інше.

Я думаю, що це просто зробити так:

Це

Але цей шестикутник досить складний, і я не знаю, як обчислити перетин AABB - полігон, чи може бути простіший спосіб?

Будь-яка мова програмування, яка вам найбільше подобається, я можу її легко перенести.

Дякую.


3
Я збентежений. Ви конкретно згадуєте про "тестовий тест", чи ви пробували типовий тест AABB? Це робить саме те, що ти хочеш.
SomeWritesЗарезервовано

1
Я згоден з коментарем вище - що не так з "класичним" тестом? Більше того, більшість запропонованих рішень тут явно повільніші ... плюс деякі з них можуть дати неправильні результати (не надійні).
wondra

Ви можете спробувати Тест роздільної осі gamedevelopment.tutsplus.com/tutorials/…
Pharap

Відповіді:


8

Використовуйте суму Міньковського

Хороший спосіб вирішити цю проблему , щоб розглянути перетин між лінією руху ( v ) переведені в початок координат ( V « ) і сума Маньківського від А повертається на 180 градусів на початку координат ( А» ) і його перешкоди (тільки B в даному випадку): А »B .

У наступній картині I місце А ляпас-мазок в походженні довільної системи координат. Це спрощує розуміння того, що обертання A на 180 градусів призводить до A ' , а v переведений на початок дорівнює v' .

Сума Міньковського - зелений прямокутник, а точки перетину рухомого А та нерухомого В можна знайти, перетинаючи лінію ААВВ . Ці точки позначені синіми колами.

Мінківська сума - випадна справа

На наступному малюнку було використано інше походження і виявлені ті ж самі точки перетину.

Сума Міньковського - більш загальний випадок

Кілька рухомих AABB

Щоб зробити цю роботу для двох AABB, які рухаються лінійним способом протягом певного періоду часу, ви віднімаєте вектор швидкості B від вектора швидкості A і використовуєте його як відрізок лінії для перетину лінії AABB.

Псевдокод

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)

Відповідь на зіткнення

Залежно від геймплея, ви б або виконали більш дрібне виявлення зіткнень (можливо, містять сітки AABB), або переходите до наступної фази: реакція на зіткнення.

Коли відбувається зіткнення, алгоритм перетину лінії AABB поверне або 1, або 2 точки перетину залежно від того, припиняє рух A всередині В або проходить через нього відповідно. (Це дисконтування вироджених випадків, коли A пасеться B уздовж їхніх боків або уздовж одного з відповідних кутів.)

Так чи інакше, перша точка перетину вздовж відрізка лінії є точкою зіткнення, ви переведете це назад у правильне положення у світовій системі координат (перше світло-синє коло на другому малюнку уздовж вихідного v , назвіть його p ), а потім вирішити (наприклад, для пружних зіткнень, відображаючи v вздовж нормального зіткнення в p ), яким буде фактичне положення для A в кінці кадру ( At + 1 ).

Відповідь на зіткнення

Якщо є більше, ніж просто 2 колайдери, це стане трохи складнішим, оскільки ви хочете зробити зіткнення для другої, відбитої, частини v також.


Спасибі, найцікавіше Чи можете ви пояснити, як ви поводитесь із випадком, коли A і B перетинаються під час руху, але закінчуєте рух без перетину?
GameAlchemist

@GameAlchemist Це була б реакція на зіткнення, а не стільки виявлення зіткнення (вихідна тема питання). Але мені подобається Paint, тому перегляньте правки. :-)
Ерік

Дякую за оновлення (і хура за схеми :-)), це не було моїм питанням, але допомогло мені зрозуміти, що ваш алгоритм вже розглядає випадок, коли A повністю проходить через B.
GameAlchemist

5

OBB - орієнтована обмежувальна коробка. Ось підручник

Ефективно обмежувальне поле, вирівняне з вектором швидкості об'єкта A як вісь y (вгору). Її ширину та висоту можна обчислити за початковою та кінцевою точками об’єкта А. Потім ви порівнюєте це з AABB об'єкта B (трактуючи його як OOBB) та вашим золотим.

Якщо ви просто шукаєте тест на швидке перехрестя, щоб побачити, якби вони МОЖЛИВИ перетинатися, ви можете створити AABB, який оточує AABB об'єкта A, як у початковому, так і в кінцевому положенні. Якщо AABB не перетинається з цим усім, що охоплює AABB, то перетину немає; Однак це може призвести до помилкових позитивних результатів, тому слід використовувати його лише як попередній тест.


4

Вам не потрібні OOB, і вам не потрібно використовувати детектування зіткнень із кроком у часі. Просто скористайтеся звичайним тестом AABB, дивіться за цим посиланням . По суті, він робить саме те, що є у вашій діаграмі: AABB, що рухається, "змітається" від початкової точки до кінцевої точки, а потім використовується для виявлення зіткнень проти інших, статичних AABB.

Якщо ви переживаєте, що цей тест промітання дорожчий, оскільки він повертає "час впливу", я думаю, ви передчасно оптимізуєте.

Більш глибоку інформацію про тестові випробування можна знайти у чудовій книзі: Виявлення зіткнення в реальному часі Крістера Еріксона.


3

Слабкість випадку крайнього наближення AABB

Вам потрібно спочатку розкласти рух на більш дрібні кроки і використовувати цю інформацію для обчислення високого рівня AABB. Якщо великий перетин AABB перетинається, ви можете перевірити менші кроки, щоб бути точнішими.

Оцінюючи, чи могло статися зіткнення чи ні, перевіряючи AABB (або OOBB), використовуючи лише початкову та кінцеву позиції, можна пропустити зіткнення, якщо будь-який об’єкт обертається швидко і довше в одному вимірі, ніж інший.

Щоб обчислити більш точну оцінку AABB, розподіліть рух на більш дрібні кроки і, використовуючи лише початковий AABB (а не об’єктну сітку), обертайте AABB (тепер просто поле, не вирівняне по осі), оскільки об'єкт обертається і рухатиметься в кожному крок. Максимальні та мінімальні точки для кожної осі дасть вам AABB, який закриває весь рух об’єкта.

Якщо є перехрестя з більшим AABB, то можна використовувати менші AABB, які вже були розраховані, щоб визначити, де могло бути зіткнення. Для кожного з менших AABB, які перетинаються з іншим об'єктом, ви можете зробити більш дороге виявлення перетину сітки.


2
або заздалегідь підрахуйте максимальну ширину, яку може ББ використовувати для будь-якого обертання, і скористайтеся цим
храповиком виродком

2

Вам доведеться розкласти рух на менші кроки руху. Наприклад:

Ви хочете розкласти рух, використовуючи більший компонентn (у цьому випадку вісь X), а потім перевірити на зіткнення на кожному кроці.

Це може здатися надто дорогим, але врахуйте, що об'єкт, що рухається швидше, ніж його власна ширина, кожен цикл буде НАДОБРЕ швидким, тому цей сценарій не такий поширений, як ви могли подумати раніше.


2
Цей метод поганий, тому що він не сприймає деяких випадків (наприклад, поле, яке знаходиться близько до першого, а друге, яке ви намалювали), і збільшити вибірку було б надмірним. Простий тест на багатокутник із застосуванням SAT повинен бути досить швидким та надійним.
Сопель

1
Так, це нормальне рішення, але не надто велике. Точність швидко знижується, коли зіткнення наближається до кутів об'єктів, продуктивність зменшується зі збільшенням швидкості (або точності, залежно від реалізації), і це просто без зайвих зусиль.
BWG

2

Ви також повинні використовувати відносні швидкості для перевірки зіткнення, щоб одна AABB була "статичною", а інша рухалася зі швидкістю власної швидкості за вирахуванням швидкості "статичної".

Найшвидший спосіб зрозуміти, чи можуть вони перетинатися, - це просто розширити рухомий AABB зі швидкістю.

наприклад, AABB рухається праворуч з 0,1 х / кадр, потім ви розширюєте його, щоб лівий край залишався таким же, а правий край на 0,1 далі. Потім ви можете звернутися до нового AABB. Якщо помилково, то зіткнення не відбувається. (раннє повернення і точне для малих швидкостей).

Потім ви можете перевірити, чи перетинається кінець та запуск AABB рухомого об’єкта. якщо правда, то поверніть істину.

В іншому випадку вам потрібно перевірити, чи перетинає діагональ статична ABB.

Це передбачає отримання координат діагоналі, де x = лівий край статичного та правий край, побачте, чи y знаходиться всередині нижнього та верхнього. (повторіть навпаки)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.