Qual è il modo più veloce per verificare se due AABB in movimento si intersecano?


12

Ho due AABB che si stanno muovendo, qual è il modo più veloce per verificare se si intersecano sotto un frame?

Spostando intendo non solo verificare con il solito metodo di intersezione del rettangolo, intendo una sorta di semplice test semplice che restituisce solo un valore booleano, nessun tempo di hit o altro.

Quello che penso è semplicemente farlo in questo modo:

Questo

Ma che Hexagon è piuttosto complesso e non so come calcolare un incrocio AABB - Polygon, c'è forse un modo più semplice?

Qualsiasi linguaggio di programmazione che ti piace di più, posso facilmente portarlo.

Grazie.


3
Non ho capito bene. Hai menzionato in particolare il "sweep test", hai provato il tipico sweep test AABB? Fa esattamente quello che vuoi.
SomeWrites Riservato il

1
Sono d'accordo con il commento sopra - cosa c'è di sbagliato nel test "classico"? Inoltre, la maggior parte delle soluzioni proposte qui sono chiaramente più lente di così ... inoltre alcune di esse possono dare risultati errati (non robusti).
Wondra,

Potresti provare il test dell'asse di separazione gamedevelopment.tutsplus.com/tutorials/…
Pharap,

Risposte:


8

Usa la somma di Minkowski

Un buon modo per risolvere questo problema è considerare l'intersezione tra una linea di movimento ( v ) tradotta nell'origine ( v ' ) e la somma di Minkowski di A ruotata di 180 gradi all'origine ( A' ) e i suoi ostacoli (solo B in questo caso): a'B .

Nell'immagine seguente inserisco A smack-dab nell'origine di un sistema di coordinate arbitrario. Ciò semplifica la comprensione della rotazione di 180 gradi di A in A ' , e v tradotto nell'origine equivale a v' .

La somma di Minkowski è il rettangolo verde e i punti di intersezione di una A in movimento e una B fissa possono essere trovati facendo l' intersezione linea-AABB . Questi punti sono contrassegnati dai cerchi blu.

Somma di Minkowski - caso degenerato

Nell'immagine seguente è stata utilizzata un'origine diversa e sono stati trovati gli stessi punti di intersezione.

Somma di Minkowski - caso più generale

AABB mobili multipli

Per far funzionare questo per due AABB che si muovono in modo lineare durante uno specifico periodo di tempo, sottraresti il vettore di velocità B dal vettore di velocità A e lo utilizzeresti come segmento di linea per l'intersezione linea-AABB.

Codice pseudo

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)

Risposta alla collisione

A seconda del gameplay eseguiresti un rilevamento delle collisioni più dettagliato (forse gli AABB contengono mesh) o passerai alla fase successiva: la risposta alle collisioni.

Quando c'è una collisione l'algoritmo line-AABB-intersection restituirà 1 o 2 punti di intersezione a seconda che A finisca il suo movimento all'interno di B o lo attraversi, rispettivamente. (Questo sta scontando i casi degeneri in cui A sfiora B lungo i loro lati o lungo uno dei rispettivi angoli.)

Ad ogni modo, il primo punto di intersezione lungo il tratto di linea è il punto di collisione, lo ritrasformeresti nella posizione corretta nel sistema di coordinate del mondo (il primo cerchio azzurro nella seconda immagine lungo la v originale , chiamalo p ) e quindi decidere (ad es. per le collisioni elastiche riflettendo v lungo la collisione normale a p ) quale sarà la posizione effettiva per A alla fine del telaio ( At + 1 ).

Risposta alla collisione

Se ci sono più di 2 soli collider, questo diventerà un po 'più complesso, poiché si vorrebbe fare il rilevamento delle collisioni anche per la seconda, riflessa, parte di v .


Grazie, molto interessante. Potresti spiegare come gestisci il caso quando A e B si intersecano durante lo spostamento, ma finiscono lo spostamento senza intersezione?
GameAlchemist,

@GameAlchemist Sarebbe la risposta alla collisione e non tanto il rilevamento della collisione (l'oggetto originale della domanda). Ma mi piace Paint, quindi dai un'occhiata alla modifica. :-)
Eric

Grazie per l'aggiornamento (e hurra per gli schemi :-)), questa non era la mia domanda, ma mi ha aiutato a capire che il tuo algoritmo gestisce già il caso quando A passa completamente attraverso B.
GameAlchemist

5

OBB - Scatola di delimitazione orientata. Ecco un tutorial

In effetti, un rettangolo di selezione allineato con il vettore di velocità dell'oggetto A come asse y (su). La sua larghezza e altezza possono essere calcolate dai punti iniziale e finale dell'oggetto A. Quindi si confronta questo con l'AABB dell'oggetto B (trattandolo come OOBB) e il proprio oro.

Se stai solo cercando un rapido test di intersezione per vedere SE POTREBBERO intersecarsi, potresti creare un AABB che circonda l'AABB dell'oggetto A in entrambe le posizioni iniziale e finale. Se un AABB non si interseca con tutto ciò che comprende AABB, allora non c'è intersezione; Tuttavia, questo potrebbe portare a falsi positivi, quindi dovresti usarlo solo come test preliminare.


4

Non sono necessari OOB e non è necessario utilizzare il rilevamento delle collisioni temporali. Basta usare il normale test AABB spazzato, vedere questo link . In sostanza, fa esattamente quello che hai nel tuo diagramma: l'AABB in movimento viene "spazzato" dal punto iniziale al punto finale e quindi viene utilizzato per il rilevamento delle collisioni con altri AABB statici.

Se sei preoccupato che questo test spazzato sia più costoso perché restituisce un "tempo di impatto", penso che tu ottimizzi prematuramente.

Informazioni più approfondite sui test spazzati sono disponibili nell'eccellente libro: Real-Time Collision Detection di Christer Ericson.


3

Debolezza del caso del bordo di approssimazione AABB

Dovrai prima decomporre il movimento in passaggi più piccoli e utilizzare tali informazioni per calcolare un AABB di alto livello. Se il grande AABB si interseca, puoi quindi controllare i passaggi più piccoli per essere più accurati.

Stimare se ci può essere stata o meno una collisione controllando AABB (o OOBB) usando solo le posizioni iniziale e finale può perdere le collisioni se uno degli oggetti sta ruotando rapidamente ed è più lungo in una dimensione rispetto a un'altra.

Per calcolare un AABB di stima più accurato, scomporre il movimento in passaggi più piccoli e utilizzando solo l'AABB iniziale (non la mesh dell'oggetto), ruotare l'AABB (ora solo una casella, non allineato all'asse) poiché l'oggetto ruoterebbe e si muoverà su ogni passo. I punti massimo e minimo per ciascun asse ti daranno l'AABB che racchiude l'intero movimento dell'oggetto.

Se esiste un'intersezione con AABB più grande, è quindi possibile utilizzare gli AABB più piccoli che sono già stati calcolati per determinare dove potrebbe essere stata la collisione. Per ciascuno degli AABB più piccoli che si intersecano con l'altro oggetto, è quindi possibile eseguire il rilevamento delle intersezioni mesh più costoso.


2
o precalcolate la larghezza massima che il BB può per qualsiasi rotazione e usatelo
maniaco del cricchetto

2

Dovrai scomporre il movimento in piccoli passi di movimento. Per esempio:

Si desidera decomporre il movimento utilizzando il componente maggiore (in questo caso, l'asse X), quindi verificare la collisione in ogni passaggio.

Questo potrebbe sembrare troppo costoso, ma tieni presente che un oggetto che si muove più velocemente della sua larghezza ogni ciclo sarà ESTREMAMENTE veloce, quindi questo scenario non è così comune come potresti pensare.


2
Questo metodo è errato, perché non rileverà alcuni casi (ad esempio una casella vicina al primo e il secondo che hai disegnato) e l'aumento del campionamento sarebbe eccessivo. Il semplice test poligonale con SAT dovrebbe essere abbastanza veloce e affidabile.
Sopel,

1
Sì, questa è una soluzione OK ma non troppo eccezionale. La precisione diminuisce rapidamente quando la collisione si avvicina agli angoli degli oggetti, le prestazioni diminuiscono all'aumentare della velocità (o della precisione, a seconda dell'implementazione), ed è semplicemente inutilmente confusa.
BWG,

2

È inoltre necessario utilizzare le velocità relative per il controllo delle collisioni in modo che un AABB sia "statico" e l'altro si sposti a una velocità della propria velocità meno la velocità di quello "statico".

Il modo più veloce per vedere se possono intersecarsi è semplicemente espandere l'AABB in movimento con la velocità.

ad esempio l'AABB si sta muovendo a destra con 0,1 x / frame, quindi lo si estende in modo che il bordo sinistro rimanga lo stesso e il bordo destro sia ulteriormente 0,1. Quindi è possibile verificare con il nuovo AABB. Se falso, non vi è alcuna collisione. (ritorno anticipato e preciso per le piccole velocità).

Quindi puoi verificare se la fine e avviare AABB dell'oggetto in movimento si intersecano. se vero allora ritorna vero.

Altrimenti è necessario verificare se la diagonale interseca l'ABB statico.

Ciò implica ottenere le coordinate della diagonale dove x = bordo sinistro dello statico e bordo destro per vedere se y è all'interno del fondo e in alto. (ripetere il contrario)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.