Come posso implementare un Bullet Physics CollisionObject che rappresenta il mio cubo come terreno?


8

Ho integrato con successo la libreria Bullet Physics nel mio sistema di entità / componente. Le entità possono scontrarsi. Ora devo consentire loro di scontrarsi con il terreno, che è finito e simile a un cubo (pensa a InfiniMiner o al suo clone Minecraft ). Ho iniziato a utilizzare la libreria Bullet Physics solo ieri, quindi forse mi manca qualcosa di ovvio.

Finora ho esteso la RigidBodyclasse per sovrascrivere la checkCollisionWith(CollisionObject co)funzione. Al momento è solo un semplice controllo dell'origine, non usando l'altra forma. Lo farò più avanti. Per ora sembra così:

@Override
public boolean checkCollideWith(CollisionObject co) {
    Transform t = new Transform();
    co.getWorldTransform(t);
    if(COLONY.SolidAtPoint(t.origin.x, t.origin.y,t.origin.z)){
        return true;
    }
    return false;
}

Funziona alla grande, per quanto riguarda il rilevamento di collisioni. Tuttavia, questo non gestisce la risposta alla collisione. Sembra che la risposta di collisione predefinita sia spostare gli oggetti in collisione al di fuori delle forme altrui, possibilmente i loro AABB.

Al momento la forma del terreno è solo una scatola delle dimensioni del mondo. Ciò significa che le entità che si scontrano con il terreno sparano semplicemente all'esterno di quella casella di dimensioni mondiali. Quindi è chiaro che o ho bisogno di modificare la risposta alla collisione o ho bisogno di creare una forma che si adatta direttamente alla forma del terreno. Quindi quale opzione è la migliore e come posso implementarla? Forse c'è un'opzione a cui non sto pensando?

Va notato che il terreno è dinamico e frequentemente modificato dal giocatore.

Risposte:


8

Mentre apprezzo la risposta di Kevin Reid, era ad un livello superiore a quello che mi poneva la mia domanda. Comprensibilmente senza la conoscenza della Bullet Physics, sarebbe difficile rispondere a questa domanda. Ho funzionato e ho una risposta specifica per Bullet Physics.

Oltre ad estendere la RigidBodyclasse come ho menzionato nella mia domanda. Avevo anche bisogno di estendere la CollisionAlgorithmlezione. Questo è principalmente per sovrascrivere la processCollision()funzione. All'interno della processCollision()funzione (che prende i due corpi in collisione come argomenti), sono stato in grado di creare una forma del cubo e appropriata Transformper il cubo con cui la mia entità stava attualmente scontrandosi. Quindi lascia che la collisione predefinita avvenga in base all'entità e al cubo / ai cubi specifici con cui si scontra. Per utilizzare la nuova estensione CollisionAlgorithm, avevo bisogno di registrare l'algoritmo per gestire le forme che voglio che gestisse. In questo caso è praticamente il tipo di terreno rispetto a tutto il resto. Per quello che ho usato registerCollisionCreateFunc()con il mio CollisionDispatcher.

Quindi, per quelli che seguiranno in futuro:

  1. Estendi RigidBodyper avere un controllo di collisione di base con il tuo terreno.
  2. Crea un'istanza della tua RigidBodyclasse e aggiungila alla tua DynamicsWorldo qualunque cosa PhysicsProccesortu stia utilizzando.
  3. Estendi CollisionAlgorithm, in particolare processCollision()per creare forme e trasformazioni di fisica Bullet che si adattano alla posizione della collisione.
  4. Registra la tua versione di CollisionAlgorithmcon il tuo CollisionDispatcherutilizzo registerCollisionCreateFunc(). (Questa registrazione viene eseguita più volte, una volta per ogni coppia di forme che si desidera scontrare.)

MODIFICARE

Ecco un video in azione se qualcuno è interessato.

Rilevamento della collisione iniziale

Per i miei controlli di collisione iniziali, il mio esteso ha rigidBodyla precedenza sulla checkCollideWithfunzione descritta nella mia domanda. Ho una funzione per il mio terreno che può verificare se il mondo è solido in un punto specifico. Fondamentalmente, collaudo il mio terreno contro l'oggetto che viene passato dalla checkCollideWithfunzione, vedendo se il mio terreno è solido ovunque entro i limiti di quell'oggetto.

Ora, c'è anche il prossimo passo in Bullet, trovare i punti di contatto. Ciò avviene nella processCollision()funzione che ho menzionato sopra. Qui, ho creato una scatola Misura le dimensioni di un cubo del terreno, quindi quando rilevo una collisione nella checkCollideWithfunzione, posiziono quella scatola delle dimensioni del cubo del terreno Forma nella posizione di collisione e lascio che Bullet utilizzi tutti gli algoritmi predefiniti per rilevare i punti di collisione lì .

Quindi, fondamentalmente, se i limiti di un oggetto fisico toccano il materiale solido. Metterò il mio corpo fisico temporaneo in quella posizione e dirò a Bullet di controllare le collisioni contro quel cubo temporaneo, come se fosse sempre lì. È una specie di super ottimizzazione posizionando un boxShape per ogni cubo nel mio terreno. Invece di milioni di boxShapes, ho solo bisogno di uno che si teletrasporta in giro quando viene rilevata una collisione.


Puoi espandere ulteriormente il modo in cui hai rilevato le collisioni?
Timoxley,

1
@timoxley Ho aggiornato un po 'la risposta.
MichaelHouse

Come gestiresti un singolo oggetto che si scontra in più punti, ad esempio una scala appoggiata a terra e su un muro?
Timoxley,

Il cubo temporaneo viene spostato per tutti i punti in cui un oggetto viene a contatto con il terreno. Viene utilizzato solo per il rilevamento accurato per ottenere punti di contatto e rispondere in modo appropriato.
MichaelHouse

3

Avevo dei problemi con la strategia implementata nell'altra mia risposta. I punti di contatto a volte restavano intorno, era un po 'confuso fare forme diverse dai cubi e a volte permettere agli oggetti di scivolare attraverso il terreno.

Quindi, invece di modificare o sovrascrivere una delle classi Bullet, esiste un'opzione alternativa di utilizzare un oggetto di collisione Bullet incorporato che rappresenterà il terreno. Il BvhTriangleMeshShape( doc ) è una forma incorporata rappresentata da una mesh triangolare.

Questa mesh può essere generata contemporaneamente alla mesh per visualizzare il mondo. Ciò significa che l'oggetto fisico può corrispondere esattamente all'oggetto renderizzato.

Creo un RigidBodyper ogni pezzo nel mio terreno. Quel corpo ha la sua forma impostata su a BvhTriangleMeshShape. Quando il terreno viene modificato, allo stesso tempo sto ricostruendo la rappresentazione visiva del pezzo, sto anche ricostruendo la forma fisica. Quindi, quando arriva il momento di bufferizzare la forma visiva, cambio anche le forme fisiche in questo modo:

dynamicsWorld.removeRigidBody(chunk.getRigidBody());
chunk.getRigidBody().setCollisionShape(newShape);
dynamicsWorld.addRigidBody(chunk.getRigidBody());

Questo assicura che il corpo sia rimosso correttamente, pulendo i punti di contatto. Quindi la sua forma viene modificata e viene aggiunta di nuovo.

Al fine di generare BvhTriangleMeshShapeogni pezzo deve mantenere un TriangleIndexVertexArray( doc ). Si tratta essenzialmente di buffer a due byte. Uno con le posizioni dei vertici del triangolo e l'altro con gli indici per costruire quei triangoli. Questo array di vertici deve essere mantenuto in quanto BvhTriangleMeshShapenon crea una copia dei dati.

L'uso di tutte le classi di fisica Bullet integrate è probabilmente più veloce di qualsiasi altra cosa che potrei scrivere, e infatti funziona molto velocemente. Non ho riscontrato rallentamenti dopo l'implementazione di questa nuova strategia.

inserisci qui la descrizione dell'immagine


Noterò a chiunque legga questo che, almeno durante i miei test, JBullet è MOLTO lento a cucinare mesh (cioè preelaborarle prima che possano essere utilizzate per la fisica), almeno rispetto al tempo impiegato per convertire un pezzo in una rete tramite cubi in marcia. Stiamo parlando di ordini di grandezza più lenti. Quindi, esaminerò PhysX e vedrò quanto meglio riesco a farlo funzionare. Se qualcuno ha informazioni su questo, mi piacerebbe sentirlo.
Philip Guin,

2

Non ho familiarità con Bullet Physics, ma ho usato ODE. Lì, dopo il test di collisione sì-o-no, esiste un test di collisione forma-forma più dettagliato che genera una serie di punti di contatto.

Nel tuo caso, il tuo mondo è una raccolta di scatole, quindi puoi farlo:

  1. Prendi l'AABB dell'entità in movimento.
  2. Scorrere i voxel del terreno nel volume che lo interseca.
  3. Per ogni voxel del terreno solido, costruisci una scatola di corrispondenza e calcola (preferibilmente usando le routine fornite dal motore fisico) la collisione di quella scatola con l'entità in movimento.
  4. Restituisce la raccolta di tutti i punti di contatto risultanti.

Questo non sta ridefinendo la risposta alla collisione ; questo è uno strato prima di quello. La risposta alla collisione è determinata completamente dai punti di contatto calcolati dalla collisione.

Come ho detto, non ho familiarità con Bullet Physics, quindi non so se la sua architettura sia suscettibile a questo.


Grazie. Penso che anche la risposta alla collisione sia legata al test di collisione della forma. Deve usare queste informazioni per decidere in che modo separarle e fino a che punto separarle, giusto? Starei bene con l'attuale risposta alla collisione se rispondesse alla forma del mio terreno.
MichaelHouse

Sì; Intendevo dire che non si ridefinisce l'algoritmo di risposta alla collisione, ma piuttosto si ridefinisce la generazione di punti di contatto che sono gli input di tale algoritmo.
Kevin Reid,
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.