Il modo più efficiente per disegnare un gran numero degli stessi oggetti, ma con trasformazioni diverse


8

Vorrei disegnare un gran numero (più migliaia) di maglie semplici (ognuna forse ... un massimo di 50 triangoli, ma anche quello è un limite superiore molto grande), tutti esattamente uguali.

Come un semplice modo di forza bruta, in questo momento sto solo facendo migliaia di richiami di disegno, dove cambio solo le matrici di trasformazione di cui hanno bisogno gli shader e quindi disegno nuovamente gli stessi oggetti.

Naturalmente questo è terribilmente lento, poiché (immagino) ci sono troppe chiamate di richiamo per il driver e il mio PC per gestire in modo efficiente.

Cosa posso fare per renderlo più veloce?


4
Non posso darti una risposta completa, ma la risposta di alto livello è usare l' istanziazione geometrica .
Seth Battin,

Cerca "Geometry Instancing" su Google, forse puoi trovare qualcosa che ti aiuti in questo modo
Luis W

Risposte:


11

La soluzione a questo è istanziata. Questo tutorial spiega alcuni metodi di installazione. Se hai ARB_draw_instancede ARB_instanced_arrays, usali.

L'idea generale è di archiviare tutte le trasformazioni delle mesh in un oggetto buffer separato e collegarlo a una matrice di attributi che utilizza un "vertice" per istanza tramite glVertexAttribDivisor.

Se, dopo quello, non stai ancora correndo veloce come vuoi, probabilmente sei legato al processore vertice. Esegui l'abbattimento del frustum sulle maglie e, preferibilmente, costruisci un BVH da attraversare invece di eseguire il cull su tutte le maglie in modo indipendente.


1
+1; con molte migliaia di oggetti potresti anche essere legato alla CPU sulle trasformazioni (solo l'invio di posizione e rotazione nel buffer per istanza e il calcolo della matrice per oggetto sulla GPU possono aiutare qui) e non dimenticare di vedere come aggiorni quel buffer dinamico di vertici!
Maximus Minimus,

@Robert Rouhani: Grazie, ho studiato e implementato prontamente. Ora posso disegnare 5000 mesh con 20 tris ciascuna a 250 FPS. A proposito, il tuo modo suggerito sembra un po 'obsoleto. Dal momento che l'istanza della geometria 3.GL di OpenGL è parte ufficiale delle specifiche del core OpenGL, non è più necessario ARB_xxx. Uso un buffer uniforme per memorizzare le matrici e utilizzo glDrawElementsInstanced. All'interno del vertex shader, c'è un layout (std140) matrici uniformi {mat4 array [5000]; } dove posso accedere all'elemento rilevante tramite array [gl_InstanceID]
TravisG

1
@TravisG Tendo a provare a supportare versioni precedenti. Comprendo che entrambe le estensioni sono state promosse al core per un po ', tuttavia la stringa di estensione sarà comunque presente :). Inoltre, l'utilizzo glVertexAttribDivisor(che non è deprecato o obsoleto in alcun modo) ha il vantaggio di non avere un limite massimo sul conteggio delle istanze. Le prestazioni sono state storicamente migliori dei buffer uniformi, ma probabilmente sono uguali o molto simili adesso, ed entrambi i modi portano a termine il lavoro.
Robert Rouhani,

@Robert Rouhani: Mhm ... credo sia vero. Qualcuno con driver obsoleti potrebbe supportare ARB_xxx ma non le funzionalità ufficiali OpenGl 3.x di base. Dò un'occhiata a glVertexAttribDivisor, grazie.
TravisG

@Robert Rouhani: ho implementato entrambe le versioni (utilizzando buffer uniformi e in alternativa la versione suggerita in cui utilizzo un attributo vertice che cambia solo una volta per istanza) e la versione del buffer uniforme è in realtà circa due volte più veloce (4000 fps in modalità di rilascio, vs ~ 2000 con glVertexAttribDivisor, il numero di 250 fps era solo per lato CPU).
TravisG
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.