Collisioni di oggetti piccoli e ad alta velocità: evitare il tunneling


14

MODIFICA / AGGIORNAMENTO: La mia più grande domanda in questo momento è se l'equazione "t = ..." del passaggio 3 è una buona idea o esiste un modo migliore per farlo. La maggior parte degli altri problemi è stata affrontata parzialmente o completamente, ma nessun commento o risposta ha toccato davvero questo problema. Ancora una volta, è probabilmente necessaria una soluzione analitica, le velocità e le distanze sono troppo grandi e gli oggetti sono troppo piccoli, per qualsiasi soluzione iterativa / ricorsiva (alcune sono suggerite di seguito nei commenti) a cui posso pensare (anche se se c'è una soluzione iterativa / ricorsiva speciale che gestirà bene questo tipo di situazioni, quindi sono decisamente aperto ad essa). Grazie mille per il tuo aiuto finora, siete tutti fantastici e apprezzo molto i vostri pensieri e il vostro aiuto!

Sto cercando di rilevare le collisioni tra piccoli oggetti ad alta velocità. Questa è una situazione in cui il tunneling può avvenire molto facilmente, anche a velocità relativamente basse.

Il lancio del raggio non funzionerà, poiché sta rilevando una collisione tra due oggetti ad alta velocità, non tra un oggetto e una parete fissa. (A meno che non abbia frainteso il ray casting?) Le prestazioni sono MOLTO MOLTO una considerazione; se possibile, voglio evitare un grande successo in termini di prestazioni. Ho già implementato un quadtree funzionale e molto efficace ( http://en.wikipedia.org/wiki/Quadtree ), quindi lo modificherò e lo userò come descritto di seguito.

Modifica: la riduzione dell'intervallo di tempo non funzionerà. Le velocità sono troppo elevate per questa soluzione, il che significa che i risultati delle prestazioni sarebbero troppo elevati, pur continuando a perdere la stragrande maggioranza delle collisioni tra tunnel . (Ad esempio, potrei avere un oggetto con una dimensione di circa 1 unità a una velocità misurata in milioni di unità per intervallo di tempo ...)

LA SOLUZIONE PROPOSTA:

Passo 1:

Crea una casella attorno al movimento di ciascun oggetto, quindi inserisci quelle caselle nel quadrifoglio per generare un elenco iniziale di possibili collisioni. Vedi l'immagine seguente (questa immagine mostra un oggetto circolare che si sposta da una posizione all'altra e il movimento che genera un rettangolo, che verrà inserito nel quadrifoglio):Rettangolo generato dal movimento

Passaggio 2: (potresti voler saltare questo passaggio?)

Scorri l'elenco delle possibili collisioni generate dal quadrifoglio. Vedi se i rettangoli si intersecano in ogni possibile collisione. In tal caso, procedere al passaggio 3.

MODIFICA: Sotto, Sean Middleditch ha suggerito di usare i volumi spazzati / l'intersezione delle capsule (se gli oggetti sono cerchi). Ciò lascia tre opzioni: 1) saltare completamente il passaggio 2. 2) Eseguire il passaggio 2 a modo mio. 3) Fallo alla maniera di Sean. Il modo in cui Sean sarà più computazionalmente costoso della mia idea di scatola, tuttavia eliminerà più falsi positivi del mio modo, impedendo loro di arrivare al passo finale.

Qualcuno può parlare per esperienza su quale di queste 3 scelte sia la migliore? (Intendo utilizzare questo motore fisico per alcune cose diverse, quindi sto cercando la soluzione "generalmente migliore" che funziona più velocemente nella più ampia varietà di situazioni, non solo un caso di test specifico in cui posso facilmente misurare quale soluzione è il più veloce).

Passaggio 3:

Utilizzare l'equazione t = di seguito, se il discriminante (ovvero la parte sotto la radice quadrata) è negativo o 0, nessuna collisione, se positivo, quindi utilizzare il valore t come tempo di collisione (dopo di che è facile regolare le posizioni di conseguenza. ..se entrambi gli oggetti continuano a esistere dopo la collisione). Equazione:

t = (-1/2 sqrt ((2 a w-2 a x + 2 b y-2 b z-2 c w + 2 c x-2 d y + 2 dz) ^ 2-4 (w ^ 2- 2 w x + x ^ 2 + y ^ 2-2 y z + z ^ 2) (a ^ 2-2 a c + b ^ 2-2 b d + c ^ 2 + d ^ 2-r ^ 2-2 r ss ^ 2)) - a w + a xb y + b z + c wc x + d yd z) / (w ^ 2-2 w x + x ^ 2 + y ^ 2-2 y z + z ^ 2 ) .

Dove (1 e 2 vengono utilizzati per indicare gli oggetti 1 e 2):

t è un valore temporale negativo compreso tra 0 e -1, dove 0 è il fotogramma corrente e -1 è il fotogramma precedente;

a = x posizione 1;

b = y posizione 1;

c = x posizione 2;

d = y posizione 2;

w = x velocità 1;

x = x velocità 2;

y = y velocità 1;

z = y velocità 2;

r = raggio 1;

s = raggio 2;

Derivazione: (^ 2 significa quadrato)

Prendi le equazioni parametriche (ad esempio, newxpos1 = a + t w) per i movimenti degli oggetti e inseriscili nella formula della distanza (quadratura di entrambi i lati): formula della distanza al quadrato = (a + t w - (c + t x)) ^ 2 + (b + t y - (d + t * z)) ^ 2. Ricorda, t sarà negativo. Per trovare il tempo di collisione per due oggetti circolari impostiamo il lato sinistro uguale a (r + s) ^ 2. Risolvendo per t usando l'equazione quadratica (e una grande quantità di algebra molto noiosa), otteniamo l'equazione "t = ..." sopra.

Le mie domande:

1) È un buon modo per farlo? Funzionerà affatto? Incontrerò problemi imprevisti? (So ​​che avrò problemi quando più di 2 oggetti alla volta si scontrano, ma non mi interessa poiché l'unico caso a cui mi oppongo davvero è quando hanno basse velocità relative (se le velocità relative sono alte allora la soluzione "sciocca" fornita dall'algoritmo sarà "abbastanza buona", e sarà impossibile per un essere umano vedere l'errore), e se più di 2 si scontrano con basse velocità relative nello stesso intervallo di tempo, la maggior parte delle soluzioni essere comunque abbastanza vicino, dal momento che non ho intenzione di avere un sacco di collisioni anelastiche)

2) La mia performance soffrirà molto? Non penso che lo farà, ma se lo farà, c'è un modo migliore per farlo?

3) Devo saltare il passaggio 2 e andare direttamente dal passaggio 1 al 3? Ovviamente il passaggio 2 non è vitale, ma potrebbe aiutare le prestazioni (OPPURE potrebbe costare più tempo della CPU di quanto risparmi).

Tutti gli altri commenti, suggerimenti o critiche sono i benvenuti. Grazie per l'aiuto!


1
Christer Ericson ha alcune informazioni sui test spazzati sfera / sfera nel suo libro arancione. Esistono diversi modi per risolvere il problema, ma immagino che ti piacerà di più l'intervallo dimezzato. È bello provare a ricavare queste cose da soli, ma dovresti davvero andare a leggere il libro arancione e confrontarlo per ottenere una routine di rilevamento davvero buona e saperne di più.
RandyGaul,

Sembra che tu abbia già un piano .. provalo e vedi come funziona?
Trevor Powell,

Penso che il modo "solito" sia quello di avere un piccolo intervallo massimo sul tuo delta time. Quindi, se hai 1000ms, basta simulare 10x 100ms (o 100x 10ms o 33x 30ms o qualcosa di simile).
ashes999,

@RandyGaul Ho esaminato l'algoritmo descritto a pagina 215-218, in particolare pagina 218 (anteprima di Google). È abbastanza elegante, anche se non ho ancora riflettuto su tutte le sue implicazioni, i suoi punti di forza e le sue debolezze. Sarà molto più veloce del mio? In tal caso, quale parte del mio algoritmo è lenta rispetto alla ricorsione di Ericson? L'equazione nel passaggio 3 sarà troppo lenta? La ricorsione mi fa esitare, poiché alcuni oggetti potrebbero muoversi MOLTO velocemente, e quindi in alcuni casi potrebbe essere necessaria una grande ricorsione. (Inoltre, OUCH, $ 70 per quel libro ...)
MindSeeker,

1
@MindSeeker Non ho tempo di esaminare la tua derivazione, ma sono sicuro che gli algoritmi nel libro di Ericson, uno qualsiasi, funzioneranno davvero bene e probabilmente saranno più veloci e più robusti delle tue cose. Puoi trovare le versioni PDF online gratuitamente, se vuoi provare le altre pagine. Inoltre, se effettuerai spesso il rilevamento delle collisioni, il libro arancione è un punto fermo.
RandyGaul,

Risposte:


9

Hai essenzialmente creato una versione un po 'troppo entusiasta dei volumi spazzati .

Prendi le due posizioni dell'oggetto. "Spazza" l'oggetto dall'inizio alla fine. Per una sfera, ciò creerebbe una capsula. Per una scatola, ciò creerebbe un esagono (o una scatola più lunga è il movimento è lungo un singolo asse). Per i poligoni convessi generali, ciò creerebbe un diverso poligono convesso.

È ora possibile eseguire test di intersezione (incluse query quadtree) utilizzando questo volume di sweep. È possibile calcolare quando si è verificata la collisione, far avanzare la simulazione dall'ora di inizio alla durata della collisione e ripetere.

Un'altra opzione, un po 'più semplice, è fare ciò che @ ashes999 ha dichiarato e usare semplicemente un intervallo di tempo più piccolo o velocità più basse. Esiste una velocità massima ideale derivata dall'intervallo in cui nessun oggetto può muoversi oltre il suo lato più stretto in una singola interazione fisica. Per oggetti particolarmente piccoli o particolarmente veloci potresti non essere in grado di trovare un intervallo ragionevolmente piccolo che funzioni bene.

Vedere Rilevamento delle collisioni in tempo reale per uno dei migliori libri introduttivi / di intermediazione sul tema del rilevamento delle collisioni.


Grazie per il fantastico contributo! Scomponendo la tua risposta in modo che io possa porre domande al riguardo: "" Spazza "l'oggetto dall'inizio alla fine." Finora sto monitorando; sicuramente un miglioramento rispetto al mio metodo box. Darò queste forme a quadtree e poi verificherò le collisioni più esatte. "È possibile calcolare quando si è verificata la collisione." Haha più facile a dirsi che a farsi :) Mi stai raccomandando di attenermi alla mia equazione dal passaggio 3 per il passaggio? O c'è un modo migliore? Questa è la parte davvero critica.
MindSeeker,

[continua] "Un'altra opzione ..." Ho pensato a quell'opzione, ma sfortunatamente le velocità sono troppo alte. Vedi la mia risposta al commento su @ ashes999 e modifica sopra per maggiori informazioni. Grazie mille per il tuo aiuto!
MindSeeker,

L'unico modo per conoscere le prestazioni è provarle, misurarle e vedere. Ho già visto un codice "ovviamente" inefficiente che ha massicciamente superato in precedenza le versioni efficienti, di solito per ragioni non intuitive. Non chiedere ciò che è più veloce; prova e scoprilo.
Sean Middleditch,

Abbastanza giusto, andrò avanti e proverò il mio metodo, modificato come mi hai suggerito. La mia domanda nel commento rimane comunque: "È possibile calcolare quando si è verificata la collisione". Stai raccomandando di attenermi alla mia equazione dal passaggio 3 per quel passaggio? O c'è un modo migliore? Questa è la parte più difficile del problema, penso. Volumi spazzati, se li capisco correttamente, possono dirmi che i percorsi degli oggetti si intersecano, ma non possono dirmi se / quando gli oggetti stessi si scontrano.
MindSeeker,

1
La geometria spazzata di @MindSeeker è raycasting tranne per il fatto che stai lanciando la forma anziché un raggio. Quindi il metodo dovrebbe apparire simile all'utilizzo del ray casting con "raggi" per tutti gli oggetti in rapido movimento invece di un solo raggio rispetto a un oggetto fermo. Dopo aver determinato le potenziali collisioni dai "raggi", è necessario risolvere il tempo su entrambi i "raggi" per assicurarsi che si trovino nello stesso punto allo stesso tempo.
stonemetal

2

L'algoritmo proposto nella domanda funziona alla grande: è veloce ed è completamente accurato , anche quando gli oggetti vanno a velocità estreme. Ho implementato un quadrifoglio, quindi dopo aver inserito le caselle dal passaggio 1 al quadrifoglio, ho trovato il passaggio 2 non necessario: il mio programma era in esecuzione quasi alla stessa velocità di prima.

Sto usando questo algoritmo da un paio di mesi e sembra essere perfettamente preciso nel determinare il tempo di collisione. Dal momento che sembra non esserci nulla di meglio sul web, consiglio vivamente di usare questo. (Alcune delle risposte nelle altre risposte e commenti sopra sono fantastiche, ma o non soddisfano del tutto le esigenze dichiarate dalla domanda oppure l'autore era molto ambiguo su qualcosa e non è mai tornato a rispondere quando è stato interrogato sull'ambiguità ).


1

Non ho ancora abbastanza reputazione per commentare, ma vorrei solo aggiungere che usando ciò che Sean Middleditch menzionato sopra rende possibile calcolare la tua "t". Almeno se avessi capito la sua risposta e la tua domanda fosse corretta.

Ecco un link a una fantastica risposta di Sam Hocevar che fornisce la migliore spiegazione che io abbia mai trovato (ha anche disegnato delle foto, evviva!)

/gamedev//a/55991/112940

Se questo è più veloce del tuo metodo, non posso dirlo, ma sicuramente ti dà tutto ciò di cui hai bisogno per implementarlo e confrontarlo con il tuo.

Solo per evitare di lasciare un "link solo risposta", fornirò una breve sintesi della sua idea:

  1. calcola la differenza di Minkowski tra le due caselle di delimitazione
  2. usando la velocità relativa tra allora, getta un segmento raggio / linea dall'origine al riquadro creato dalla differenza di Minkowski per ottenere il punto di intersezione
  3. Se il raggio colpisce, dividi la distanza percorsa dal raggio per la lunghezza del vettore che rappresenta la velocità relativa e avrai la tua "t"
  4. fai clic sul link che ho fornito sopra e vedi sam bella spiegazione di tutto ciò, con molte immagini. È fantastico.
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.