Perché i tutorial utilizzano approcci diversi al rendering OpenGL?


43

http://www.sdltutorials.com/sdl-opengl-tutorial-basics

http://www.opengl-tutorial.org/beginners-tutorials/tutorial-2-the-first-triangle/

Questi due tutorial utilizzano approcci completamente diversi per ottenere quasi lo stesso risultato. Il primo usa cose come glBegin(GL_QUADS). Il secondo usa cose come vertexBufferObjectsshader basati su GLEW. Ma il risultato è lo stesso: ottieni forme di base.

Perché esistono queste differenze?

Il primo approccio sembra molto più facile da capire. Qual è il vantaggio del secondo approccio complicato?


4
Non c'è mai solo un modo per scuoiare un gatto.
Philipp

4
@Philipp Sì, ma ci sono modi giusti e modi sbagliati, vecchi modi e nuovi modi (e come dimostrano le risposte di seguito, i vecchi e i nuovi modi potrebbero non essere compatibili in tutte le situazioni)
Andrew Hill

3
Non ci sono nessun modi giusti e modi sbagliati, modi solo peggio e migliori modi (in diverse dimensioni differenti).
user253751

glBegine glEndsono stati deprecati perché sono estremamente inefficienti per le attuali architetture grafiche
Alex

Risposte:


77

OpenGL ha quattro diverse versioni principali, senza contare le versioni per dispositivi mobili e sistemi integrati (OpenGL | ES) e il Web tramite JavaScript (WebGL). Proprio come Direct3D 11 ha un modo diverso di fare le cose rispetto a Direct3D 8, così OpenGL 3 ha un modo diverso di fare le cose rispetto a OpenGL 1. La grande differenza è che le versioni OpenGL sono principalmente solo componenti aggiuntivi rispetto alle versioni precedenti (ma non interamente).

Oltre alle diverse edizioni e versioni di OpenGL, anche OpenGL principale ha aggiunto il concetto di profili. Vale a dire il profilo di compatibilità (che abilita il supporto per le API dalle versioni precedenti) e il profilo principale (che disabilita quelle vecchie API). Cose come glBeginsemplicemente non funzionano quando si utilizza il profilo principale, ma lo faranno quando si utilizza il profilo di compatibilità (che è l'impostazione predefinita).

Come ulteriore importante complicazione, alcune implementazioni di OpenGL (come quelle di Apple, tra le altre) abiliteranno le nuove funzionalità di OpenGL solo quando si utilizza il profilo principale. Ciò significa che è necessario smettere di utilizzare API più vecchie per utilizzare API più recenti.

Quindi si finiscono con diversi scenari molto confusi per le esercitazioni:

  1. Il tutorial è vecchio e utilizza solo API obsolete.
  2. Il tutorial è nuovo e ben scritto e utilizza solo API compatibili con Core.
  3. Il tutorial è nuovo ma fa l'errore di presumere che stai lavorando con un driver che abilita tutte le API in modalità Compatibilità e mescola liberamente sia le API nuove che quelle vecchie.
  4. Il tutorial è per una diversa edizione di OpenGL come OpenGL | ES che non supporta affatto le vecchie API, in qualsiasi versione.

Cose come glBeginfanno parte di quella che a volte viene chiamata API in modalità immediata. Questo è anche molto confuso perché non esiste una modalità mantenuta in OpenGL e "modalità immediata" aveva già una diversa definizione nella grafica. È molto meglio fare riferimento a quelle come API OpenGL 1.x poiché sono obsolete da OpenGL 2.1.

L'API 1.x di OpenGL invierebbe immediatamente i vertici alla pipeline grafica ai vecchi tempi. Funzionava bene quando la velocità dell'hardware che rendeva i vertici era approssimativamente alla pari della velocità della CPU che generava i dati del vertice. OpenGL ha quindi scaricato la rasterizzazione del triangolo e non molto altro.

In questi giorni, la GPU può masticare un numero enorme di vertici a velocità molto elevate mentre esegue la trasformazione avanzata di vertici e pixel e la CPU semplicemente non può nemmeno tenere il passo da remoto. Inoltre, l'interfaccia tra la CPU e la GPU è stata progettata attorno a questa differenza di velocità, il che significa che non è nemmeno più possibile inviare vertici alla GPU uno alla volta.

Tutti i driver GL devono emulare glBeginallocando internamente un buffer di vertici, inserendo i vertici inviati glVertexin questo buffer e quindi inviando l'intero buffer in una singola chiamata di disegno quando glEndviene chiamato. Il sovraccarico di queste funzioni è di gran lunga maggiore che se si aggiorna da solo il buffer dei vertici, motivo per cui alcuni documenti (erroneamente!) Faranno riferimento ai buffer dei vertici come "un'ottimizzazione" (non è un'ottimizzazione; è l'unico modo per parlare con la GPU).

Esistono varie altre API che sono state deprecate o obsolete in OpenGL nel corso degli anni. La cosiddetta pipeline a funzione fissa è un altro pezzo del genere. Alcuni documenti potrebbero comunque utilizzare questa pipeline o mescolarsi con la pipeline programmabile. La pipeline a funzione fissa viene dai tempi antichi in cui le schede grafiche codificavano per intero tutta la matematica utilizzata per il rendering delle scene 3D e l'API OpenGL si limitava a impostare alcuni valori di configurazione per quella matematica. In questi giorni l'hardware ha pochissima matematica hardcoded e (proprio come la tua CPU) esegue invece programmi forniti dall'utente (spesso chiamati shader).

Ancora una volta i driver devono emulare la vecchia API poiché le funzionalità a funzione fissa semplicemente non sono più presenti sull'hardware. Ciò significa che il driver ha un gruppo di shader di compatibilità integrati che eseguono la vecchia matematica dai giorni a funzione fissa che viene utilizzata quando non si forniscono i propri shader. Le vecchie funzioni OpenGL che modificano il vecchio stato di funzioni fisse (come la vecchia API di illuminazione OpenGL) in realtà utilizzano le moderne funzionalità OpenGL come buffer uniformi per alimentare questi valori agli shader di compatibilità del driver.

I driver che supportano la compatibilità devono fare un sacco di lavoro dietro le quinte solo per capire quando stai usando queste funzionalità obsolete e assicurarti di poterle combinare con funzionalità moderne senza intoppi, il che aggiunge sovraccarico e complica notevolmente il driver. Questo è uno dei motivi per cui alcuni driver ti costringono ad abilitare il profilo principale per accedere alle funzionalità più recenti; semplifica notevolmente i loro driver interni, non dovendo supportare entrambe le API vecchie e nuove utilizzate contemporaneamente.

Molta documentazione può consigliare di iniziare con le vecchie API semplicemente perché è più facile iniziare. Direct3D ha risolto questo problema per i principianti offrendo una libreria di accompagnamento ( DirectX Tool Kit ) che fornisce API di disegno più semplici e shader pre-scritti che possono essere liberamente miscelati con l'utilizzo diretto di Direct3D 11 man mano che la tua esperienza cresce. La più ampia comunità OpenGL è rimasta per lo più attaccata al profilo di compatibilità per i principianti, sfortunatamente, il che è problematico in quanto vi sono ancora sistemi che non consentono di mescolare vecchie API OpenGL con quelle più recenti. Esistono librerie e strumenti non ufficiali per il rendering più semplice sul nuovo OpenGL con diversi livelli di funzionalità e casi d'uso e linguaggi di destinazione ( MonoGame per gli utenti .NET, ad esempio), ma nulla è stato approvato o concordato ufficialmente.

La documentazione che stai trovando potrebbe non essere nemmeno per OpenGL ma potrebbe essere per una delle altre API simili. OpenGL | ES 1.x aveva un rendering a funzione fissa ma non aveva le API OpenGL 1.x per l'invio dei vertici. OpenGL | ES 2.x + e WebGL 1+ non hanno alcuna funzione fissa e non esistono modalità di compatibilità con le versioni precedenti per tali API.

Queste API sembrano molto simili al principale OpenGL; non sono del tutto compatibili, ma ci sono estensioni ufficiali di OpenGL che alcuni driver (non tutti) supportano per diventare compatibili con OpenGL | ES (su cui si basa WebGL). Perché le cose non erano abbastanza confuse prima.


4
+1 Risposta fantastica! Se potessi menzionare un paio di quelle librerie e strumenti non ufficiali per un semplice rendering sul nuovo OpenGL sarebbe fantastico :)
Mehrdad,

2
Risposta brillante. Ho avuto gli stessi problemi con DirectX nel corso della giornata - molto più semplice rispetto a OpenGL, ma il passaggio dalla modalità conservata / immediata agli shader è stato enorme. Fortunatamente, la documentazione ha aiutato molto (a differenza di OpenGL, almeno per me), ma l'inizio di "come faccio ad accendere anche" è stato folle: D
Luaan,

Sono l'autore di opengl-tutorial.org e sono d'accordo con Sean. L'API si è evoluta in questo modo principalmente per motivi di prestazioni.
Calvin1602,

Ottime informazioni sull'argomento ..
Reynmar,

1
@Mehrdad: non ricordo nulla sulla cima della mia testa; ci sono librerie come SDL2 o SFML che aggiungono rendering 2D semplificato, varie librerie di grafici di scene, MonoGame per C #, ecc., ma in realtà non sono a conoscenza di qualcosa di direttamente equivalente a Direct TK ora che ci penso. Modificherà il post dal momento che dire "molti" può essere una grossa bugia grassa. :)
Sean Middleditch il

9

La differenza principale è quanto siano aggiornate le strategie. La modalità immediata utilizzata nel primo tutorial:

glBegin(GL_QUADS);
    glColor3f(1, 0, 0); glVertex3f(0, 0, 0);
    glColor3f(1, 1, 0); glVertex3f(100, 0, 0);
    glColor3f(1, 0, 1); glVertex3f(100, 100, 0);
    glColor3f(1, 1, 1); glVertex3f(0, 100, 0);
glEnd();

È obsoleto e non supportato nelle versioni più recenti.

L'uso di buffer e shader di vertici è l'attuale metodo di rendering con OpenGL. Può sembrare più complicato, ma si comporta notevolmente meglio. Inoltre, una volta che hai il tuo codice di supporto che racchiude il materiale OpenGL, le differenze vengono astratte per la maggior parte.


2

Solo per aggiungere un po 'più di contesto alle altre risposte eccellenti.

La modalità immediata come descritto nel primo collegamento è, come altri hanno già detto, il codice legacy dalle prime versioni di OpenGL (1.1). È stato utilizzato quando le GPU erano poco più che rasterizzatori a triangolo e l'idea di pipeline programmabili non esisteva. Se guardi il codice sorgente di alcuni dei primi giochi con accelerazione hardware come GLQuake e Quake 2, ad esempio, vedrai la modalità immediata in uso. In termini semplici, la CPU invia istruzioni per vertici una alla volta alla GPU per iniziare a disegnare triangoli sullo schermo. Per la cronaca, GL_QUADS ha lo stesso risultato di GL_TRIANGLES, tranne per il fatto che la GPU deve trasformare quei quadratini in triangoli stessi al volo.

Modern (3.2+) OpenGL adotta un approccio diverso. Memorizza i dati dei vertici nella memoria della GPU per un rapido accesso, quindi puoi inviare istruzioni di disegno usando glDrawArrays o glDrawElements. Hai anche la pipeline programmabile (glUseProgram) che ti consente di personalizzare il modo in cui la GPU posiziona e colora i vertici.

Ci sono alcuni motivi per cui la modalità immediata è stata deprecata, il motivo principale è rappresentato dalle prestazioni. Come ha detto Sean nella sua risposta, al giorno d'oggi le GPU possono sgranocchiare i dati più velocemente di quanto la CPU possa caricarli, quindi si verificherebbe il collo di bottiglia delle prestazioni della GPU. C'è un piccolo overhead coinvolto per ogni chiamata a OpenGL che fai, è minuscola ma quando fai decine di migliaia di chiamate ogni frame inizia a impilarsi. In poche parole, per disegnare un modello strutturato usando la modalità immediata, sono necessari almeno 2 chiamate per vertice (glTexCoord2f e glVertex3f) per frame. Con il moderno OpenGL usi un paio di chiamate all'inizio per bufferizzare i dati, quindi puoi disegnare l'intero modello, indipendentemente da quanti vertici contiene, usando solo poche chiamate per associare l'oggetto array di vertici, abilitare alcuni puntatori di attributi e quindi una singola chiamata a glDrawElements o glDrawArrays.

Quale tecnica è giusta? Bene, dipende da cosa stai cercando di fare. Un semplice gioco 2D che non richiede alcuna tecnica di post-elaborazione o shader funzionerà bene usando la modalità immediata e probabilmente sarà più facile scrivere il codice. Tuttavia, un gioco 3D più moderno farebbe davvero fatica, e se stai pensando di imparare il GLSL (linguaggio shader), allora impara sicuramente la tecnica moderna.

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.