La fine delle pipeline di rendering a funzione fissa (e come spostarsi)

Le pipeline a funzione fissa non hanno più business sulle nostre schede video. Ecco cosa devi sapere su di loro e su come spostarti da loro, se ancora non l'hai ancora fatto.

In The Beginning: The Rise of Graphics Hardware

C'era una volta, quando lo sviluppo del gioco (o la codifica di tutto ciò che ha a che fare con la grafica in tempo reale, in realtà) era limitato a scrivere su una matrice relativamente piccola di intensità di colore (la frame buffer) e inviandolo all'hardware, potevi fare tutto ciò che volevi con esso. Puoi disegnare sull'immagine uno, dieci o cento volte. Potresti passare di nuovo il buffer del frame per fare un pò di FX. In breve, qualsiasi cosa fosse in grado di fare il tuo processore, puoi farlo con l'immagine che viene inviata al monitor. Questo ti ha permesso di fare cose davvero fantastiche e creative, ma la gente non l'ha mai usata (o raramente) fino a quel punto. Ma perché?

La risposta: perché era lento. Un'immagine 640 × 480 px (una risoluzione comune in quel momento) contiene 307.200 pixel. E le CPU erano molto più lente allora, che non potevi davvero fare molto nel poco tempo che ti è stato dato per disegnare quella cornice. Dopo tutto, se vuoi continuare a disegnare a 30 FPS, hai solo circa 30ms per aggiornare la logica di gioco e renderizzare sullo schermo, e questo deve includere il sovraccarico dell'intercomunicazione con l'hardware. Non era molto.

Poi sono arrivate le fantastiche GPU con rendering di condotte. Tu, lo sviluppatore, ti occuperesti dell'aggiornamento della logica di gioco e dell'invio delle trame e dei triangoli alla GPU, e farebbero il pesante sollevamento e il calcolo del numero su di essi. Quelli erano pipeline di rendering a funzione fissa (FFP): significa che non è possibile configurare il funzioni loro si esibirono. Potresti dire loro "fai la nebbia grigio scuro" o "non fare l'illuminazione per me!" e potresti configurare molto l'altro parametri, ma il funzioni stessi rimasti. 

L'hardware era cablato e strettamente specializzato in modo da eseguire alcune operazioni standard sui dati. E poiché era cablato in quel modo, era molto più veloce rispetto a farlo sul tuo processore. Ma uno svantaggio era che pagavi molto per quella velocità: pagavi in ​​flessibilità. Ma se hai mai voluto disegnare qualcosa di complesso, la CPU semplicemente non era abbastanza veloce, e l'invio dei tuoi vertici alla GPU era l'unica scelta.

Questo è all'incirca il modo in cui la pipeline a funzione fissa ha funzionato. L'immagine non è intesa come una rappresentazione accurata, ma per darti un'idea di come è stata eseguita.

Le richieste per un migliore realismo

Il mondo della grafica stava ancora cambiando rapidamente. Proprio come tutte le persone creative e di talento, gli sviluppatori di giochi amano le sfide e uno di il le sfide per loro erano (e rimarranno!), per molto tempo, per rendere immagini realistiche sempre più belle. 

La pipeline a funzioni fisse ha fornito alcune funzioni interessanti, come modalità di fusione multiple, ombreggiatura Gouraud per per vertice, effetti nebbia, buffer di stencil (per volumi di ombre) e così via, così gli sviluppatori hanno usato quello che potevano. Presto, ci furono alcuni effetti davvero impressionanti in corso, il tutto in virtù di fenomeni reali simulati usando alcuni trucchi a buon mercato (beh, a buon mercato secondo gli standard odierni). 

Tutto andava molto bene, ma era ancora limitato dalla quantità di funzioni che la pipeline fissa poteva fare. Dopotutto, il mondo reale ha così tanti materiali diversi, e per simularli, l'unica variazione che è stata loro consentita di eseguire è stata la modifica di alcune modalità di fusione, l'aggiunta di altre trame o il ritocco dei colori di riflessione della luce.

Poi è successo: sono arrivate le prime GPU programmabili. Loro non sono venuti durante la notte, naturalmente, e dovevano arrivare un giorno, ma questo creava ancora eccitazione. Queste GPU avevano quello che veniva chiamato a pipeline di rendering programmabile: ora puoi scrivere programmi, chiamati shaders, in un linguaggio di assemblaggio limitato e farli eseguire per ogni vertice o frammento, sulla scheda video. Questo è stato un grande balzo in avanti, e stava migliorando. 

Ben presto i linguaggi di assemblaggio sono aumentati di complessità ed espressività e sono emersi linguaggi di alto livello per la programmazione GPU, come HLSL, GLSL e successivamente Cg. Oggi disponiamo di shader geometrici che possono persino riprodurre nuovi vertici, o shader che controllano dinamicamente tessellation e triangoli a mosaico, e al loro interno possiamo campionare un sacco di trame, diramarsi dinamicamente e fare ogni sorta di matematica pazza sui valori di input.

Quando dai agli sviluppatori questi vantaggi, si scatenano; presto stavamo scrivendo shader per tutti i tipi di cose: mappatura della parallasse, modelli di illuminazione personalizzata, rifrazione, il tuo nome. Successivamente, sono emersi anche sistemi di illuminazione completamente personalizzati, come l'ombreggiatura differita e il pre-pass di luce, e si potevano vedere complessi effetti di post-elaborazione come l'occlusione ambientale dello spazio dello schermo e l'occlusione ambientale basata sull'orizzonte. Alcuni hanno persino "abusato" gli shader per svolgere compiti ripetitivi e matematici, come l'elaborazione statistica o la rottura degli hash delle stringhe. (Questo era prima che l'elaborazione generica su GPU ottenesse il supporto principale). 

In breve, la grafica al computer è esplosa con l'introduzione degli shader, e con una buona ragione: la capacità di programmare cosa è successo esattamente a vertici, frammenti, trame e così via, e per farlo veloce, fornito possibilità quasi infinite.

Una rappresentazione semplificata della pipeline programmabile. Nota come le fasi specifiche di trasformazione, ombreggiatura o trama sono state sostituite da shader specializzati. (Tessellazioni omesse per chiarezza.)

L'interruttore completo

Ben presto, le pipeline delle funzioni fisse erano obsolete, almeno per gli sviluppatori di giochi. Dopo tutto, perché preoccuparsi di giardini così murati quando puoi programmare con precisione cosa succede ai tuoi dati? Sono rimasti in uso per molto più tempo in alcune applicazioni in cui il realismo non era un problema, come per il CAD. Ma in generale, venivano ignorati. 

OpenGL ES 2.0, rilasciato nel 2007, deprecato o rimosso la sua pipeline a funzione fissa in favore di una programmabile. OpenGL 3.2, nel 2009, ha finalmente rimosso tutte le nozioni di elaborazione dei vertici e dei frammenti a funzione fissa (tuttavia, rimane disponibile per l'uso legacy tramite profilo di compatibilità). È chiaro che oggi non ha molto senso lavorare con la pipeline limitata quando hai potenti GPU in grado di fare cose fantastiche a tua disposizione.

Poiché queste API ti obbligano a usare shader (e questo include DirectX, che, pur non rimuovendo esplicitamente la funzionalità, include strumenti per aiutare a migrare dal vecchio approccio e non ha praticamente nessuna nuova documentazione riguardante il FFP), sono difficili da ottenere correttamente per un principiante. Se stai iniziando solo come rookie di programmazione in 3D, è molto più semplice solo dire all'API le tue matrici, i parametri di illuminazione e quant'altro, e farlo fare tutto per te. 

Ma a lungo andare, ti gioverà molto di più se impari a scrivere programmi che descrivano esattamente il processo. Comprenderai complicatamente cosa sta succedendo sotto la cappa, comprenderai alcuni concetti molto importanti a cui FFP non richiede di essere, e sarai in grado di modificare i tuoi materiali molto facilmente per fare qualcosa di complesso che la funzione fissa non può mai fare per te (ed è utile anche per il debug!).

Ho menzionato OpenGL ES, e vorrei approfondirmi in dettaglio. Dato che i giochi su cellulare diventano sempre più popolari, è logico creare mondi virtuali sempre più complessi. La maggior parte delle chiamate a funzioni fisse sono state rimosse in ES 2.0 (che, naturalmente, significa che sono assenti anche dalle versioni successive). Questo significa essenzialmente che, per utilizzare una qualsiasi delle funzionalità dopo ES 1.1, è necessario utilizzare shader. 

ES 2.0 è supportato da iPhone dal 3GS, iPad dalla prima versione e dispositivi iPod Touch di generazione 3 e successiva. Qualcomm Snapdragon, un chip ampiamente utilizzato nella produzione di telefoni Android, supporta anche OpenGL ES 2.0. Questo è molto ampio supporto, perché ES 2.0 non è esattamente "nuovo": ora ha più di 7 anni. Per ottenere il massimo da queste architetture, hai bisogno di lasciare andare la pipeline a funzione fissa

Presumo che la maggior parte di voi lo abbia fatto molto, molto tempo fa, ma non è difficile per me immaginare alcuni motori grafici 2D o giochi legacy che usano ancora funzioni fisse (perché non c'è bisogno di altro). Tutto ciò va bene, ma usarlo per nuovi progetti o addestrare programmatori al loro interno sembra una perdita di tempo. Ciò è amplificato dal fatto che un sacco di tutorial che puoi trovare su Internet sono grossolanamente obsoleti e ti insegneranno come usare FFP fin dall'inizio - e prima ancora di renderti conto di cosa sta succedendo, sarai lì dentro.

Il mio primo pennello con grafica 3D era un antico tutorial di DirectX 7 scritto in Visual Basic. A quel tempo, l'uso della pipeline a funzione fissa aveva generalmente senso, perché l'hardware non era abbastanza avanzato da ottenere la stessa funzionalità con gli shader alla stessa velocità. Ma oggi vediamo che le API grafiche iniziano a cadere o deprecano gravemente il supporto per esso, e in realtà diventa solo un artefatto del passato. È un artefatto utile e utile che ci rende nostalgici, ma dovremmo starne alla larga. È vecchio e non è più usato.

Questi dolci riflessi e rifrazioni di fresnel, generati da una demo di OGRE (Open-source Graphics Rendering Engine), non sarebbero mai stati fatti se si fosse attenuti ai modi in cui i vecchi tutorial di DirectX 8 o OpenGL 1.1 consigliano.

Conclusione

Se sei impegnato nello sviluppo di un gioco serio, restare fedele alla pipeline a funzione fissa è una reliquia dei giorni passati. Se stai pensando di entrare nella grafica 3D, il mio consiglio (e il consiglio di molti, molti sviluppatori là fuori) è semplicemente di evitarlo. 

Se vedi passare posizioni di illuminazione all'API di grafica (non come parametro shader), o chiamate di funzioni API come glFogv, corri come il vento e non guardare indietro. C'è un nuovo mondo di GPU programmabili là fuori, ed è in circolazione da molto tempo. Qualsiasi altra cosa probabilmente ti fa perdere tempo.

Anche se ti occupi solo di grafica 2D, è comunque una saggia idea non affidarsi più al FFP. (Ovviamente, questo è il tempo che va bene se non si supporta l'hardware antico.) Gli shaders possono fornire alcuni effetti straordinari e lampo. Sfocatura delle immagini, nitidezza, griglie di curvatura, rendering vettoriale e simulazione di particelle o fisica su larga scala possono essere eseguite sulla GPU e possono trarre vantaggio da entrambi i giochi 2D e 3D. 

Quindi, ancora una volta, il mio consiglio, anche se non si impara esplicitamente sullo sviluppo di giochi 3D, è imparare a scrivere shaders. Sono divertenti con cui lavorare, e ti garantisco che trascorrerai molte ore divertenti a perfezionare un effetto shader fresco: uno skybox dinamico, una vernice per auto o una mappatura delle ombre con divisione parallela o qualunque cosa il tuo cuore desideri. Almeno questo è successo a me: una volta che sei abituato a lavorare con la pipeline fissa a causa di alcune limitazioni (come sono stato costretto a, nel corso della giornata, per ottenere prestazioni accettabili sul mio 5200FX), programmare la GPU è un esplosione, e un sacco di divertimento.

Spero di aver spiegato a coloro per i quali non è chiaro, come la grafica 3D ha funzionato molto tempo fa e come funziona ora, e spero di aver convinto i pochi di voi che erano sul punto di seguire i tutorial di NeHe o Swiftless per fare altrimenti e vai a guardare qualcosa di più moderno. Come sempre, potrei aver fatto degli errori, quindi sentitevi liberi di indicarli nei commenti. Fino alla prossima volta!