Higher order surface e dintorni

La scorsa settimana abbiamo introdotto l’argomento relativo alle nuove architetture presentate da ATi e compatibili con lo standard DirectX11; tra le feature presenti, una di quelle che spicca maggiormente, sia per l’impatto a livello di qualità d’immagine, sia per la sua inclusione nelle specifiche delle DX11, che dovrebbero preludere ad un suo reale e diffuso utilizzo, è il tessellator e, nello specifico, la sua implementazione secondo Microsoft.

Di fatto, in effetti, il tessellator nello specifico non rappresenta una novità, in quanto già presente, seppure in forma rudimentale, su R200, nota come ATi 8500 e, se consideriamo, in senso lato, la generazione di texture che diano l’illusione della tridimensionalità o di una maggior complessità delle superfici, dobbiamo risalire, per i prodotti di tipo consumer, al 1998 ed alle specifiche DX6, con l’introduzione delle tecniche di bump mapping.

Lo scopo di queste tecniche è quello di fornire un maggior realismo agli oggetti che popolano una scena 3D mediante varie tecniche che vanno da semplici operazioni di multitexturing allo “spostamento” di alcuni vertici o punti di un poligono (displacement) alla generazione di un elevato numero di poligono partendo da un quantitativo ridotto degli stessi. Ovviamente è anche possibile combinare queste tecniche al fine di avere superfici sempre più “verosimili”.

Come detto, alcune di queste si basano sull’utilizzo di comuni texture map che contengono informazioni sulle differenti gradazioni di grigio invece che sui colori, per simulare un gioco di luci e ombre che dà l’illusione di una superficie rugosa, con elementi in rilievo e, comunque, non completamente piatta.

Le tradizionali tecniche di bump mapping fanno uso di cosiddette heightmap che sono delle tabelle contenenti i valori “altimetrici” di una superficie. Grazie all’utilizzo di una eightmap è possibile conoscere l’altitudine di un determinato punto rispetto alla superficie di riferimento (data dalla quota 0 sulla mappa) e di conseguenza, di sapere come orientare la normale che tiene conto dei valori di illuminazione in quel determinato punto.

E’ proprio grazie all’utilizzo delle normali alla superficie in ogni punto che si riesce a riprodurre il gioco di luci e ombre che crea l’illusione della tridimensionalità. Quello che avviene è che i valori contenuti nella heightmap sono trasformati in una texture in cui ad ogni quota corrisponde un determinato valore in una scala di grigi che ha come estremi il bianco ed il nero.

bump-mapping-texture-map.jpg

A questo punto, per ogni pixel, si definisce una normale che indica l’inclinazione della superficie rispetto alla luce incidente. Questo significa che, ad esempio, al bianco corrisponde una normale con direzione  e verso rivolti verso l’osservatore (la riflessione avviene lungo la stessa direzione e lo stesso verso della luce incidente), mentre la nero corrispondono normali orientate in direzione perpendicolare alla retta ideale che congiunge il punto di osservazione e quello in cui si calcola il valore dell’illuminazione.

bump-mapping-mappa-normali.jpg

Una volta ottenute le nuove normali, si procede al calcolo dell’illuminazione con le comuni tecniche di phong shading. Il risultato finale è piuttosto buono, anche alla luce del fatto che si tratta di una tecniche che permette di simulare una complessità poligonale di fatto inesistente. L’immagine sottostante rende bene l’idea della differenza degli angoli di riflessione tra un’immagine senza ed una con bump mapping applicato

bump-mapping-riflessioni.jpg

Come si può vedere, man mano che ci si allontana dalla linea ideale che congiunge il punto di osservazione a quello in cui si calcola il valore di illuminazione, si passa a valori sempre più scuri. Il gioco di chiaro-scuri fa si che il cervello crei l’illusione di maggior realismo, attraverso la rugosità della superficie, come si vede in basso

bump-mapping-esempio.jpg

Tra le varie tipologie di bump mapping, una menzione a parte merita l’environment mapped bump mapping (EMBM), lanciato da Matrox con la G400, che utilizza ben tre texture, una come texture di base, una contenente le quote (bump map) e la terza, detta environment map è, di fatto, una light map. Tra le varie tipologie di EMBM, a sua volta, va segnalato il cosidetto real environment mapped bump mapping che fa uso di cube map o del più vecchio sphere map, ossia di una “texture tridimensionale” che permette di estendere l’applicazione dellìEMBM a tutto lo spazio circostante ad un determinato punto. In basso l’esempio di una cube map

cubemap.jpg

Un altro approccio che serve a rendere l’illusione di una aumentata complessità poligonale a fronte di un reale aumento della complessità delle geometrie pari a zero è il displacement mapping . Al pari del bump mapping, il displacement mapping non richiede l’uso di hardware dedicato ma, a differenza del bump mapping che dà solo l’illusione di superfici “bumped”, in questo caso si ha un reale spostamento di alcuni punto della superficie che vengono traslati rispetto alla loro posizione originale.

Se il bump mapping trae giovamento delle capacità di multitexturing delle tmu, il displacement mapping richiede la capacità delle unità geometriche di fare un’operazione di texture fetching, esattamente come accade con le unità di pixel shader. Le unità di vertex shader devono essere in grado di “prelevare” texture non filtrate da utilizzare come base per le operazioni di “spostamento” dei vertici. La feature, prevista dallo Shader Model 3.0 delle DX9 può avere differenti modi di implementazione. Nell’immagine in basso una unità di vertex shading dell’NV40, in cui si vede il circuito dedicato al vertex texturing che ha accesso diretto alla texture cache.

nv40-vertex-shader.jpg

Nei chip ATi della serie R5x0 non è presente un’unità fisica in grado di fare vertex texturing, motivo per cui si deve ricorrere a metodi alternativi come il render to vertex buffer, ossia le texture che devono essere usate come dispacement map vengono “scritte” direttamente all’interno del vertex buffer e sono, in tal modo, messe a disposizione delle unità di vertex shading. Con il passaggio ai chip a shader unificati non ha più senso parlare di vertex texturing in quanto lo shader core è composto da fpu che si occupano sia di effettuare operazioni di vertex shading che di pixel shading r, di conseguenza, hanno accesso diretto alle texture cache.

Come tutte le operazioni di texturing, anche quelle eseguite dai vertex shader presentano lunghe latenze per mascherare le quali, si deve ricorrere al thread switching.  

Anche per il displacement mapping gli ingredienti di base, dunque, sono: una heightmap  che contenga le informazioni sui vertici da spostare; una normal map per l’illuminazione; una mesh usata come “base”; una texture da applicare sulla mesh dopo aver eseguito il “displacement” dei vertici. Chi cambia è, quindi, solo lo “chef” (i vertex shader invece delle tmu) e il riusultato è notevole, come dimostra il confronto tra una texture bump mapped (in alto) ed una displaced (in basso)

texture-bumpmapped.jpg

texture-displaced.jpg

Gli approcci al displacement mapping sono due, uno tipico della rasterizzazione, l’altro del ray-tracing; il primo parte dalla mesh di base e risponde alla domanda: quali vertici devono essere spostati e di quanto. Il secondo, invece, cerca di individuare, pixel per pixel, la geometria visibile nel frame.

Se il bump mapping serve a dare l’illusione di una geometria più complessa di quella che è in realtà, simulando la presenza di rugosità o asperità inesistenti, col semplice gioco delle luci e delle ombre e il displacement mapping crea un effeto analogo con la differenza che, pur non aumentando la complessità geometrica, i vertici vengono effettivamente traslati, esiste un’altra feature che, in abbinamento con le due presentate in precedenza, aumenta realmente la complessità delle geometrie: la tessellation.

Un tessellator funziona in maniera concettualmente piuttosto semplice: è formato da una parte programmabile e da una di tipo fixed function ma può essere interamente emulato tramite unità programmabili. La parte prpogrammabile è composta, a sua volta, da due blocchi, il primo dei quali si occupa di ricevere istruzioni sul tipo di curva che deve essere riprodotta o, meglio, approssimata. Una volta ricevuto questo input, invia al vero e proprio tessellator (che opera con fixed function reali o emulate) le istruzioni su dove posizionare, sulla mesh in lavorazione, i nuovi vertici, per ridurre le dimensioni dei triangoli (e aumentarne il numero). Il tessellator esegue e passa il tutto al successivo stadio, anch’esso programmabile, che raccoglie sia i dati sul tipo di curva che gli arrivano direttamente dal primo stadio, sia la mesh elaborata dal tessellator. Quest’ultimo stadio si occupa di controllare che la mesh all’uscita del tessellator risponda alle specifiche della superficie in input e si occupa di applicare eventuali altri effetti che trasformino la mesh in una “superficie curva” (displacement mapping, EMBM, ecc).

Il primo esempio di tessellator su chip di tipo consumer è stato quello presente su R200, che faceva uso di n-patches e passò alla storia col nome commerciale di Truform. Nonostante le limitazioni e lo scarso supporto, riuscì a fornire, in alcuni titoli, tangibili miglioramenti a livello di grafica. In basso, uno schema che indica il funzionamento di massima del truform di R200

truform.jpg

Con la generazione di chip DX9, scomparve il tessellator in hardware, emulato dalle unità di vertex shading; l’unione delle operazioni di tessellation e displacement mapping è nota come adaptive displacement mapping. 

Con l’avvento dei chip a shader unificati torna anche l’unità fisica di tessellation, questa volta in forma completamente programmabile. La tessellation, però, non fa parte degli standard directX, pertanto è solo ATi ad implementarla nei suoi chip. Finalmente, con le DX11, la tessellation diventa standard anche se la sua implementazione differisce da quella proposta da ATi ocn la serie 4xx0 e, sembrerebbe, anche da quella proposta da nVidia con GT300. Analizzando brevemente le architetture dei tessellator di RV770 ed RV870 si nota subito, nel secondo, la presenza di due nuovi stadi, hull shader e domain shader, assenti nel chip DX10.1.

rv870-tessellator.jpg

RV870

rv770-tessellator.jpg

RV770

Hull shader e domain shader sono i due stadi programmabili che si occupano proprio il primo di inviare al tessellator (di tipo fixed function) le informazioni sul dove posizionare i nuovi vertici e il secondo di confrontare il risultato del lavoro del tessellator con il tipo di curva che si intende riprodurre e applicare ulteriori effetti grafici. Questi due compiti, nell’implemntazione presente su RV770, sono svolti da vertex shader e geometry shader rispettivamente. Le due soluzioni, pertanto, differiscono non nella qualità dell’uno rispetto all’altro ma nel semplice fatto che quello DX11 presenta due unità dedicate a specifici compiti che in quello presente su RV770 sono svolti dallo shader core.

Alcuni dei vantaggi dell’utilizzo della tessellation sono piuttosto evidenti: miglioramento della qualità delle immagini grazie alla presenza di un numero enormemente maggiore di poligoni e al miglioramento della scalabilità del LoD; miglior utilizzo della bandwidth, in quanto il traffico dei dati (vertici) dalla cpu alla gpu si riduce. Altri sono meno palesi come, ad esempio, la possibilità di cambiare la base, ovvero, il tipo di curva da rappresentare e, in tal modo, operare una traslazione dei punti di controllo degli oggetti o dei personaggi, che serve a permettere animazioni migliori a costi computazionali ridotti. Oppure la possibilità di generare vertici e, quindi, nuove figure che siano la ripetizione di una figura iniziale con lo stesso orientamento, oppure ruotata, traslata, speculare e così via.

Press ESC to close